Skip to content

Conversation

@grod220
Copy link
Member

@grod220 grod220 commented Dec 19, 2025

Adds a new zero‑copy state API backed by wincode.

Key Changes

  • Adds p-stake-interface crate (#![no_std] compatible)
  • Introduces alignment-1 POD types (PodU32, PodU64, PodI64, PodAddress) for safe zero-copy from
    unaligned slices
  • New API via StakeStateV2:
    • StakeStateV2::from_bytes(&[u8]) -> Result<&StakeStateV2, StakeStateError> for read-only access
    • StakeStateV2::from_bytes_mut(&mut [u8]) -> Result<&mut StakeStateV2, StakeStateError> for
      mutations
    • Tag-checked accessors: meta(), stake(), meta_mut(), stake_mut()
    • State transitions: initialize(), delegate()
  • Maintains full ABI compatibility with legacy bincode-encoded stake accounts

Motivation

Deserialization via bincode/borsh is computationally expensive for programs that only need to access specific fields or verify the state. This zero-copy approach allows for significantly lower compute unit (CU) usage when interacting with stake accounts.

@grod220 grod220 changed the title Wincode spike StakeStakeV2 zero copy api [wincode] Jan 12, 2026
@grod220 grod220 marked this pull request as ready for review January 12, 2026 18:27
@grod220 grod220 requested review from febo and joncinque January 12, 2026 18:27
}
}

pub fn from_bytes(bytes: &[u8]) -> Result<Self, StakeStateError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be zero-copy if you do a transmute instead of StakeStateV2Tag::deserialize, but not sure if there is any benefit in doing that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we lose some safety though? What do you think about this instead?

    pub fn from_bytes(bytes: &[u8]) -> Result<Self, StakeStateError> {
        if bytes.len() < 4 {
            return Err(StakeStateError::UnexpectedEof);
        }
        let raw = u32::from_le_bytes(bytes[..4].try_into().unwrap());
        Self::from_u32(raw)
    }

#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, SchemaWrite, SchemaRead)]
#[wincode(assert_zero_copy)]
pub struct PodAddress(pub [u8; 32]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add wincode support to Address, then this type is not needed.

};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StakeStateV2View<'a> {
Copy link
Contributor

@febo febo Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a breaking change, could we stop using the enum? Seems like all we need is already in StakeStateV2Layout, so that one could become the state "account". One benefit is that we won't need to have the *View and *Write type. The fields not applicable for a variant can be optional.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Discussed offline)

Going to revise the API, but ensure a private-field pattern to ensure only methods can make state transitions to prevent invalidate state.

@grod220 grod220 requested a review from febo January 16, 2026 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants