Explorar el Código

Replace solana_program::stake with solana_stake_interface (#4664)

* start replacing program::stake

* replace solana_sysvar::stake_history (doesn't work because of dependency issue)

* patch solana-sysvar-id (unsuccessful)

* Fixup lockfile to use patch correctly

* use stake interface git dep for now

* remove now-unused import

* update lock file

* remove now-unused import

* add solana-clock patch

* missing feature activation

* fix lock file for patches

* another lock file fix

* add patches to svm/examples

* fmt

* missing feature activation

* update lock file

* missing feature activation

* add patch for frozen-abi

* update digest

* use published crate now that 1.2 is out

* add crates to patch-crates.sh

* undo adding clock crate (was already there)

* add crates_map entry for solana-sysvar

* missing solana-stake-interface/borsh in sdk/program

* update lock files

* trigger ci

* temp change to git dep with correct program ID

* switch back to crates.io stake interface

* use small crates in cargo-build-sbf tests to get around patching issue

* try removing dev dep

* activate solana-stake-interface/serde when serde is activated in solana-sysvar

* trigger ci

* trigger ci

* trigger ci

---------

Co-authored-by: Jon C <me@jonc.dev>
Kevin Heavey hace 9 meses
padre
commit
989eb2ffa7

+ 25 - 0
Cargo.lock

@@ -8676,6 +8676,7 @@ dependencies = [
  "solana-slot-hashes",
  "solana-slot-history",
  "solana-stable-layout",
+ "solana-stake-interface",
  "solana-system-interface",
  "solana-sysvar",
  "solana-sysvar-id",
@@ -9698,6 +9699,29 @@ dependencies = [
  "solana-version",
 ]
 
+[[package]]
+name = "solana-stake-interface"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c"
+dependencies = [
+ "borsh 0.10.3",
+ "borsh 1.5.5",
+ "num-traits",
+ "serde",
+ "serde_derive",
+ "solana-clock",
+ "solana-cpi",
+ "solana-decode-error",
+ "solana-frozen-abi",
+ "solana-frozen-abi-macro",
+ "solana-instruction",
+ "solana-program-error",
+ "solana-pubkey",
+ "solana-system-interface",
+ "solana-sysvar-id",
+]
+
 [[package]]
 name = "solana-stake-program"
 version = "2.2.0"
@@ -10071,6 +10095,7 @@ dependencies = [
  "solana-sha256-hasher",
  "solana-slot-hashes",
  "solana-slot-history",
+ "solana-stake-interface",
  "solana-sysvar",
  "solana-sysvar-id",
  "test-case",

+ 5 - 0
Cargo.toml

@@ -613,6 +613,7 @@ solana-send-transaction-service = { path = "send-transaction-service", version =
 solana-short-vec = { path = "sdk/short-vec", version = "=2.2.0" }
 solana-shred-version = { path = "sdk/shred-version", version = "=2.2.0" }
 solana-stable-layout = { path = "sdk/stable-layout", version = "=2.2.0" }
+solana-stake-interface = { version = "1.2.1" }
 solana-stake-program = { path = "programs/stake", version = "=2.2.0", default-features = false }
 solana-storage-bigtable = { path = "storage-bigtable", version = "=2.2.0" }
 solana-storage-proto = { path = "storage-proto", version = "=2.2.0" }
@@ -735,11 +736,14 @@ crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d
 #
 # There is a similar override in `programs/sbf/Cargo.toml`.  Please keep both
 # comments and the overrides in sync.
+solana-clock = { path = "sdk/clock" }
 solana-curve25519 = { path = "curves/curve25519" }
 solana-account-info = { path = "sdk/account-info" }
 solana-borsh = { path = "sdk/borsh" }
 solana-cpi = { path = "sdk/cpi" }
 solana-decode-error = { path = "sdk/decode-error" }
+solana-frozen-abi = { path = "sdk/frozen-abi" }
+solana-frozen-abi-macro = { path = "sdk/frozen-abi/macro" }
 solana-hash = { path = "sdk/hash" }
 solana-instruction = { path = "sdk/instruction" }
 solana-msg = { path = "sdk/msg" }
@@ -750,6 +754,7 @@ solana-program-option = { path = "sdk/program-option" }
 solana-program-pack = { path = "sdk/program-pack" }
 solana-pubkey = { path = "sdk/pubkey" }
 solana-sha256-hasher = { path = "sdk/sha256-hasher" }
+solana-sysvar-id = { path = "sdk/sysvar-id" }
 solana-zk-sdk = { path = "zk-sdk" }
 
 # curve25519-dalek uses the simd backend by default in v4 if possible,

+ 4 - 6
platform-tools-sdk/cargo-build-sbf/tests/crates/fail/Cargo.toml

@@ -10,14 +10,12 @@ edition = "2021"
 publish = false
 
 [dependencies]
-solana-program = { path = "../../../../../sdk/program", version = "=2.2.0" }
+solana-account-info= { path = "../../../../../sdk/account-info", version = "=2.2.0" }
+solana-program-entrypoint = { path = "../../../../../sdk/program-entrypoint", version = "=2.2.0" }
+solana-program-error= { path = "../../../../../sdk/program-error", version = "=2.2.0" }
+solana-pubkey = { path = "../../../../../sdk/pubkey", version = "=2.2.0" }
 
 [lib]
 crate-type = ["cdylib"]
 
-[patch.crates-io]
-solana-decode-error = { path = "../../../../../sdk/decode-error" }
-solana-instruction = { path = "../../../../../sdk/instruction" }
-solana-pubkey = { path = "../../../../../sdk/pubkey" }
-
 [workspace]

+ 4 - 2
platform-tools-sdk/cargo-build-sbf/tests/crates/fail/src/lib.rs

@@ -1,8 +1,10 @@
 //! Example Rust-based SBF noop program
 
-use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
+use {
+    solana_account_info::AccountInfo, solana_program_error::ProgramResult, solana_pubkey::Pubkey,
+};
 
-solana_program::entrypoint!(process_instruction);
+solana_program_entrypoint::entrypoint!(process_instruction);
 fn process_instruction(
     _program_id: &Pubkey,
     _accounts: &[AccountInfo],

+ 4 - 5
platform-tools-sdk/cargo-build-sbf/tests/crates/noop/Cargo.toml

@@ -10,14 +10,13 @@ edition = "2021"
 publish = false
 
 [dependencies]
-solana-program = { path = "../../../../../sdk/program", version = "=2.2.0" }
+solana-account-info= { path = "../../../../../sdk/account-info", version = "=2.2.0" }
+solana-program-entrypoint = { path = "../../../../../sdk/program-entrypoint", version = "=2.2.0" }
+solana-program-error= { path = "../../../../../sdk/program-error", version = "=2.2.0" }
+solana-pubkey = { path = "../../../../../sdk/pubkey", version = "=2.2.0" }
 
 [lib]
 crate-type = ["cdylib"]
 
-[patch.crates-io]
-solana-decode-error = { path = "../../../../../sdk/decode-error" }
-solana-instruction = { path = "../../../../../sdk/instruction" }
-solana-pubkey = { path = "../../../../../sdk/pubkey" }
 
 [workspace]

+ 4 - 2
platform-tools-sdk/cargo-build-sbf/tests/crates/noop/src/lib.rs

@@ -1,8 +1,10 @@
 //! Example Rust-based SBF noop program
 
-use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
+use {
+    solana_account_info::AccountInfo, solana_program_error::ProgramResult, solana_pubkey::Pubkey,
+};
 
-solana_program::entrypoint!(process_instruction);
+solana_program_entrypoint::entrypoint!(process_instruction);
 fn process_instruction(
     _program_id: &Pubkey,
     _accounts: &[AccountInfo],

+ 4 - 6
platform-tools-sdk/cargo-build-sbf/tests/crates/package-metadata/Cargo.toml

@@ -14,15 +14,13 @@ tools-version = "v1.43"
 program-id = "MyProgram1111111111111111111111111111111111"
 
 [dependencies]
+solana-account-info= { path = "../../../../../sdk/account-info", version = "=2.2.0" }
 solana-package-metadata = { path = "../../../../../sdk/package-metadata", version = "=2.2.0" }
-solana-program = { path = "../../../../../sdk/program", version = "=2.2.0" }
+solana-program-entrypoint = { path = "../../../../../sdk/program-entrypoint", version = "=2.2.0" }
+solana-program-error= { path = "../../../../../sdk/program-error", version = "=2.2.0" }
+solana-pubkey = { path = "../../../../../sdk/pubkey", version = "=2.2.0" }
 
 [lib]
 crate-type = ["cdylib"]
 
-[patch.crates-io]
-solana-decode-error = { path = "../../../../../sdk/decode-error" }
-solana-instruction = { path = "../../../../../sdk/instruction" }
-solana-pubkey = { path = "../../../../../sdk/pubkey" }
-
 [workspace]

+ 6 - 2
platform-tools-sdk/cargo-build-sbf/tests/crates/package-metadata/src/lib.rs

@@ -1,9 +1,13 @@
 //! Example Rust-based SBF noop program
 
-use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
+use {
+    solana_account_info::AccountInfo,
+    solana_program_error::ProgramResult,
+    solana_pubkey::Pubkey
+};
 
 solana_package_metadata::declare_id_with_package_metadata!("solana.program-id");
-solana_program::entrypoint!(process_instruction);
+solana_program_entrypoint::entrypoint!(process_instruction);
 fn process_instruction(
     _program_id: &Pubkey,
     _accounts: &[AccountInfo],

+ 4 - 6
platform-tools-sdk/cargo-build-sbf/tests/crates/workspace-metadata/Cargo.toml

@@ -10,16 +10,14 @@ edition = "2021"
 publish = false
 
 [dependencies]
-solana-program = { path = "../../../../../sdk/program", version = "=2.2.0" }
+solana-account-info= { path = "../../../../../sdk/account-info", version = "=2.2.0" }
+solana-program-entrypoint = { path = "../../../../../sdk/program-entrypoint", version = "=2.2.0" }
+solana-program-error= { path = "../../../../../sdk/program-error", version = "=2.2.0" }
+solana-pubkey = { path = "../../../../../sdk/pubkey", version = "=2.2.0" }
 
 [lib]
 crate-type = ["cdylib"]
 
-[patch.crates-io]
-solana-decode-error = { path = "../../../../../sdk/decode-error" }
-solana-instruction = { path = "../../../../../sdk/instruction" }
-solana-pubkey = { path = "../../../../../sdk/pubkey" }
-
 [workspace]
 
 [workspace.metadata.solana]

+ 6 - 2
platform-tools-sdk/cargo-build-sbf/tests/crates/workspace-metadata/src/lib.rs

@@ -1,8 +1,12 @@
 //! Example Rust-based SBF noop program
 
-use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
+use {
+    solana_account_info::AccountInfo,
+    solana_program_error::ProgramResult,
+    solana_pubkey::Pubkey
+};
 
-solana_program::entrypoint!(process_instruction);
+solana_program_entrypoint::entrypoint!(process_instruction);
 fn process_instruction(
     _program_id: &Pubkey,
     _accounts: &[AccountInfo],

+ 23 - 0
programs/sbf/Cargo.lock

@@ -6701,6 +6701,7 @@ dependencies = [
  "solana-slot-hashes",
  "solana-slot-history",
  "solana-stable-layout",
+ "solana-stake-interface",
  "solana-system-interface",
  "solana-sysvar",
  "solana-sysvar-id",
@@ -8012,6 +8013,27 @@ dependencies = [
  "solana-pubkey",
 ]
 
+[[package]]
+name = "solana-stake-interface"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c"
+dependencies = [
+ "borsh 0.10.3",
+ "borsh 1.5.5",
+ "num-traits",
+ "serde",
+ "serde_derive",
+ "solana-clock",
+ "solana-cpi",
+ "solana-decode-error",
+ "solana-instruction",
+ "solana-program-error",
+ "solana-pubkey",
+ "solana-system-interface",
+ "solana-sysvar-id",
+]
+
 [[package]]
 name = "solana-stake-program"
 version = "2.2.0"
@@ -8294,6 +8316,7 @@ dependencies = [
  "solana-sdk-macro",
  "solana-slot-hashes",
  "solana-slot-history",
+ "solana-stake-interface",
  "solana-sysvar-id",
 ]
 

+ 2 - 0
programs/sbf/Cargo.toml

@@ -247,6 +247,7 @@ members = [
 #
 # There is a similar override in `../../Cargo.toml`.  Please keep both comments
 # and the overrides in sync.
+solana-clock = { path = "../../sdk/clock" }
 solana-curve25519 = { path = "../../curves/curve25519" }
 solana-account-info = { path = "../../sdk/account-info" }
 solana-borsh = { path = "../../sdk/borsh" }
@@ -262,4 +263,5 @@ solana-program-option = { path = "../../sdk/program-option" }
 solana-program-pack = { path = "../../sdk/program-pack" }
 solana-pubkey = { path = "../../sdk/pubkey" }
 solana-sha256-hasher = { path = "../../sdk/sha256-hasher" }
+solana-sysvar-id = { path = "../../sdk/sysvar-id" }
 solana-zk-sdk = { path = "../../zk-sdk" }

+ 1 - 1
runtime/src/bank/serde_snapshot.rs

@@ -570,7 +570,7 @@ mod tests {
         #[cfg_attr(
             feature = "frozen-abi",
             derive(AbiExample),
-            frozen_abi(digest = "CiLUqUypBaGKz24XoQbv8EhpyeRD8jwwSFfosYWUrFL4")
+            frozen_abi(digest = "3PsrjAtyWBU3KPopGoM1UK1sa8HjVzehjBi7M2v6wW1Q")
         )]
         #[derive(Serialize)]
         pub struct BankAbiTestWrapper {

+ 2 - 0
scripts/patch-crates.sh

@@ -71,6 +71,7 @@ update_solana_dependencies() {
     solana-streamer
     solana-svm-rent-collector
     solana-svm-transaction
+    solana-sysvar-id
     solana-test-validator
     solana-thin-client
     solana-tpu-client
@@ -205,6 +206,7 @@ patch_crates_io_solana_no_header() {
   crates_map+=("solana-streamer streamer")
   crates_map+=("solana-svm-rent-collector svm-rent-collector")
   crates_map+=("solana-svm-transaction svm-transaction")
+  crates_map+=("solana-sysvar-id sdk/sysvar-id")
   crates_map+=("solana-test-validator test-validator")
   crates_map+=("solana-thin-client thin-client")
   crates_map+=("solana-tpu-client tpu-client")

+ 4 - 1
sdk/program/Cargo.toml

@@ -80,6 +80,7 @@ solana-short-vec = { workspace = true }
 solana-slot-hashes = { workspace = true, features = ["serde", "sysvar"] }
 solana-slot-history = { workspace = true, features = ["serde", "sysvar"] }
 solana-stable-layout = { workspace = true }
+solana-stake-interface = { workspace = true, features = ["bincode"] }
 solana-system-interface = { workspace = true, features = ["bincode"] }
 solana-sysvar = { workspace = true, features = ["bincode", "bytemuck"] }
 solana-sysvar-id = { workspace = true }
@@ -136,7 +137,8 @@ borsh = [
     "solana-hash/borsh",
     "solana-instruction/borsh",
     "solana-program-error/borsh",
-    "solana-pubkey/borsh"
+    "solana-pubkey/borsh",
+    "solana-stake-interface/borsh",
 ]
 dev-context-only-utils = []
 frozen-abi = [
@@ -151,6 +153,7 @@ frozen-abi = [
     "solana-pubkey/frozen-abi",
     "solana-rent/frozen-abi",
     "solana-short-vec/frozen-abi",
+    "solana-stake-interface/frozen-abi",
     "solana-sysvar/frozen-abi"
 ]
 

+ 0 - 7
sdk/program/src/lib.rs

@@ -638,13 +638,6 @@ pub use solana_pubkey::{declare_deprecated_id, declare_id, pubkey};
 #[deprecated(since = "2.1.0", note = "Use `solana-sysvar-id` crate instead")]
 pub use solana_sysvar_id::{declare_deprecated_sysvar_id, declare_sysvar_id};
 
-#[macro_use]
-extern crate serde_derive;
-
-#[cfg_attr(feature = "frozen-abi", macro_use)]
-#[cfg(feature = "frozen-abi")]
-extern crate solana_frozen_abi_macro;
-
 /// Convenience macro for doing integer division where the operation's safety
 /// can be checked at compile-time.
 ///

+ 13 - 0
sdk/program/src/stake.rs

@@ -0,0 +1,13 @@
+#[deprecated(since = "2.2.0", note = "Use solana-stake-interface instead")]
+pub use solana_stake_interface::{
+    config, stake_flags, state, tools, MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION,
+};
+
+pub mod instruction {
+    #[deprecated(since = "2.2.0", note = "Use solana-stake-interface instead")]
+    pub use solana_stake_interface::{error::StakeError, instruction::*};
+}
+
+pub mod program {
+    pub use solana_sdk_ids::stake::{check_id, id, ID};
+}

+ 0 - 32
sdk/program/src/stake/config.rs

@@ -1,32 +0,0 @@
-//! config for staking
-//!  carries variables that the stake program cares about
-
-#[deprecated(
-    since = "1.16.7",
-    note = "Please use `solana_sdk::stake::state::{DEFAULT_SLASH_PENALTY, DEFAULT_WARMUP_COOLDOWN_RATE}` instead"
-)]
-pub use super::state::{DEFAULT_SLASH_PENALTY, DEFAULT_WARMUP_COOLDOWN_RATE};
-use serde_derive::{Deserialize, Serialize};
-// stake config ID
-pub use solana_sdk_ids::stake::config::{check_id, id, ID};
-
-#[deprecated(
-    since = "1.16.7",
-    note = "Please use `solana_sdk::stake::state::warmup_cooldown_rate()` instead"
-)]
-#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
-pub struct Config {
-    /// how much stake we can activate/deactivate per-epoch as a fraction of currently effective stake
-    pub warmup_cooldown_rate: f64,
-    /// percentage of stake lost when slash, expressed as a portion of u8::MAX
-    pub slash_penalty: u8,
-}
-
-impl Default for Config {
-    fn default() -> Self {
-        Self {
-            warmup_cooldown_rate: DEFAULT_WARMUP_COOLDOWN_RATE,
-            slash_penalty: DEFAULT_SLASH_PENALTY,
-        }
-    }
-}

+ 0 - 954
sdk/program/src/stake/instruction.rs

@@ -1,954 +0,0 @@
-// Remove the following `allow` when the `Redelegate` variant is renamed to
-// `Unused` starting from v3.
-// Required to avoid warnings from uses of deprecated types during trait derivations.
-#![allow(deprecated)]
-
-use {
-    crate::{
-        instruction::{AccountMeta, Instruction},
-        program_error::ProgramError,
-        pubkey::Pubkey,
-        stake::{
-            config,
-            program::id,
-            state::{Authorized, Lockup, StakeAuthorize, StakeStateV2},
-        },
-        system_instruction, sysvar,
-    },
-    log::*,
-    num_derive::{FromPrimitive, ToPrimitive},
-    serde_derive::{Deserialize, Serialize},
-    solana_clock::{Epoch, UnixTimestamp},
-    solana_decode_error::DecodeError,
-    thiserror::Error,
-};
-
-/// Reasons the stake might have had an error
-#[derive(Error, Debug, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
-pub enum StakeError {
-    // 0
-    #[error("not enough credits to redeem")]
-    NoCreditsToRedeem,
-
-    #[error("lockup has not yet expired")]
-    LockupInForce,
-
-    #[error("stake already deactivated")]
-    AlreadyDeactivated,
-
-    #[error("one re-delegation permitted per epoch")]
-    TooSoonToRedelegate,
-
-    #[error("split amount is more than is staked")]
-    InsufficientStake,
-
-    // 5
-    #[error("stake account with transient stake cannot be merged")]
-    MergeTransientStake,
-
-    #[error("stake account merge failed due to different authority, lockups or state")]
-    MergeMismatch,
-
-    #[error("custodian address not present")]
-    CustodianMissing,
-
-    #[error("custodian signature not present")]
-    CustodianSignatureMissing,
-
-    #[error("insufficient voting activity in the reference vote account")]
-    InsufficientReferenceVotes,
-
-    // 10
-    #[error("stake account is not delegated to the provided vote account")]
-    VoteAddressMismatch,
-
-    #[error(
-        "stake account has not been delinquent for the minimum epochs required for deactivation"
-    )]
-    MinimumDelinquentEpochsForDeactivationNotMet,
-
-    #[error("delegation amount is less than the minimum")]
-    InsufficientDelegation,
-
-    #[error("stake account with transient or inactive stake cannot be redelegated")]
-    RedelegateTransientOrInactiveStake,
-
-    #[error("stake redelegation to the same vote account is not permitted")]
-    RedelegateToSameVoteAccount,
-
-    // 15
-    #[error("redelegated stake must be fully activated before deactivation")]
-    RedelegatedStakeMustFullyActivateBeforeDeactivationIsPermitted,
-
-    #[error("stake action is not permitted while the epoch rewards period is active")]
-    EpochRewardsActive,
-}
-
-impl From<StakeError> for ProgramError {
-    fn from(e: StakeError) -> Self {
-        ProgramError::Custom(e as u32)
-    }
-}
-
-impl<E> DecodeError<E> for StakeError {
-    fn type_of() -> &'static str {
-        "StakeError"
-    }
-}
-
-#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
-pub enum StakeInstruction {
-    /// Initialize a stake with lockup and authorization information
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Uninitialized stake account
-    ///   1. `[]` Rent sysvar
-    ///
-    /// Authorized carries pubkeys that must sign staker transactions
-    ///   and withdrawer transactions.
-    /// Lockup carries information about withdrawal restrictions
-    Initialize(Authorized, Lockup),
-
-    /// Authorize a key to manage stake or withdrawal
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Stake account to be updated
-    ///   1. `[]` Clock sysvar
-    ///   2. `[SIGNER]` The stake or withdraw authority
-    ///   3. Optional: `[SIGNER]` Lockup authority, if updating StakeAuthorize::Withdrawer before
-    ///      lockup expiration
-    Authorize(Pubkey, StakeAuthorize),
-
-    /// Delegate a stake to a particular vote account
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Initialized stake account to be delegated
-    ///   1. `[]` Vote account to which this stake will be delegated
-    ///   2. `[]` Clock sysvar
-    ///   3. `[]` Stake history sysvar that carries stake warmup/cooldown history
-    ///   4. `[]` Unused account, formerly the stake config
-    ///   5. `[SIGNER]` Stake authority
-    ///
-    /// The entire balance of the staking account is staked.  DelegateStake
-    ///   can be called multiple times, but re-delegation is delayed
-    ///   by one epoch
-    DelegateStake,
-
-    /// Split u64 tokens and stake off a stake account into another stake account.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Stake account to be split; must be in the Initialized or Stake state
-    ///   1. `[WRITE]` Uninitialized stake account that will take the split-off amount
-    ///   2. `[SIGNER]` Stake authority
-    Split(u64),
-
-    /// Withdraw unstaked lamports from the stake account
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Stake account from which to withdraw
-    ///   1. `[WRITE]` Recipient account
-    ///   2. `[]` Clock sysvar
-    ///   3. `[]` Stake history sysvar that carries stake warmup/cooldown history
-    ///   4. `[SIGNER]` Withdraw authority
-    ///   5. Optional: `[SIGNER]` Lockup authority, if before lockup expiration
-    ///
-    /// The u64 is the portion of the stake account balance to be withdrawn,
-    ///    must be `<= StakeAccount.lamports - staked_lamports`.
-    Withdraw(u64),
-
-    /// Deactivates the stake in the account
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Delegated stake account
-    ///   1. `[]` Clock sysvar
-    ///   2. `[SIGNER]` Stake authority
-    Deactivate,
-
-    /// Set stake lockup
-    ///
-    /// If a lockup is not active, the withdraw authority may set a new lockup
-    /// If a lockup is active, the lockup custodian may update the lockup parameters
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Initialized stake account
-    ///   1. `[SIGNER]` Lockup authority or withdraw authority
-    SetLockup(LockupArgs),
-
-    /// Merge two stake accounts.
-    ///
-    /// Both accounts must have identical lockup and authority keys. A merge
-    /// is possible between two stakes in the following states with no additional
-    /// conditions:
-    ///
-    /// * two deactivated stakes
-    /// * an inactive stake into an activating stake during its activation epoch
-    ///
-    /// For the following cases, the voter pubkey and vote credits observed must match:
-    ///
-    /// * two activated stakes
-    /// * two activating accounts that share an activation epoch, during the activation epoch
-    ///
-    /// All other combinations of stake states will fail to merge, including all
-    /// "transient" states, where a stake is activating or deactivating with a
-    /// non-zero effective stake.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Destination stake account for the merge
-    ///   1. `[WRITE]` Source stake account for to merge.  This account will be drained
-    ///   2. `[]` Clock sysvar
-    ///   3. `[]` Stake history sysvar that carries stake warmup/cooldown history
-    ///   4. `[SIGNER]` Stake authority
-    Merge,
-
-    /// Authorize a key to manage stake or withdrawal with a derived key
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Stake account to be updated
-    ///   1. `[SIGNER]` Base key of stake or withdraw authority
-    ///   2. `[]` Clock sysvar
-    ///   3. Optional: `[SIGNER]` Lockup authority, if updating StakeAuthorize::Withdrawer before
-    ///      lockup expiration
-    AuthorizeWithSeed(AuthorizeWithSeedArgs),
-
-    /// Initialize a stake with authorization information
-    ///
-    /// This instruction is similar to `Initialize` except that the withdraw authority
-    /// must be a signer, and no lockup is applied to the account.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Uninitialized stake account
-    ///   1. `[]` Rent sysvar
-    ///   2. `[]` The stake authority
-    ///   3. `[SIGNER]` The withdraw authority
-    ///
-    InitializeChecked,
-
-    /// Authorize a key to manage stake or withdrawal
-    ///
-    /// This instruction behaves like `Authorize` with the additional requirement that the new
-    /// stake or withdraw authority must also be a signer.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Stake account to be updated
-    ///   1. `[]` Clock sysvar
-    ///   2. `[SIGNER]` The stake or withdraw authority
-    ///   3. `[SIGNER]` The new stake or withdraw authority
-    ///   4. Optional: `[SIGNER]` Lockup authority, if updating StakeAuthorize::Withdrawer before
-    ///      lockup expiration
-    AuthorizeChecked(StakeAuthorize),
-
-    /// Authorize a key to manage stake or withdrawal with a derived key
-    ///
-    /// This instruction behaves like `AuthorizeWithSeed` with the additional requirement that
-    /// the new stake or withdraw authority must also be a signer.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Stake account to be updated
-    ///   1. `[SIGNER]` Base key of stake or withdraw authority
-    ///   2. `[]` Clock sysvar
-    ///   3. `[SIGNER]` The new stake or withdraw authority
-    ///   4. Optional: `[SIGNER]` Lockup authority, if updating StakeAuthorize::Withdrawer before
-    ///      lockup expiration
-    AuthorizeCheckedWithSeed(AuthorizeCheckedWithSeedArgs),
-
-    /// Set stake lockup
-    ///
-    /// This instruction behaves like `SetLockup` with the additional requirement that
-    /// the new lockup authority also be a signer.
-    ///
-    /// If a lockup is not active, the withdraw authority may set a new lockup
-    /// If a lockup is active, the lockup custodian may update the lockup parameters
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Initialized stake account
-    ///   1. `[SIGNER]` Lockup authority or withdraw authority
-    ///   2. Optional: `[SIGNER]` New lockup authority
-    SetLockupChecked(LockupCheckedArgs),
-
-    /// Get the minimum stake delegation, in lamports
-    ///
-    /// # Account references
-    ///   None
-    ///
-    /// Returns the minimum delegation as a little-endian encoded u64 value.
-    /// Programs can use the [`get_minimum_delegation()`] helper function to invoke and
-    /// retrieve the return value for this instruction.
-    ///
-    /// [`get_minimum_delegation()`]: super::tools::get_minimum_delegation
-    GetMinimumDelegation,
-
-    /// Deactivate stake delegated to a vote account that has been delinquent for at least
-    /// `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION` epochs.
-    ///
-    /// No signer is required for this instruction as it is a common good to deactivate abandoned
-    /// stake.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Delegated stake account
-    ///   1. `[]` Delinquent vote account for the delegated stake account
-    ///   2. `[]` Reference vote account that has voted at least once in the last
-    ///      `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION` epochs
-    DeactivateDelinquent,
-
-    /// Redelegate activated stake to another vote account.
-    ///
-    /// Upon success:
-    ///   * the balance of the delegated stake account will be reduced to the undelegated amount in
-    ///     the account (rent exempt minimum and any additional lamports not part of the delegation),
-    ///     and scheduled for deactivation.
-    ///   * the provided uninitialized stake account will receive the original balance of the
-    ///     delegated stake account, minus the rent exempt minimum, and scheduled for activation to
-    ///     the provided vote account. Any existing lamports in the uninitialized stake account
-    ///     will also be included in the re-delegation.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Delegated stake account to be redelegated. The account must be fully
-    ///      activated and carry a balance greater than or equal to the minimum delegation amount
-    ///      plus rent exempt minimum
-    ///   1. `[WRITE]` Uninitialized stake account that will hold the redelegated stake
-    ///   2. `[]` Vote account to which this stake will be re-delegated
-    ///   3. `[]` Unused account, formerly the stake config
-    ///   4. `[SIGNER]` Stake authority
-    ///
-    #[deprecated(since = "2.1.0", note = "Redelegate will not be enabled")]
-    Redelegate,
-
-    /// Move stake between accounts with the same authorities and lockups, using Staker authority.
-    ///
-    /// The source account must be fully active. If its entire delegation is moved, it immediately
-    /// becomes inactive. Otherwise, at least the minimum delegation of active stake must remain.
-    ///
-    /// The destination account must be fully active or fully inactive. If it is active, it must
-    /// be delegated to the same vote account as the source. If it is inactive, it
-    /// immediately becomes active, and must contain at least the minimum delegation. The
-    /// destination must be pre-funded with the rent-exempt reserve.
-    ///
-    /// This instruction only affects or moves active stake. Additional unstaked lamports are never
-    /// moved, activated, or deactivated, and accounts are never deallocated.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Active source stake account
-    ///   1. `[WRITE]` Active or inactive destination stake account
-    ///   2. `[SIGNER]` Stake authority
-    ///
-    /// The u64 is the portion of the stake to move, which may be the entire delegation
-    MoveStake(u64),
-
-    /// Move unstaked lamports between accounts with the same authorities and lockups, using Staker
-    /// authority.
-    ///
-    /// The source account must be fully active or fully inactive. The destination may be in any
-    /// mergeable state (active, inactive, or activating, but not in warmup cooldown). Only lamports that
-    /// are neither backing a delegation nor required for rent-exemption may be moved.
-    ///
-    /// # Account references
-    ///   0. `[WRITE]` Active or inactive source stake account
-    ///   1. `[WRITE]` Mergeable destination stake account
-    ///   2. `[SIGNER]` Stake authority
-    ///
-    /// The u64 is the portion of available lamports to move
-    MoveLamports(u64),
-}
-
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub struct LockupArgs {
-    pub unix_timestamp: Option<UnixTimestamp>,
-    pub epoch: Option<Epoch>,
-    pub custodian: Option<Pubkey>,
-}
-
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub struct LockupCheckedArgs {
-    pub unix_timestamp: Option<UnixTimestamp>,
-    pub epoch: Option<Epoch>,
-}
-
-#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
-pub struct AuthorizeWithSeedArgs {
-    pub new_authorized_pubkey: Pubkey,
-    pub stake_authorize: StakeAuthorize,
-    pub authority_seed: String,
-    pub authority_owner: Pubkey,
-}
-
-#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
-pub struct AuthorizeCheckedWithSeedArgs {
-    pub stake_authorize: StakeAuthorize,
-    pub authority_seed: String,
-    pub authority_owner: Pubkey,
-}
-
-pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::Initialize(*authorized, *lockup),
-        vec![
-            AccountMeta::new(*stake_pubkey, false),
-            AccountMeta::new_readonly(sysvar::rent::id(), false),
-        ],
-    )
-}
-
-pub fn initialize_checked(stake_pubkey: &Pubkey, authorized: &Authorized) -> Instruction {
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::InitializeChecked,
-        vec![
-            AccountMeta::new(*stake_pubkey, false),
-            AccountMeta::new_readonly(sysvar::rent::id(), false),
-            AccountMeta::new_readonly(authorized.staker, false),
-            AccountMeta::new_readonly(authorized.withdrawer, true),
-        ],
-    )
-}
-
-pub fn create_account_with_seed(
-    from_pubkey: &Pubkey,
-    stake_pubkey: &Pubkey,
-    base: &Pubkey,
-    seed: &str,
-    authorized: &Authorized,
-    lockup: &Lockup,
-    lamports: u64,
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::create_account_with_seed(
-            from_pubkey,
-            stake_pubkey,
-            base,
-            seed,
-            lamports,
-            StakeStateV2::size_of() as u64,
-            &id(),
-        ),
-        initialize(stake_pubkey, authorized, lockup),
-    ]
-}
-
-pub fn create_account(
-    from_pubkey: &Pubkey,
-    stake_pubkey: &Pubkey,
-    authorized: &Authorized,
-    lockup: &Lockup,
-    lamports: u64,
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::create_account(
-            from_pubkey,
-            stake_pubkey,
-            lamports,
-            StakeStateV2::size_of() as u64,
-            &id(),
-        ),
-        initialize(stake_pubkey, authorized, lockup),
-    ]
-}
-
-pub fn create_account_with_seed_checked(
-    from_pubkey: &Pubkey,
-    stake_pubkey: &Pubkey,
-    base: &Pubkey,
-    seed: &str,
-    authorized: &Authorized,
-    lamports: u64,
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::create_account_with_seed(
-            from_pubkey,
-            stake_pubkey,
-            base,
-            seed,
-            lamports,
-            StakeStateV2::size_of() as u64,
-            &id(),
-        ),
-        initialize_checked(stake_pubkey, authorized),
-    ]
-}
-
-pub fn create_account_checked(
-    from_pubkey: &Pubkey,
-    stake_pubkey: &Pubkey,
-    authorized: &Authorized,
-    lamports: u64,
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::create_account(
-            from_pubkey,
-            stake_pubkey,
-            lamports,
-            StakeStateV2::size_of() as u64,
-            &id(),
-        ),
-        initialize_checked(stake_pubkey, authorized),
-    ]
-}
-
-fn _split(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    lamports: u64,
-    split_stake_pubkey: &Pubkey,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new(*split_stake_pubkey, false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-
-    Instruction::new_with_bincode(id(), &StakeInstruction::Split(lamports), account_metas)
-}
-
-pub fn split(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    lamports: u64,
-    split_stake_pubkey: &Pubkey,
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::allocate(split_stake_pubkey, StakeStateV2::size_of() as u64),
-        system_instruction::assign(split_stake_pubkey, &id()),
-        _split(
-            stake_pubkey,
-            authorized_pubkey,
-            lamports,
-            split_stake_pubkey,
-        ),
-    ]
-}
-
-pub fn split_with_seed(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    lamports: u64,
-    split_stake_pubkey: &Pubkey, // derived using create_with_seed()
-    base: &Pubkey,               // base
-    seed: &str,                  // seed
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::allocate_with_seed(
-            split_stake_pubkey,
-            base,
-            seed,
-            StakeStateV2::size_of() as u64,
-            &id(),
-        ),
-        _split(
-            stake_pubkey,
-            authorized_pubkey,
-            lamports,
-            split_stake_pubkey,
-        ),
-    ]
-}
-
-pub fn merge(
-    destination_stake_pubkey: &Pubkey,
-    source_stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-) -> Vec<Instruction> {
-    let account_metas = vec![
-        AccountMeta::new(*destination_stake_pubkey, false),
-        AccountMeta::new(*source_stake_pubkey, false),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-
-    vec![Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::Merge,
-        account_metas,
-    )]
-}
-
-pub fn create_account_and_delegate_stake(
-    from_pubkey: &Pubkey,
-    stake_pubkey: &Pubkey,
-    vote_pubkey: &Pubkey,
-    authorized: &Authorized,
-    lockup: &Lockup,
-    lamports: u64,
-) -> Vec<Instruction> {
-    let mut instructions = create_account(from_pubkey, stake_pubkey, authorized, lockup, lamports);
-    instructions.push(delegate_stake(
-        stake_pubkey,
-        &authorized.staker,
-        vote_pubkey,
-    ));
-    instructions
-}
-
-pub fn create_account_with_seed_and_delegate_stake(
-    from_pubkey: &Pubkey,
-    stake_pubkey: &Pubkey,
-    base: &Pubkey,
-    seed: &str,
-    vote_pubkey: &Pubkey,
-    authorized: &Authorized,
-    lockup: &Lockup,
-    lamports: u64,
-) -> Vec<Instruction> {
-    let mut instructions = create_account_with_seed(
-        from_pubkey,
-        stake_pubkey,
-        base,
-        seed,
-        authorized,
-        lockup,
-        lamports,
-    );
-    instructions.push(delegate_stake(
-        stake_pubkey,
-        &authorized.staker,
-        vote_pubkey,
-    ));
-    instructions
-}
-
-pub fn authorize(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    new_authorized_pubkey: &Pubkey,
-    stake_authorize: StakeAuthorize,
-    custodian_pubkey: Option<&Pubkey>,
-) -> Instruction {
-    let mut account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-
-    if let Some(custodian_pubkey) = custodian_pubkey {
-        account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
-    }
-
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::Authorize(*new_authorized_pubkey, stake_authorize),
-        account_metas,
-    )
-}
-
-pub fn authorize_checked(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    new_authorized_pubkey: &Pubkey,
-    stake_authorize: StakeAuthorize,
-    custodian_pubkey: Option<&Pubkey>,
-) -> Instruction {
-    let mut account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-        AccountMeta::new_readonly(*new_authorized_pubkey, true),
-    ];
-
-    if let Some(custodian_pubkey) = custodian_pubkey {
-        account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
-    }
-
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::AuthorizeChecked(stake_authorize),
-        account_metas,
-    )
-}
-
-pub fn authorize_with_seed(
-    stake_pubkey: &Pubkey,
-    authority_base: &Pubkey,
-    authority_seed: String,
-    authority_owner: &Pubkey,
-    new_authorized_pubkey: &Pubkey,
-    stake_authorize: StakeAuthorize,
-    custodian_pubkey: Option<&Pubkey>,
-) -> Instruction {
-    let mut account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(*authority_base, true),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-    ];
-
-    if let Some(custodian_pubkey) = custodian_pubkey {
-        account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
-    }
-
-    let args = AuthorizeWithSeedArgs {
-        new_authorized_pubkey: *new_authorized_pubkey,
-        stake_authorize,
-        authority_seed,
-        authority_owner: *authority_owner,
-    };
-
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::AuthorizeWithSeed(args),
-        account_metas,
-    )
-}
-
-pub fn authorize_checked_with_seed(
-    stake_pubkey: &Pubkey,
-    authority_base: &Pubkey,
-    authority_seed: String,
-    authority_owner: &Pubkey,
-    new_authorized_pubkey: &Pubkey,
-    stake_authorize: StakeAuthorize,
-    custodian_pubkey: Option<&Pubkey>,
-) -> Instruction {
-    let mut account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(*authority_base, true),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(*new_authorized_pubkey, true),
-    ];
-
-    if let Some(custodian_pubkey) = custodian_pubkey {
-        account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
-    }
-
-    let args = AuthorizeCheckedWithSeedArgs {
-        stake_authorize,
-        authority_seed,
-        authority_owner: *authority_owner,
-    };
-
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::AuthorizeCheckedWithSeed(args),
-        account_metas,
-    )
-}
-
-pub fn delegate_stake(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    vote_pubkey: &Pubkey,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(*vote_pubkey, false),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
-        // For backwards compatibility we pass the stake config, although this account is unused
-        AccountMeta::new_readonly(config::id(), false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-    Instruction::new_with_bincode(id(), &StakeInstruction::DelegateStake, account_metas)
-}
-
-pub fn withdraw(
-    stake_pubkey: &Pubkey,
-    withdrawer_pubkey: &Pubkey,
-    to_pubkey: &Pubkey,
-    lamports: u64,
-    custodian_pubkey: Option<&Pubkey>,
-) -> Instruction {
-    let mut account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new(*to_pubkey, false),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(sysvar::stake_history::id(), false),
-        AccountMeta::new_readonly(*withdrawer_pubkey, true),
-    ];
-
-    if let Some(custodian_pubkey) = custodian_pubkey {
-        account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
-    }
-
-    Instruction::new_with_bincode(id(), &StakeInstruction::Withdraw(lamports), account_metas)
-}
-
-pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(sysvar::clock::id(), false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-    Instruction::new_with_bincode(id(), &StakeInstruction::Deactivate, account_metas)
-}
-
-pub fn set_lockup(
-    stake_pubkey: &Pubkey,
-    lockup: &LockupArgs,
-    custodian_pubkey: &Pubkey,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(*custodian_pubkey, true),
-    ];
-    Instruction::new_with_bincode(id(), &StakeInstruction::SetLockup(*lockup), account_metas)
-}
-
-pub fn set_lockup_checked(
-    stake_pubkey: &Pubkey,
-    lockup: &LockupArgs,
-    custodian_pubkey: &Pubkey,
-) -> Instruction {
-    let mut account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new_readonly(*custodian_pubkey, true),
-    ];
-
-    let lockup_checked = LockupCheckedArgs {
-        unix_timestamp: lockup.unix_timestamp,
-        epoch: lockup.epoch,
-    };
-    if let Some(new_custodian) = lockup.custodian {
-        account_metas.push(AccountMeta::new_readonly(new_custodian, true));
-    }
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::SetLockupChecked(lockup_checked),
-        account_metas,
-    )
-}
-
-pub fn get_minimum_delegation() -> Instruction {
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::GetMinimumDelegation,
-        Vec::default(),
-    )
-}
-
-pub fn deactivate_delinquent_stake(
-    stake_account: &Pubkey,
-    delinquent_vote_account: &Pubkey,
-    reference_vote_account: &Pubkey,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*stake_account, false),
-        AccountMeta::new_readonly(*delinquent_vote_account, false),
-        AccountMeta::new_readonly(*reference_vote_account, false),
-    ];
-    Instruction::new_with_bincode(id(), &StakeInstruction::DeactivateDelinquent, account_metas)
-}
-
-fn _redelegate(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    vote_pubkey: &Pubkey,
-    uninitialized_stake_pubkey: &Pubkey,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*stake_pubkey, false),
-        AccountMeta::new(*uninitialized_stake_pubkey, false),
-        AccountMeta::new_readonly(*vote_pubkey, false),
-        // For backwards compatibility we pass the stake config, although this account is unused
-        AccountMeta::new_readonly(config::id(), false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-    Instruction::new_with_bincode(id(), &StakeInstruction::Redelegate, account_metas)
-}
-
-#[deprecated(since = "2.1.0", note = "Redelegate will not be enabled")]
-pub fn redelegate(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    vote_pubkey: &Pubkey,
-    uninitialized_stake_pubkey: &Pubkey,
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::allocate(uninitialized_stake_pubkey, StakeStateV2::size_of() as u64),
-        system_instruction::assign(uninitialized_stake_pubkey, &id()),
-        _redelegate(
-            stake_pubkey,
-            authorized_pubkey,
-            vote_pubkey,
-            uninitialized_stake_pubkey,
-        ),
-    ]
-}
-
-#[deprecated(since = "2.1.0", note = "Redelegate will not be enabled")]
-pub fn redelegate_with_seed(
-    stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    vote_pubkey: &Pubkey,
-    uninitialized_stake_pubkey: &Pubkey, // derived using create_with_seed()
-    base: &Pubkey,                       // base
-    seed: &str,                          // seed
-) -> Vec<Instruction> {
-    vec![
-        system_instruction::allocate_with_seed(
-            uninitialized_stake_pubkey,
-            base,
-            seed,
-            StakeStateV2::size_of() as u64,
-            &id(),
-        ),
-        _redelegate(
-            stake_pubkey,
-            authorized_pubkey,
-            vote_pubkey,
-            uninitialized_stake_pubkey,
-        ),
-    ]
-}
-
-pub fn move_stake(
-    source_stake_pubkey: &Pubkey,
-    destination_stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    lamports: u64,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*source_stake_pubkey, false),
-        AccountMeta::new(*destination_stake_pubkey, false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-
-    Instruction::new_with_bincode(id(), &StakeInstruction::MoveStake(lamports), account_metas)
-}
-
-pub fn move_lamports(
-    source_stake_pubkey: &Pubkey,
-    destination_stake_pubkey: &Pubkey,
-    authorized_pubkey: &Pubkey,
-    lamports: u64,
-) -> Instruction {
-    let account_metas = vec![
-        AccountMeta::new(*source_stake_pubkey, false),
-        AccountMeta::new(*destination_stake_pubkey, false),
-        AccountMeta::new_readonly(*authorized_pubkey, true),
-    ];
-
-    Instruction::new_with_bincode(
-        id(),
-        &StakeInstruction::MoveLamports(lamports),
-        account_metas,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use {super::*, crate::instruction::InstructionError};
-
-    #[test]
-    fn test_custom_error_decode() {
-        use num_traits::FromPrimitive;
-        fn pretty_err<T>(err: InstructionError) -> String
-        where
-            T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
-        {
-            if let InstructionError::Custom(code) = err {
-                let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
-                format!(
-                    "{:?}: {}::{:?} - {}",
-                    err,
-                    T::type_of(),
-                    specific_error,
-                    specific_error,
-                )
-            } else {
-                "".to_string()
-            }
-        }
-        assert_eq!(
-            "Custom(0): StakeError::NoCreditsToRedeem - not enough credits to redeem",
-            pretty_err::<StakeError>(StakeError::NoCreditsToRedeem.into())
-        )
-    }
-}

+ 0 - 18
sdk/program/src/stake/mod.rs

@@ -1,18 +0,0 @@
-//! The [stake native program][np].
-//!
-//! [np]: https://docs.solanalabs.com/runtime/sysvars#stakehistory
-
-#[allow(deprecated)]
-pub mod config;
-pub mod instruction;
-pub mod stake_flags;
-pub mod state;
-pub mod tools;
-
-pub mod program {
-    pub use solana_sdk_ids::stake::{check_id, id, ID};
-}
-
-/// The minimum number of epochs before stake account that is delegated to a delinquent vote
-/// account may be unstaked with `StakeInstruction::DeactivateDelinquent`
-pub const MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION: usize = 5;

+ 0 - 140
sdk/program/src/stake/stake_flags.rs

@@ -1,140 +0,0 @@
-#[cfg(feature = "borsh")]
-use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
-
-/// Additional flags for stake state.
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[cfg_attr(
-    feature = "borsh",
-    derive(BorshSerialize, BorshDeserialize, BorshSchema),
-    borsh(crate = "borsh")
-)]
-#[derive(Serialize, Deserialize, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Debug)]
-pub struct StakeFlags {
-    bits: u8,
-}
-
-#[cfg(feature = "borsh")]
-impl borsh0_10::de::BorshDeserialize for StakeFlags {
-    fn deserialize_reader<R: borsh0_10::maybestd::io::Read>(
-        reader: &mut R,
-    ) -> ::core::result::Result<Self, borsh0_10::maybestd::io::Error> {
-        Ok(Self {
-            bits: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-        })
-    }
-}
-
-#[cfg(feature = "borsh")]
-impl borsh0_10::BorshSchema for StakeFlags {
-    fn declaration() -> borsh0_10::schema::Declaration {
-        "StakeFlags".to_string()
-    }
-    fn add_definitions_recursively(
-        definitions: &mut borsh0_10::maybestd::collections::HashMap<
-            borsh0_10::schema::Declaration,
-            borsh0_10::schema::Definition,
-        >,
-    ) {
-        let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec(
-            borsh0_10::maybestd::boxed::Box::new([(
-                "bits".to_string(),
-                <u8 as borsh0_10::BorshSchema>::declaration(),
-            )]),
-        ));
-        let definition = borsh0_10::schema::Definition::Struct { fields };
-        Self::add_definition(
-            <Self as borsh0_10::BorshSchema>::declaration(),
-            definition,
-            definitions,
-        );
-        <u8 as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-    }
-}
-
-#[cfg(feature = "borsh")]
-impl borsh0_10::ser::BorshSerialize for StakeFlags {
-    fn serialize<W: borsh0_10::maybestd::io::Write>(
-        &self,
-        writer: &mut W,
-    ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> {
-        borsh0_10::BorshSerialize::serialize(&self.bits, writer)?;
-        Ok(())
-    }
-}
-
-/// Currently, only bit 1 is used. The other 7 bits are reserved for future usage.
-impl StakeFlags {
-    ///  Stake must be fully activated before deactivation is allowed (bit 1).
-    #[deprecated(
-        since = "2.1.0",
-        note = "This flag will be removed because it was only used for `redelegate`, which will not be enabled."
-    )]
-    pub const MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED: Self =
-        Self { bits: 0b0000_0001 };
-
-    pub const fn empty() -> Self {
-        Self { bits: 0 }
-    }
-
-    pub const fn contains(&self, other: Self) -> bool {
-        (self.bits & other.bits) == other.bits
-    }
-
-    pub fn remove(&mut self, other: Self) {
-        self.bits &= !other.bits;
-    }
-
-    pub fn set(&mut self, other: Self) {
-        self.bits |= other.bits;
-    }
-
-    pub const fn union(self, other: Self) -> Self {
-        Self {
-            bits: self.bits | other.bits,
-        }
-    }
-}
-
-impl Default for StakeFlags {
-    fn default() -> Self {
-        StakeFlags::empty()
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    #[allow(deprecated)]
-    fn test_stake_flags() {
-        let mut f = StakeFlags::empty();
-        assert!(!f.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-
-        f.set(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED);
-        assert!(f.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-
-        f.remove(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED);
-        assert!(!f.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-
-        let f1 = StakeFlags::empty();
-        let f2 = StakeFlags::empty();
-        let f3 = f1.union(f2);
-        assert!(!f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-
-        let f1 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED;
-        let f2 = StakeFlags::empty();
-        let f3 = f1.union(f2);
-        assert!(f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-
-        let f1 = StakeFlags::empty();
-        let f2 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED;
-        let f3 = f1.union(f2);
-        assert!(f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-
-        let f1 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED;
-        let f2 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED;
-        let f3 = f1.union(f2);
-        assert!(f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED));
-    }
-}

+ 0 - 1301
sdk/program/src/stake/state.rs

@@ -1,1301 +0,0 @@
-#![allow(clippy::arithmetic_side_effects)]
-#![deny(clippy::wildcard_enum_match_arm)]
-// Remove the following `allow` when `StakeState` is removed, required to avoid
-// warnings from uses of deprecated types during trait derivations.
-#![allow(deprecated)]
-
-#[cfg(feature = "borsh")]
-use borsh::{io, BorshDeserialize, BorshSchema, BorshSerialize};
-use {
-    crate::{
-        instruction::InstructionError,
-        pubkey::Pubkey,
-        stake::{
-            instruction::{LockupArgs, StakeError},
-            stake_flags::StakeFlags,
-        },
-        stake_history::{StakeHistoryEntry, StakeHistoryGetEntry},
-    },
-    solana_clock::{Clock, Epoch, UnixTimestamp},
-    std::collections::HashSet,
-};
-
-pub type StakeActivationStatus = StakeHistoryEntry;
-
-// means that no more than RATE of current effective stake may be added or subtracted per
-// epoch
-pub const DEFAULT_WARMUP_COOLDOWN_RATE: f64 = 0.25;
-pub const NEW_WARMUP_COOLDOWN_RATE: f64 = 0.09;
-pub const DEFAULT_SLASH_PENALTY: u8 = ((5 * u8::MAX as usize) / 100) as u8;
-
-pub fn warmup_cooldown_rate(current_epoch: Epoch, new_rate_activation_epoch: Option<Epoch>) -> f64 {
-    if current_epoch < new_rate_activation_epoch.unwrap_or(u64::MAX) {
-        DEFAULT_WARMUP_COOLDOWN_RATE
-    } else {
-        NEW_WARMUP_COOLDOWN_RATE
-    }
-}
-
-#[cfg(feature = "borsh")]
-macro_rules! impl_borsh_stake_state {
-    ($borsh:ident) => {
-        impl $borsh::BorshDeserialize for StakeState {
-            fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
-                let enum_value: u32 = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                match enum_value {
-                    0 => Ok(StakeState::Uninitialized),
-                    1 => {
-                        let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        Ok(StakeState::Initialized(meta))
-                    }
-                    2 => {
-                        let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        let stake: Stake = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        Ok(StakeState::Stake(meta, stake))
-                    }
-                    3 => Ok(StakeState::RewardsPool),
-                    _ => Err(io::Error::new(
-                        io::ErrorKind::InvalidData,
-                        "Invalid enum value",
-                    )),
-                }
-            }
-        }
-        impl $borsh::BorshSerialize for StakeState {
-            fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
-                match self {
-                    StakeState::Uninitialized => writer.write_all(&0u32.to_le_bytes()),
-                    StakeState::Initialized(meta) => {
-                        writer.write_all(&1u32.to_le_bytes())?;
-                        $borsh::BorshSerialize::serialize(&meta, writer)
-                    }
-                    StakeState::Stake(meta, stake) => {
-                        writer.write_all(&2u32.to_le_bytes())?;
-                        $borsh::BorshSerialize::serialize(&meta, writer)?;
-                        $borsh::BorshSerialize::serialize(&stake, writer)
-                    }
-                    StakeState::RewardsPool => writer.write_all(&3u32.to_le_bytes()),
-                }
-            }
-        }
-    };
-}
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy)]
-#[allow(clippy::large_enum_variant)]
-#[deprecated(
-    since = "1.17.0",
-    note = "Please use `StakeStateV2` instead, and match the third `StakeFlags` field when matching `StakeStateV2::Stake` to resolve any breakage. For example, `if let StakeState::Stake(meta, stake)` becomes `if let StakeStateV2::Stake(meta, stake, _stake_flags)`."
-)]
-pub enum StakeState {
-    #[default]
-    Uninitialized,
-    Initialized(Meta),
-    Stake(Meta, Stake),
-    RewardsPool,
-}
-#[cfg(feature = "borsh")]
-impl_borsh_stake_state!(borsh);
-#[cfg(feature = "borsh")]
-impl_borsh_stake_state!(borsh0_10);
-impl StakeState {
-    /// The fixed number of bytes used to serialize each stake account
-    pub const fn size_of() -> usize {
-        200 // see test_size_of
-    }
-
-    pub fn stake(&self) -> Option<Stake> {
-        match self {
-            Self::Stake(_meta, stake) => Some(*stake),
-            Self::Uninitialized | Self::Initialized(_) | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn delegation(&self) -> Option<Delegation> {
-        match self {
-            Self::Stake(_meta, stake) => Some(stake.delegation),
-            Self::Uninitialized | Self::Initialized(_) | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn authorized(&self) -> Option<Authorized> {
-        match self {
-            Self::Stake(meta, _stake) => Some(meta.authorized),
-            Self::Initialized(meta) => Some(meta.authorized),
-            Self::Uninitialized | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn lockup(&self) -> Option<Lockup> {
-        self.meta().map(|meta| meta.lockup)
-    }
-
-    pub fn meta(&self) -> Option<Meta> {
-        match self {
-            Self::Stake(meta, _stake) => Some(*meta),
-            Self::Initialized(meta) => Some(*meta),
-            Self::Uninitialized | Self::RewardsPool => None,
-        }
-    }
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy)]
-#[allow(clippy::large_enum_variant)]
-pub enum StakeStateV2 {
-    #[default]
-    Uninitialized,
-    Initialized(Meta),
-    Stake(Meta, Stake, StakeFlags),
-    RewardsPool,
-}
-#[cfg(feature = "borsh")]
-macro_rules! impl_borsh_stake_state_v2 {
-    ($borsh:ident) => {
-        impl $borsh::BorshDeserialize for StakeStateV2 {
-            fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
-                let enum_value: u32 = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                match enum_value {
-                    0 => Ok(StakeStateV2::Uninitialized),
-                    1 => {
-                        let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        Ok(StakeStateV2::Initialized(meta))
-                    }
-                    2 => {
-                        let meta: Meta = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        let stake: Stake = $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        let stake_flags: StakeFlags =
-                            $borsh::BorshDeserialize::deserialize_reader(reader)?;
-                        Ok(StakeStateV2::Stake(meta, stake, stake_flags))
-                    }
-                    3 => Ok(StakeStateV2::RewardsPool),
-                    _ => Err(io::Error::new(
-                        io::ErrorKind::InvalidData,
-                        "Invalid enum value",
-                    )),
-                }
-            }
-        }
-        impl $borsh::BorshSerialize for StakeStateV2 {
-            fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
-                match self {
-                    StakeStateV2::Uninitialized => writer.write_all(&0u32.to_le_bytes()),
-                    StakeStateV2::Initialized(meta) => {
-                        writer.write_all(&1u32.to_le_bytes())?;
-                        $borsh::BorshSerialize::serialize(&meta, writer)
-                    }
-                    StakeStateV2::Stake(meta, stake, stake_flags) => {
-                        writer.write_all(&2u32.to_le_bytes())?;
-                        $borsh::BorshSerialize::serialize(&meta, writer)?;
-                        $borsh::BorshSerialize::serialize(&stake, writer)?;
-                        $borsh::BorshSerialize::serialize(&stake_flags, writer)
-                    }
-                    StakeStateV2::RewardsPool => writer.write_all(&3u32.to_le_bytes()),
-                }
-            }
-        }
-    };
-}
-#[cfg(feature = "borsh")]
-impl_borsh_stake_state_v2!(borsh);
-#[cfg(feature = "borsh")]
-impl_borsh_stake_state_v2!(borsh0_10);
-
-impl StakeStateV2 {
-    /// The fixed number of bytes used to serialize each stake account
-    pub const fn size_of() -> usize {
-        200 // see test_size_of
-    }
-
-    pub fn stake(&self) -> Option<Stake> {
-        match self {
-            Self::Stake(_meta, stake, _stake_flags) => Some(*stake),
-            Self::Uninitialized | Self::Initialized(_) | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn stake_ref(&self) -> Option<&Stake> {
-        match self {
-            Self::Stake(_meta, stake, _stake_flags) => Some(stake),
-            Self::Uninitialized | Self::Initialized(_) | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn delegation(&self) -> Option<Delegation> {
-        match self {
-            Self::Stake(_meta, stake, _stake_flags) => Some(stake.delegation),
-            Self::Uninitialized | Self::Initialized(_) | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn delegation_ref(&self) -> Option<&Delegation> {
-        match self {
-            StakeStateV2::Stake(_meta, stake, _stake_flags) => Some(&stake.delegation),
-            Self::Uninitialized | Self::Initialized(_) | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn authorized(&self) -> Option<Authorized> {
-        match self {
-            Self::Stake(meta, _stake, _stake_flags) => Some(meta.authorized),
-            Self::Initialized(meta) => Some(meta.authorized),
-            Self::Uninitialized | Self::RewardsPool => None,
-        }
-    }
-
-    pub fn lockup(&self) -> Option<Lockup> {
-        self.meta().map(|meta| meta.lockup)
-    }
-
-    pub fn meta(&self) -> Option<Meta> {
-        match self {
-            Self::Stake(meta, _stake, _stake_flags) => Some(*meta),
-            Self::Initialized(meta) => Some(*meta),
-            Self::Uninitialized | Self::RewardsPool => None,
-        }
-    }
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub enum StakeAuthorize {
-    Staker,
-    Withdrawer,
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[cfg_attr(
-    feature = "borsh",
-    derive(BorshSerialize, BorshDeserialize, BorshSchema),
-    borsh(crate = "borsh")
-)]
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub struct Lockup {
-    /// UnixTimestamp at which this stake will allow withdrawal, unless the
-    ///   transaction is signed by the custodian
-    pub unix_timestamp: UnixTimestamp,
-    /// epoch height at which this stake will allow withdrawal, unless the
-    ///   transaction is signed by the custodian
-    pub epoch: Epoch,
-    /// custodian signature on a transaction exempts the operation from
-    ///  lockup constraints
-    pub custodian: Pubkey,
-}
-impl Lockup {
-    pub fn is_in_force(&self, clock: &Clock, custodian: Option<&Pubkey>) -> bool {
-        if custodian == Some(&self.custodian) {
-            return false;
-        }
-        self.unix_timestamp > clock.unix_timestamp || self.epoch > clock.epoch
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::de::BorshDeserialize for Lockup {
-    fn deserialize_reader<R: borsh0_10::maybestd::io::Read>(
-        reader: &mut R,
-    ) -> ::core::result::Result<Self, borsh0_10::maybestd::io::Error> {
-        Ok(Self {
-            unix_timestamp: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            epoch: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            custodian: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-        })
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::BorshSchema for Lockup {
-    fn declaration() -> borsh0_10::schema::Declaration {
-        "Lockup".to_string()
-    }
-    fn add_definitions_recursively(
-        definitions: &mut borsh0_10::maybestd::collections::HashMap<
-            borsh0_10::schema::Declaration,
-            borsh0_10::schema::Definition,
-        >,
-    ) {
-        let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec(
-            borsh0_10::maybestd::boxed::Box::new([
-                (
-                    "unix_timestamp".to_string(),
-                    <UnixTimestamp as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "epoch".to_string(),
-                    <Epoch as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "custodian".to_string(),
-                    <Pubkey as borsh0_10::BorshSchema>::declaration(),
-                ),
-            ]),
-        ));
-        let definition = borsh0_10::schema::Definition::Struct { fields };
-        Self::add_definition(
-            <Self as borsh0_10::BorshSchema>::declaration(),
-            definition,
-            definitions,
-        );
-        <UnixTimestamp as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Epoch as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Pubkey as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::ser::BorshSerialize for Lockup {
-    fn serialize<W: borsh0_10::maybestd::io::Write>(
-        &self,
-        writer: &mut W,
-    ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> {
-        borsh0_10::BorshSerialize::serialize(&self.unix_timestamp, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.epoch, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.custodian, writer)?;
-        Ok(())
-    }
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[cfg_attr(
-    feature = "borsh",
-    derive(BorshSerialize, BorshDeserialize, BorshSchema),
-    borsh(crate = "borsh")
-)]
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub struct Authorized {
-    pub staker: Pubkey,
-    pub withdrawer: Pubkey,
-}
-
-impl Authorized {
-    pub fn auto(authorized: &Pubkey) -> Self {
-        Self {
-            staker: *authorized,
-            withdrawer: *authorized,
-        }
-    }
-    pub fn check(
-        &self,
-        signers: &HashSet<Pubkey>,
-        stake_authorize: StakeAuthorize,
-    ) -> Result<(), InstructionError> {
-        let authorized_signer = match stake_authorize {
-            StakeAuthorize::Staker => &self.staker,
-            StakeAuthorize::Withdrawer => &self.withdrawer,
-        };
-
-        if signers.contains(authorized_signer) {
-            Ok(())
-        } else {
-            Err(InstructionError::MissingRequiredSignature)
-        }
-    }
-
-    pub fn authorize(
-        &mut self,
-        signers: &HashSet<Pubkey>,
-        new_authorized: &Pubkey,
-        stake_authorize: StakeAuthorize,
-        lockup_custodian_args: Option<(&Lockup, &Clock, Option<&Pubkey>)>,
-    ) -> Result<(), InstructionError> {
-        match stake_authorize {
-            StakeAuthorize::Staker => {
-                // Allow either the staker or the withdrawer to change the staker key
-                if !signers.contains(&self.staker) && !signers.contains(&self.withdrawer) {
-                    return Err(InstructionError::MissingRequiredSignature);
-                }
-                self.staker = *new_authorized
-            }
-            StakeAuthorize::Withdrawer => {
-                if let Some((lockup, clock, custodian)) = lockup_custodian_args {
-                    if lockup.is_in_force(clock, None) {
-                        match custodian {
-                            None => {
-                                return Err(StakeError::CustodianMissing.into());
-                            }
-                            Some(custodian) => {
-                                if !signers.contains(custodian) {
-                                    return Err(StakeError::CustodianSignatureMissing.into());
-                                }
-
-                                if lockup.is_in_force(clock, Some(custodian)) {
-                                    return Err(StakeError::LockupInForce.into());
-                                }
-                            }
-                        }
-                    }
-                }
-                self.check(signers, stake_authorize)?;
-                self.withdrawer = *new_authorized
-            }
-        }
-        Ok(())
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::de::BorshDeserialize for Authorized {
-    fn deserialize_reader<R: borsh0_10::maybestd::io::Read>(
-        reader: &mut R,
-    ) -> ::core::result::Result<Self, borsh0_10::maybestd::io::Error> {
-        Ok(Self {
-            staker: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            withdrawer: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-        })
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::BorshSchema for Authorized {
-    fn declaration() -> borsh0_10::schema::Declaration {
-        "Authorized".to_string()
-    }
-    fn add_definitions_recursively(
-        definitions: &mut borsh0_10::maybestd::collections::HashMap<
-            borsh0_10::schema::Declaration,
-            borsh0_10::schema::Definition,
-        >,
-    ) {
-        let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec(
-            borsh0_10::maybestd::boxed::Box::new([
-                (
-                    "staker".to_string(),
-                    <Pubkey as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "withdrawer".to_string(),
-                    <Pubkey as borsh0_10::BorshSchema>::declaration(),
-                ),
-            ]),
-        ));
-        let definition = borsh0_10::schema::Definition::Struct { fields };
-        Self::add_definition(
-            <Self as borsh0_10::BorshSchema>::declaration(),
-            definition,
-            definitions,
-        );
-        <Pubkey as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Pubkey as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::ser::BorshSerialize for Authorized {
-    fn serialize<W: borsh0_10::maybestd::io::Write>(
-        &self,
-        writer: &mut W,
-    ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> {
-        borsh0_10::BorshSerialize::serialize(&self.staker, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.withdrawer, writer)?;
-        Ok(())
-    }
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[cfg_attr(
-    feature = "borsh",
-    derive(BorshSerialize, BorshDeserialize, BorshSchema),
-    borsh(crate = "borsh")
-)]
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub struct Meta {
-    pub rent_exempt_reserve: u64,
-    pub authorized: Authorized,
-    pub lockup: Lockup,
-}
-
-impl Meta {
-    pub fn set_lockup(
-        &mut self,
-        lockup: &LockupArgs,
-        signers: &HashSet<Pubkey>,
-        clock: &Clock,
-    ) -> Result<(), InstructionError> {
-        // post-stake_program_v4 behavior:
-        // * custodian can update the lockup while in force
-        // * withdraw authority can set a new lockup
-        if self.lockup.is_in_force(clock, None) {
-            if !signers.contains(&self.lockup.custodian) {
-                return Err(InstructionError::MissingRequiredSignature);
-            }
-        } else if !signers.contains(&self.authorized.withdrawer) {
-            return Err(InstructionError::MissingRequiredSignature);
-        }
-        if let Some(unix_timestamp) = lockup.unix_timestamp {
-            self.lockup.unix_timestamp = unix_timestamp;
-        }
-        if let Some(epoch) = lockup.epoch {
-            self.lockup.epoch = epoch;
-        }
-        if let Some(custodian) = lockup.custodian {
-            self.lockup.custodian = custodian;
-        }
-        Ok(())
-    }
-
-    pub fn auto(authorized: &Pubkey) -> Self {
-        Self {
-            authorized: Authorized::auto(authorized),
-            ..Meta::default()
-        }
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::de::BorshDeserialize for Meta {
-    fn deserialize_reader<R: borsh0_10::maybestd::io::Read>(
-        reader: &mut R,
-    ) -> ::core::result::Result<Self, borsh0_10::maybestd::io::Error> {
-        Ok(Self {
-            rent_exempt_reserve: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            authorized: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            lockup: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-        })
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::BorshSchema for Meta {
-    fn declaration() -> borsh0_10::schema::Declaration {
-        "Meta".to_string()
-    }
-    fn add_definitions_recursively(
-        definitions: &mut borsh0_10::maybestd::collections::HashMap<
-            borsh0_10::schema::Declaration,
-            borsh0_10::schema::Definition,
-        >,
-    ) {
-        let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec(
-            borsh0_10::maybestd::boxed::Box::new([
-                (
-                    "rent_exempt_reserve".to_string(),
-                    <u64 as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "authorized".to_string(),
-                    <Authorized as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "lockup".to_string(),
-                    <Lockup as borsh0_10::BorshSchema>::declaration(),
-                ),
-            ]),
-        ));
-        let definition = borsh0_10::schema::Definition::Struct { fields };
-        Self::add_definition(
-            <Self as borsh0_10::BorshSchema>::declaration(),
-            definition,
-            definitions,
-        );
-        <u64 as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Authorized as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Lockup as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::ser::BorshSerialize for Meta {
-    fn serialize<W: borsh0_10::maybestd::io::Write>(
-        &self,
-        writer: &mut W,
-    ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> {
-        borsh0_10::BorshSerialize::serialize(&self.rent_exempt_reserve, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.authorized, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.lockup, writer)?;
-        Ok(())
-    }
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[cfg_attr(
-    feature = "borsh",
-    derive(BorshSerialize, BorshDeserialize, BorshSchema),
-    borsh(crate = "borsh")
-)]
-#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
-pub struct Delegation {
-    /// to whom the stake is delegated
-    pub voter_pubkey: Pubkey,
-    /// activated stake amount, set at delegate() time
-    pub stake: u64,
-    /// epoch at which this stake was activated, std::Epoch::MAX if is a bootstrap stake
-    pub activation_epoch: Epoch,
-    /// epoch the stake was deactivated, std::Epoch::MAX if not deactivated
-    pub deactivation_epoch: Epoch,
-    /// how much stake we can activate per-epoch as a fraction of currently effective stake
-    #[deprecated(
-        since = "1.16.7",
-        note = "Please use `solana_sdk::stake::state::warmup_cooldown_rate()` instead"
-    )]
-    pub warmup_cooldown_rate: f64,
-}
-
-impl Default for Delegation {
-    fn default() -> Self {
-        #[allow(deprecated)]
-        Self {
-            voter_pubkey: Pubkey::default(),
-            stake: 0,
-            activation_epoch: 0,
-            deactivation_epoch: u64::MAX,
-            warmup_cooldown_rate: DEFAULT_WARMUP_COOLDOWN_RATE,
-        }
-    }
-}
-
-impl Delegation {
-    pub fn new(voter_pubkey: &Pubkey, stake: u64, activation_epoch: Epoch) -> Self {
-        Self {
-            voter_pubkey: *voter_pubkey,
-            stake,
-            activation_epoch,
-            ..Delegation::default()
-        }
-    }
-    pub fn is_bootstrap(&self) -> bool {
-        self.activation_epoch == u64::MAX
-    }
-
-    pub fn stake<T: StakeHistoryGetEntry>(
-        &self,
-        epoch: Epoch,
-        history: &T,
-        new_rate_activation_epoch: Option<Epoch>,
-    ) -> u64 {
-        self.stake_activating_and_deactivating(epoch, history, new_rate_activation_epoch)
-            .effective
-    }
-
-    #[allow(clippy::comparison_chain)]
-    pub fn stake_activating_and_deactivating<T: StakeHistoryGetEntry>(
-        &self,
-        target_epoch: Epoch,
-        history: &T,
-        new_rate_activation_epoch: Option<Epoch>,
-    ) -> StakeActivationStatus {
-        // first, calculate an effective and activating stake
-        let (effective_stake, activating_stake) =
-            self.stake_and_activating(target_epoch, history, new_rate_activation_epoch);
-
-        // then de-activate some portion if necessary
-        if target_epoch < self.deactivation_epoch {
-            // not deactivated
-            if activating_stake == 0 {
-                StakeActivationStatus::with_effective(effective_stake)
-            } else {
-                StakeActivationStatus::with_effective_and_activating(
-                    effective_stake,
-                    activating_stake,
-                )
-            }
-        } else if target_epoch == self.deactivation_epoch {
-            // can only deactivate what's activated
-            StakeActivationStatus::with_deactivating(effective_stake)
-        } else if let Some((history, mut prev_epoch, mut prev_cluster_stake)) = history
-            .get_entry(self.deactivation_epoch)
-            .map(|cluster_stake_at_deactivation_epoch| {
-                (
-                    history,
-                    self.deactivation_epoch,
-                    cluster_stake_at_deactivation_epoch,
-                )
-            })
-        {
-            // target_epoch > self.deactivation_epoch
-
-            // loop from my deactivation epoch until the target epoch
-            // current effective stake is updated using its previous epoch's cluster stake
-            let mut current_epoch;
-            let mut current_effective_stake = effective_stake;
-            loop {
-                current_epoch = prev_epoch + 1;
-                // if there is no deactivating stake at prev epoch, we should have been
-                // fully undelegated at this moment
-                if prev_cluster_stake.deactivating == 0 {
-                    break;
-                }
-
-                // I'm trying to get to zero, how much of the deactivation in stake
-                //   this account is entitled to take
-                let weight =
-                    current_effective_stake as f64 / prev_cluster_stake.deactivating as f64;
-                let warmup_cooldown_rate =
-                    warmup_cooldown_rate(current_epoch, new_rate_activation_epoch);
-
-                // portion of newly not-effective cluster stake I'm entitled to at current epoch
-                let newly_not_effective_cluster_stake =
-                    prev_cluster_stake.effective as f64 * warmup_cooldown_rate;
-                let newly_not_effective_stake =
-                    ((weight * newly_not_effective_cluster_stake) as u64).max(1);
-
-                current_effective_stake =
-                    current_effective_stake.saturating_sub(newly_not_effective_stake);
-                if current_effective_stake == 0 {
-                    break;
-                }
-
-                if current_epoch >= target_epoch {
-                    break;
-                }
-                if let Some(current_cluster_stake) = history.get_entry(current_epoch) {
-                    prev_epoch = current_epoch;
-                    prev_cluster_stake = current_cluster_stake;
-                } else {
-                    break;
-                }
-            }
-
-            // deactivating stake should equal to all of currently remaining effective stake
-            StakeActivationStatus::with_deactivating(current_effective_stake)
-        } else {
-            // no history or I've dropped out of history, so assume fully deactivated
-            StakeActivationStatus::default()
-        }
-    }
-
-    // returned tuple is (effective, activating) stake
-    fn stake_and_activating<T: StakeHistoryGetEntry>(
-        &self,
-        target_epoch: Epoch,
-        history: &T,
-        new_rate_activation_epoch: Option<Epoch>,
-    ) -> (u64, u64) {
-        let delegated_stake = self.stake;
-
-        if self.is_bootstrap() {
-            // fully effective immediately
-            (delegated_stake, 0)
-        } else if self.activation_epoch == self.deactivation_epoch {
-            // activated but instantly deactivated; no stake at all regardless of target_epoch
-            // this must be after the bootstrap check and before all-is-activating check
-            (0, 0)
-        } else if target_epoch == self.activation_epoch {
-            // all is activating
-            (0, delegated_stake)
-        } else if target_epoch < self.activation_epoch {
-            // not yet enabled
-            (0, 0)
-        } else if let Some((history, mut prev_epoch, mut prev_cluster_stake)) = history
-            .get_entry(self.activation_epoch)
-            .map(|cluster_stake_at_activation_epoch| {
-                (
-                    history,
-                    self.activation_epoch,
-                    cluster_stake_at_activation_epoch,
-                )
-            })
-        {
-            // target_epoch > self.activation_epoch
-
-            // loop from my activation epoch until the target epoch summing up my entitlement
-            // current effective stake is updated using its previous epoch's cluster stake
-            let mut current_epoch;
-            let mut current_effective_stake = 0;
-            loop {
-                current_epoch = prev_epoch + 1;
-                // if there is no activating stake at prev epoch, we should have been
-                // fully effective at this moment
-                if prev_cluster_stake.activating == 0 {
-                    break;
-                }
-
-                // how much of the growth in stake this account is
-                //  entitled to take
-                let remaining_activating_stake = delegated_stake - current_effective_stake;
-                let weight =
-                    remaining_activating_stake as f64 / prev_cluster_stake.activating as f64;
-                let warmup_cooldown_rate =
-                    warmup_cooldown_rate(current_epoch, new_rate_activation_epoch);
-
-                // portion of newly effective cluster stake I'm entitled to at current epoch
-                let newly_effective_cluster_stake =
-                    prev_cluster_stake.effective as f64 * warmup_cooldown_rate;
-                let newly_effective_stake =
-                    ((weight * newly_effective_cluster_stake) as u64).max(1);
-
-                current_effective_stake += newly_effective_stake;
-                if current_effective_stake >= delegated_stake {
-                    current_effective_stake = delegated_stake;
-                    break;
-                }
-
-                if current_epoch >= target_epoch || current_epoch >= self.deactivation_epoch {
-                    break;
-                }
-                if let Some(current_cluster_stake) = history.get_entry(current_epoch) {
-                    prev_epoch = current_epoch;
-                    prev_cluster_stake = current_cluster_stake;
-                } else {
-                    break;
-                }
-            }
-
-            (
-                current_effective_stake,
-                delegated_stake - current_effective_stake,
-            )
-        } else {
-            // no history or I've dropped out of history, so assume fully effective
-            (delegated_stake, 0)
-        }
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::de::BorshDeserialize for Delegation {
-    fn deserialize_reader<R: borsh0_10::maybestd::io::Read>(
-        reader: &mut R,
-    ) -> ::core::result::Result<Self, borsh0_10::maybestd::io::Error> {
-        Ok(Self {
-            voter_pubkey: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            stake: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            activation_epoch: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            deactivation_epoch: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            warmup_cooldown_rate: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-        })
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::BorshSchema for Delegation {
-    fn declaration() -> borsh0_10::schema::Declaration {
-        "Delegation".to_string()
-    }
-    fn add_definitions_recursively(
-        definitions: &mut borsh0_10::maybestd::collections::HashMap<
-            borsh0_10::schema::Declaration,
-            borsh0_10::schema::Definition,
-        >,
-    ) {
-        let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec(
-            borsh0_10::maybestd::boxed::Box::new([
-                (
-                    "voter_pubkey".to_string(),
-                    <Pubkey as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "stake".to_string(),
-                    <u64 as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "activation_epoch".to_string(),
-                    <Epoch as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "deactivation_epoch".to_string(),
-                    <Epoch as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "warmup_cooldown_rate".to_string(),
-                    <f64 as borsh0_10::BorshSchema>::declaration(),
-                ),
-            ]),
-        ));
-        let definition = borsh0_10::schema::Definition::Struct { fields };
-        Self::add_definition(
-            <Self as borsh0_10::BorshSchema>::declaration(),
-            definition,
-            definitions,
-        );
-        <Pubkey as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <u64 as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Epoch as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <Epoch as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <f64 as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::ser::BorshSerialize for Delegation {
-    fn serialize<W: borsh0_10::maybestd::io::Write>(
-        &self,
-        writer: &mut W,
-    ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> {
-        borsh0_10::BorshSerialize::serialize(&self.voter_pubkey, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.stake, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.activation_epoch, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.deactivation_epoch, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.warmup_cooldown_rate, writer)?;
-        Ok(())
-    }
-}
-
-#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[cfg_attr(
-    feature = "borsh",
-    derive(BorshSerialize, BorshDeserialize, BorshSchema),
-    borsh(crate = "borsh")
-)]
-#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy)]
-pub struct Stake {
-    pub delegation: Delegation,
-    /// credits observed is credits from vote account state when delegated or redeemed
-    pub credits_observed: u64,
-}
-
-impl Stake {
-    pub fn stake<T: StakeHistoryGetEntry>(
-        &self,
-        epoch: Epoch,
-        history: &T,
-        new_rate_activation_epoch: Option<Epoch>,
-    ) -> u64 {
-        self.delegation
-            .stake(epoch, history, new_rate_activation_epoch)
-    }
-
-    pub fn split(
-        &mut self,
-        remaining_stake_delta: u64,
-        split_stake_amount: u64,
-    ) -> Result<Self, StakeError> {
-        if remaining_stake_delta > self.delegation.stake {
-            return Err(StakeError::InsufficientStake);
-        }
-        self.delegation.stake -= remaining_stake_delta;
-        let new = Self {
-            delegation: Delegation {
-                stake: split_stake_amount,
-                ..self.delegation
-            },
-            ..*self
-        };
-        Ok(new)
-    }
-
-    pub fn deactivate(&mut self, epoch: Epoch) -> Result<(), StakeError> {
-        if self.delegation.deactivation_epoch != u64::MAX {
-            Err(StakeError::AlreadyDeactivated)
-        } else {
-            self.delegation.deactivation_epoch = epoch;
-            Ok(())
-        }
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::de::BorshDeserialize for Stake {
-    fn deserialize_reader<R: borsh0_10::maybestd::io::Read>(
-        reader: &mut R,
-    ) -> ::core::result::Result<Self, borsh0_10::maybestd::io::Error> {
-        Ok(Self {
-            delegation: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-            credits_observed: borsh0_10::BorshDeserialize::deserialize_reader(reader)?,
-        })
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::BorshSchema for Stake {
-    fn declaration() -> borsh0_10::schema::Declaration {
-        "Stake".to_string()
-    }
-    fn add_definitions_recursively(
-        definitions: &mut borsh0_10::maybestd::collections::HashMap<
-            borsh0_10::schema::Declaration,
-            borsh0_10::schema::Definition,
-        >,
-    ) {
-        let fields = borsh0_10::schema::Fields::NamedFields(<[_]>::into_vec(
-            borsh0_10::maybestd::boxed::Box::new([
-                (
-                    "delegation".to_string(),
-                    <Delegation as borsh0_10::BorshSchema>::declaration(),
-                ),
-                (
-                    "credits_observed".to_string(),
-                    <u64 as borsh0_10::BorshSchema>::declaration(),
-                ),
-            ]),
-        ));
-        let definition = borsh0_10::schema::Definition::Struct { fields };
-        Self::add_definition(
-            <Self as borsh0_10::BorshSchema>::declaration(),
-            definition,
-            definitions,
-        );
-        <Delegation as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-        <u64 as borsh0_10::BorshSchema>::add_definitions_recursively(definitions);
-    }
-}
-#[cfg(feature = "borsh")]
-impl borsh0_10::ser::BorshSerialize for Stake {
-    fn serialize<W: borsh0_10::maybestd::io::Write>(
-        &self,
-        writer: &mut W,
-    ) -> ::core::result::Result<(), borsh0_10::maybestd::io::Error> {
-        borsh0_10::BorshSerialize::serialize(&self.delegation, writer)?;
-        borsh0_10::BorshSerialize::serialize(&self.credits_observed, writer)?;
-        Ok(())
-    }
-}
-
-#[cfg(test)]
-mod test {
-    #[cfg(feature = "borsh")]
-    use crate::borsh1::try_from_slice_unchecked;
-    use {super::*, assert_matches::assert_matches, bincode::serialize};
-
-    #[cfg(feature = "borsh")]
-    fn check_borsh_deserialization(stake: StakeStateV2) {
-        let serialized = serialize(&stake).unwrap();
-        let deserialized = StakeStateV2::try_from_slice(&serialized).unwrap();
-        assert_eq!(stake, deserialized);
-    }
-
-    #[cfg(feature = "borsh")]
-    fn check_borsh_serialization(stake: StakeStateV2) {
-        let bincode_serialized = serialize(&stake).unwrap();
-        let borsh_serialized = borsh::to_vec(&stake).unwrap();
-        assert_eq!(bincode_serialized, borsh_serialized);
-    }
-
-    #[cfg(feature = "borsh")]
-    #[test]
-    fn test_size_of() {
-        assert_eq!(StakeStateV2::size_of(), std::mem::size_of::<StakeStateV2>());
-    }
-
-    #[cfg(feature = "borsh")]
-    #[test]
-    fn bincode_vs_borsh_deserialization() {
-        check_borsh_deserialization(StakeStateV2::Uninitialized);
-        check_borsh_deserialization(StakeStateV2::RewardsPool);
-        check_borsh_deserialization(StakeStateV2::Initialized(Meta {
-            rent_exempt_reserve: u64::MAX,
-            authorized: Authorized {
-                staker: Pubkey::new_unique(),
-                withdrawer: Pubkey::new_unique(),
-            },
-            lockup: Lockup::default(),
-        }));
-        check_borsh_deserialization(StakeStateV2::Stake(
-            Meta {
-                rent_exempt_reserve: 1,
-                authorized: Authorized {
-                    staker: Pubkey::new_unique(),
-                    withdrawer: Pubkey::new_unique(),
-                },
-                lockup: Lockup::default(),
-            },
-            Stake {
-                delegation: Delegation {
-                    voter_pubkey: Pubkey::new_unique(),
-                    stake: u64::MAX,
-                    activation_epoch: Epoch::MAX,
-                    deactivation_epoch: Epoch::MAX,
-                    ..Delegation::default()
-                },
-                credits_observed: 1,
-            },
-            StakeFlags::empty(),
-        ));
-    }
-
-    #[cfg(feature = "borsh")]
-    #[test]
-    fn bincode_vs_borsh_serialization() {
-        check_borsh_serialization(StakeStateV2::Uninitialized);
-        check_borsh_serialization(StakeStateV2::RewardsPool);
-        check_borsh_serialization(StakeStateV2::Initialized(Meta {
-            rent_exempt_reserve: u64::MAX,
-            authorized: Authorized {
-                staker: Pubkey::new_unique(),
-                withdrawer: Pubkey::new_unique(),
-            },
-            lockup: Lockup::default(),
-        }));
-        #[allow(deprecated)]
-        check_borsh_serialization(StakeStateV2::Stake(
-            Meta {
-                rent_exempt_reserve: 1,
-                authorized: Authorized {
-                    staker: Pubkey::new_unique(),
-                    withdrawer: Pubkey::new_unique(),
-                },
-                lockup: Lockup::default(),
-            },
-            Stake {
-                delegation: Delegation {
-                    voter_pubkey: Pubkey::new_unique(),
-                    stake: u64::MAX,
-                    activation_epoch: Epoch::MAX,
-                    deactivation_epoch: Epoch::MAX,
-                    ..Default::default()
-                },
-                credits_observed: 1,
-            },
-            StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED,
-        ));
-    }
-
-    #[cfg(feature = "borsh")]
-    #[test]
-    fn borsh_deserialization_live_data() {
-        let data = [
-            1, 0, 0, 0, 128, 213, 34, 0, 0, 0, 0, 0, 133, 0, 79, 231, 141, 29, 73, 61, 232, 35,
-            119, 124, 168, 12, 120, 216, 195, 29, 12, 166, 139, 28, 36, 182, 186, 154, 246, 149,
-            224, 109, 52, 100, 133, 0, 79, 231, 141, 29, 73, 61, 232, 35, 119, 124, 168, 12, 120,
-            216, 195, 29, 12, 166, 139, 28, 36, 182, 186, 154, 246, 149, 224, 109, 52, 100, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0,
-        ];
-        // As long as we get the 4-byte enum and the first field right, then
-        // we're sure the rest works out
-        let deserialized = try_from_slice_unchecked::<StakeStateV2>(&data).unwrap();
-        assert_matches!(
-            deserialized,
-            StakeStateV2::Initialized(Meta {
-                rent_exempt_reserve: 2282880,
-                ..
-            })
-        );
-    }
-
-    #[test]
-    fn stake_flag_member_offset() {
-        const FLAG_OFFSET: usize = 196;
-        let check_flag = |flag, expected| {
-            let stake = StakeStateV2::Stake(
-                Meta {
-                    rent_exempt_reserve: 1,
-                    authorized: Authorized {
-                        staker: Pubkey::new_unique(),
-                        withdrawer: Pubkey::new_unique(),
-                    },
-                    lockup: Lockup::default(),
-                },
-                Stake {
-                    delegation: Delegation {
-                        voter_pubkey: Pubkey::new_unique(),
-                        stake: u64::MAX,
-                        activation_epoch: Epoch::MAX,
-                        deactivation_epoch: Epoch::MAX,
-                        warmup_cooldown_rate: f64::MAX,
-                    },
-                    credits_observed: 1,
-                },
-                flag,
-            );
-
-            let bincode_serialized = serialize(&stake).unwrap();
-            let borsh_serialized = borsh::to_vec(&stake).unwrap();
-
-            assert_eq!(bincode_serialized[FLAG_OFFSET], expected);
-            assert_eq!(borsh_serialized[FLAG_OFFSET], expected);
-        };
-        #[allow(deprecated)]
-        check_flag(
-            StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED,
-            1,
-        );
-        check_flag(StakeFlags::empty(), 0);
-    }
-
-    mod deprecated {
-        use super::*;
-        #[cfg(feature = "borsh")]
-        fn check_borsh_deserialization(stake: StakeState) {
-            let serialized = serialize(&stake).unwrap();
-            let deserialized = StakeState::try_from_slice(&serialized).unwrap();
-            assert_eq!(stake, deserialized);
-        }
-
-        #[cfg(feature = "borsh")]
-        fn check_borsh_serialization(stake: StakeState) {
-            let bincode_serialized = serialize(&stake).unwrap();
-            let borsh_serialized = borsh::to_vec(&stake).unwrap();
-            assert_eq!(bincode_serialized, borsh_serialized);
-        }
-
-        #[test]
-        fn test_size_of() {
-            assert_eq!(StakeState::size_of(), std::mem::size_of::<StakeState>());
-        }
-
-        #[cfg(feature = "borsh")]
-        #[test]
-        fn bincode_vs_borsh_deserialization() {
-            check_borsh_deserialization(StakeState::Uninitialized);
-            check_borsh_deserialization(StakeState::RewardsPool);
-            check_borsh_deserialization(StakeState::Initialized(Meta {
-                rent_exempt_reserve: u64::MAX,
-                authorized: Authorized {
-                    staker: Pubkey::new_unique(),
-                    withdrawer: Pubkey::new_unique(),
-                },
-                lockup: Lockup::default(),
-            }));
-            check_borsh_deserialization(StakeState::Stake(
-                Meta {
-                    rent_exempt_reserve: 1,
-                    authorized: Authorized {
-                        staker: Pubkey::new_unique(),
-                        withdrawer: Pubkey::new_unique(),
-                    },
-                    lockup: Lockup::default(),
-                },
-                Stake {
-                    delegation: Delegation {
-                        voter_pubkey: Pubkey::new_unique(),
-                        stake: u64::MAX,
-                        activation_epoch: Epoch::MAX,
-                        deactivation_epoch: Epoch::MAX,
-                        warmup_cooldown_rate: f64::MAX,
-                    },
-                    credits_observed: 1,
-                },
-            ));
-        }
-
-        #[cfg(feature = "borsh")]
-        #[test]
-        fn bincode_vs_borsh_serialization() {
-            check_borsh_serialization(StakeState::Uninitialized);
-            check_borsh_serialization(StakeState::RewardsPool);
-            check_borsh_serialization(StakeState::Initialized(Meta {
-                rent_exempt_reserve: u64::MAX,
-                authorized: Authorized {
-                    staker: Pubkey::new_unique(),
-                    withdrawer: Pubkey::new_unique(),
-                },
-                lockup: Lockup::default(),
-            }));
-            check_borsh_serialization(StakeState::Stake(
-                Meta {
-                    rent_exempt_reserve: 1,
-                    authorized: Authorized {
-                        staker: Pubkey::new_unique(),
-                        withdrawer: Pubkey::new_unique(),
-                    },
-                    lockup: Lockup::default(),
-                },
-                Stake {
-                    delegation: Delegation {
-                        voter_pubkey: Pubkey::new_unique(),
-                        stake: u64::MAX,
-                        activation_epoch: Epoch::MAX,
-                        deactivation_epoch: Epoch::MAX,
-                        warmup_cooldown_rate: f64::MAX,
-                    },
-                    credits_observed: 1,
-                },
-            ));
-        }
-
-        #[cfg(feature = "borsh")]
-        #[test]
-        fn borsh_deserialization_live_data() {
-            let data = [
-                1, 0, 0, 0, 128, 213, 34, 0, 0, 0, 0, 0, 133, 0, 79, 231, 141, 29, 73, 61, 232, 35,
-                119, 124, 168, 12, 120, 216, 195, 29, 12, 166, 139, 28, 36, 182, 186, 154, 246,
-                149, 224, 109, 52, 100, 133, 0, 79, 231, 141, 29, 73, 61, 232, 35, 119, 124, 168,
-                12, 120, 216, 195, 29, 12, 166, 139, 28, 36, 182, 186, 154, 246, 149, 224, 109, 52,
-                100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            ];
-            // As long as we get the 4-byte enum and the first field right, then
-            // we're sure the rest works out
-            let deserialized = try_from_slice_unchecked::<StakeState>(&data).unwrap();
-            assert_matches!(
-                deserialized,
-                StakeState::Initialized(Meta {
-                    rent_exempt_reserve: 2282880,
-                    ..
-                })
-            );
-        }
-    }
-}

+ 0 - 155
sdk/program/src/stake/tools.rs

@@ -1,155 +0,0 @@
-//! Utility functions
-use {
-    crate::{program_error::ProgramError, stake::MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION},
-    solana_clock::Epoch,
-};
-
-/// Helper function for programs to call [`GetMinimumDelegation`] and then fetch the return data
-///
-/// This fn handles performing the CPI to call the [`GetMinimumDelegation`] function, and then
-/// calls [`get_return_data()`] to fetch the return data.
-///
-/// [`GetMinimumDelegation`]: super::instruction::StakeInstruction::GetMinimumDelegation
-/// [`get_return_data()`]: crate::program::get_return_data
-pub fn get_minimum_delegation() -> Result<u64, ProgramError> {
-    let instruction = super::instruction::get_minimum_delegation();
-    crate::program::invoke_unchecked(&instruction, &[])?;
-    get_minimum_delegation_return_data()
-}
-
-/// Helper function for programs to get the return data after calling [`GetMinimumDelegation`]
-///
-/// This fn handles calling [`get_return_data()`], ensures the result is from the correct
-/// program, and returns the correct type.
-///
-/// [`GetMinimumDelegation`]: super::instruction::StakeInstruction::GetMinimumDelegation
-/// [`get_return_data()`]: crate::program::get_return_data
-fn get_minimum_delegation_return_data() -> Result<u64, ProgramError> {
-    crate::program::get_return_data()
-        .ok_or(ProgramError::InvalidInstructionData)
-        .and_then(|(program_id, return_data)| {
-            (program_id == super::program::id())
-                .then_some(return_data)
-                .ok_or(ProgramError::IncorrectProgramId)
-        })
-        .and_then(|return_data| {
-            return_data
-                .try_into()
-                .or(Err(ProgramError::InvalidInstructionData))
-        })
-        .map(u64::from_le_bytes)
-}
-
-// Check if the provided `epoch_credits` demonstrate active voting over the previous
-// `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION`
-pub fn acceptable_reference_epoch_credits(
-    epoch_credits: &[(Epoch, u64, u64)],
-    current_epoch: Epoch,
-) -> bool {
-    if let Some(epoch_index) = epoch_credits
-        .len()
-        .checked_sub(MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION)
-    {
-        let mut epoch = current_epoch;
-        for (vote_epoch, ..) in epoch_credits[epoch_index..].iter().rev() {
-            if *vote_epoch != epoch {
-                return false;
-            }
-            epoch = epoch.saturating_sub(1);
-        }
-        true
-    } else {
-        false
-    }
-}
-
-// Check if the provided `epoch_credits` demonstrate delinquency over the previous
-// `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION`
-pub fn eligible_for_deactivate_delinquent(
-    epoch_credits: &[(Epoch, u64, u64)],
-    current_epoch: Epoch,
-) -> bool {
-    match epoch_credits.last() {
-        None => true,
-        Some((epoch, ..)) => {
-            if let Some(minimum_epoch) =
-                current_epoch.checked_sub(MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch)
-            {
-                *epoch <= minimum_epoch
-            } else {
-                false
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_acceptable_reference_epoch_credits() {
-        let epoch_credits = [];
-        assert!(!acceptable_reference_epoch_credits(&epoch_credits, 0));
-
-        let epoch_credits = [(0, 42, 42), (1, 42, 42), (2, 42, 42), (3, 42, 42)];
-        assert!(!acceptable_reference_epoch_credits(&epoch_credits, 3));
-
-        let epoch_credits = [
-            (0, 42, 42),
-            (1, 42, 42),
-            (2, 42, 42),
-            (3, 42, 42),
-            (4, 42, 42),
-        ];
-        assert!(!acceptable_reference_epoch_credits(&epoch_credits, 3));
-        assert!(acceptable_reference_epoch_credits(&epoch_credits, 4));
-
-        let epoch_credits = [
-            (1, 42, 42),
-            (2, 42, 42),
-            (3, 42, 42),
-            (4, 42, 42),
-            (5, 42, 42),
-        ];
-        assert!(acceptable_reference_epoch_credits(&epoch_credits, 5));
-
-        let epoch_credits = [
-            (0, 42, 42),
-            (2, 42, 42),
-            (3, 42, 42),
-            (4, 42, 42),
-            (5, 42, 42),
-        ];
-        assert!(!acceptable_reference_epoch_credits(&epoch_credits, 5));
-    }
-
-    #[test]
-    fn test_eligible_for_deactivate_delinquent() {
-        let epoch_credits = [];
-        assert!(eligible_for_deactivate_delinquent(&epoch_credits, 42));
-
-        let epoch_credits = [(0, 42, 42)];
-        assert!(!eligible_for_deactivate_delinquent(&epoch_credits, 0));
-
-        let epoch_credits = [(0, 42, 42)];
-        assert!(!eligible_for_deactivate_delinquent(
-            &epoch_credits,
-            MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch - 1
-        ));
-        assert!(eligible_for_deactivate_delinquent(
-            &epoch_credits,
-            MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch
-        ));
-
-        let epoch_credits = [(100, 42, 42)];
-        assert!(!eligible_for_deactivate_delinquent(
-            &epoch_credits,
-            100 + MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch - 1
-        ));
-        assert!(eligible_for_deactivate_delinquent(
-            &epoch_credits,
-            100 + MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION as Epoch
-        ));
-    }
-}

+ 8 - 2
sdk/sysvar/Cargo.toml

@@ -36,6 +36,7 @@ solana-sdk-ids = { workspace = true }
 solana-sdk-macro = { workspace = true }
 solana-slot-hashes = { workspace = true, features = ["sysvar"] }
 solana-slot-history = { workspace = true, features = ["sysvar"] }
+solana-stake-interface = { workspace = true }
 solana-sysvar-id = { workspace = true }
 
 [target.'cfg(not(target_os = "solana"))'.dependencies]
@@ -56,10 +57,14 @@ solana-sysvar = { path = ".", features = ["dev-context-only-utils"] }
 test-case = { workspace = true }
 
 [features]
-bincode = ["dep:bincode", "serde"]
+bincode = ["dep:bincode", "serde", "solana-stake-interface/bincode"]
 bytemuck = ["dep:bytemuck", "dep:bytemuck_derive"]
 dev-context-only-utils = ["bincode", "bytemuck", "solana-instructions-sysvar/dev-context-only-utils"]
-frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"]
+frozen-abi = [
+    "dep:solana-frozen-abi",
+    "dep:solana-frozen-abi-macro",
+    "solana-stake-interface/frozen-abi"
+]
 serde = [
     "dep:serde",
     "dep:serde_derive",
@@ -71,6 +76,7 @@ serde = [
     "solana-rent/serde",
     "solana-slot-hashes/serde",
     "solana-slot-history/serde",
+    "solana-stake-interface/serde",
 ]
 
 [package.metadata.docs.rs]

+ 8 - 127
sdk/sysvar/src/stake_history.rs

@@ -48,109 +48,15 @@
 
 #[cfg(feature = "bincode")]
 use crate::Sysvar;
-#[cfg(feature = "serde")]
-use serde_derive::{Deserialize, Serialize};
 pub use solana_sdk_ids::sysvar::stake_history::{check_id, id, ID};
-use {
-    crate::get_sysvar,
-    solana_clock::Epoch,
-    solana_sysvar_id::{impl_sysvar_id, SysvarId},
-    std::ops::Deref,
+#[deprecated(
+    since = "2.2.0",
+    note = "Use solana_stake_interface::stake_history instead"
+)]
+pub use solana_stake_interface::stake_history::{
+    StakeHistory, StakeHistoryEntry, StakeHistoryGetEntry, MAX_ENTRIES,
 };
-
-pub const MAX_ENTRIES: usize = 512; // it should never take as many as 512 epochs to warm up or cool down
-
-#[repr(C)]
-#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
-#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
-#[derive(Debug, PartialEq, Eq, Default, Clone)]
-pub struct StakeHistoryEntry {
-    pub effective: u64,    // effective stake at this epoch
-    pub activating: u64,   // sum of portion of stakes not fully warmed up
-    pub deactivating: u64, // requested to be cooled down, not fully deactivated yet
-}
-
-impl StakeHistoryEntry {
-    pub fn with_effective(effective: u64) -> Self {
-        Self {
-            effective,
-            ..Self::default()
-        }
-    }
-
-    pub fn with_effective_and_activating(effective: u64, activating: u64) -> Self {
-        Self {
-            effective,
-            activating,
-            ..Self::default()
-        }
-    }
-
-    pub fn with_deactivating(deactivating: u64) -> Self {
-        Self {
-            effective: deactivating,
-            deactivating,
-            ..Self::default()
-        }
-    }
-}
-
-impl std::ops::Add for StakeHistoryEntry {
-    type Output = StakeHistoryEntry;
-    fn add(self, rhs: StakeHistoryEntry) -> Self::Output {
-        Self {
-            effective: self.effective.saturating_add(rhs.effective),
-            activating: self.activating.saturating_add(rhs.activating),
-            deactivating: self.deactivating.saturating_add(rhs.deactivating),
-        }
-    }
-}
-
-/// A type to hold data for the [`StakeHistory` sysvar][sv].
-///
-/// [sv]: https://docs.solanalabs.com/runtime/sysvars#stakehistory
-#[repr(C)]
-#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
-#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
-#[derive(Debug, PartialEq, Eq, Default, Clone)]
-pub struct StakeHistory(Vec<(Epoch, StakeHistoryEntry)>);
-
-impl StakeHistory {
-    pub fn get(&self, epoch: Epoch) -> Option<&StakeHistoryEntry> {
-        self.binary_search_by(|probe| epoch.cmp(&probe.0))
-            .ok()
-            .map(|index| &self[index].1)
-    }
-
-    pub fn add(&mut self, epoch: Epoch, entry: StakeHistoryEntry) {
-        match self.binary_search_by(|probe| epoch.cmp(&probe.0)) {
-            Ok(index) => (self.0)[index] = (epoch, entry),
-            Err(index) => (self.0).insert(index, (epoch, entry)),
-        }
-        (self.0).truncate(MAX_ENTRIES);
-    }
-}
-
-impl Deref for StakeHistory {
-    type Target = Vec<(Epoch, StakeHistoryEntry)>;
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-pub trait StakeHistoryGetEntry {
-    fn get_entry(&self, epoch: Epoch) -> Option<StakeHistoryEntry>;
-}
-
-impl StakeHistoryGetEntry for StakeHistory {
-    fn get_entry(&self, epoch: Epoch) -> Option<StakeHistoryEntry> {
-        self.binary_search_by(|probe| epoch.cmp(&probe.0))
-            .ok()
-            .map(|index| self[index].1.clone())
-    }
-}
-
-impl_sysvar_id!(StakeHistory);
+use {crate::get_sysvar, solana_clock::Epoch};
 
 #[cfg(feature = "bincode")]
 impl Sysvar for StakeHistory {
@@ -193,7 +99,7 @@ impl StakeHistoryGetEntry for StakeHistorySysvar {
         let mut entry_buf = [0; EPOCH_AND_ENTRY_SERIALIZED_SIZE as usize];
         let result = get_sysvar(
             &mut entry_buf,
-            &StakeHistory::id(),
+            &id(),
             offset,
             EPOCH_AND_ENTRY_SERIALIZED_SIZE,
         );
@@ -224,31 +130,6 @@ impl StakeHistoryGetEntry for StakeHistorySysvar {
 mod tests {
     use {super::*, crate::tests::mock_get_sysvar_syscall, serial_test::serial};
 
-    #[test]
-    fn test_stake_history() {
-        let mut stake_history = StakeHistory::default();
-
-        for i in 0..MAX_ENTRIES as u64 + 1 {
-            stake_history.add(
-                i,
-                StakeHistoryEntry {
-                    activating: i,
-                    ..StakeHistoryEntry::default()
-                },
-            );
-        }
-        assert_eq!(stake_history.len(), MAX_ENTRIES);
-        assert_eq!(stake_history.iter().map(|entry| entry.0).min().unwrap(), 1);
-        assert_eq!(stake_history.get(0), None);
-        assert_eq!(
-            stake_history.get(1),
-            Some(&StakeHistoryEntry {
-                activating: 1,
-                ..StakeHistoryEntry::default()
-            })
-        );
-    }
-
     #[test]
     fn test_size_of() {
         let mut stake_history = StakeHistory::default();

+ 23 - 0
svm/examples/Cargo.lock

@@ -6524,6 +6524,7 @@ dependencies = [
  "solana-slot-hashes",
  "solana-slot-history",
  "solana-stable-layout",
+ "solana-stake-interface",
  "solana-system-interface",
  "solana-sysvar",
  "solana-sysvar-id",
@@ -7342,6 +7343,27 @@ dependencies = [
  "solana-pubkey",
 ]
 
+[[package]]
+name = "solana-stake-interface"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c"
+dependencies = [
+ "borsh 0.10.4",
+ "borsh 1.5.5",
+ "num-traits",
+ "serde",
+ "serde_derive",
+ "solana-clock",
+ "solana-cpi",
+ "solana-decode-error",
+ "solana-instruction",
+ "solana-program-error",
+ "solana-pubkey",
+ "solana-system-interface",
+ "solana-sysvar-id",
+]
+
 [[package]]
 name = "solana-stake-program"
 version = "2.2.0"
@@ -7641,6 +7663,7 @@ dependencies = [
  "solana-sdk-macro",
  "solana-slot-hashes",
  "solana-slot-history",
+ "solana-stake-interface",
  "solana-sysvar-id",
 ]
 

+ 2 - 0
svm/examples/Cargo.toml

@@ -55,6 +55,7 @@ crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d
 solana-curve25519 = { path = "../../curves/curve25519" }
 solana-account-info = { path = "../../sdk/account-info" }
 solana-borsh = { path = "../../sdk/borsh" }
+solana-clock = { path = "../../sdk/clock" }
 solana-cpi = { path = "../../sdk/cpi" }
 solana-decode-error = { path = "../../sdk/decode-error" }
 solana-hash = { path = "../../sdk/hash" }
@@ -67,4 +68,5 @@ solana-program-option = { path = "../../sdk/program-option" }
 solana-program-pack = { path = "../../sdk/program-pack" }
 solana-pubkey = { path = "../../sdk/pubkey" }
 solana-sha256-hasher = { path = "../../sdk/sha256-hasher" }
+solana-sysvar-id = { path = "../../sdk/sysvar-id" }
 solana-zk-sdk = { path = "../../zk-sdk" }