From 4c6891471bf2a76dfe3b9ca5b5f99f93e9db370d Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 11 Jun 2021 23:45:35 +0200 Subject: [PATCH 01/14] Move stake state / instructions into solana_program --- programs/config/src/lib.rs | 8 + programs/stake/src/config.rs | 69 +- programs/stake/src/lib.rs | 3 - programs/stake/src/stake_instruction.rs | 575 ++-------------- programs/stake/src/stake_state.rs | 874 ++++++------------------ sdk/program/src/lib.rs | 1 + sdk/program/src/stake/config.rs | 28 + sdk/program/src/stake/instruction.rs | 507 ++++++++++++++ sdk/program/src/stake/mod.rs | 5 + sdk/program/src/stake/state.rs | 532 +++++++++++++++ 10 files changed, 1360 insertions(+), 1242 deletions(-) create mode 100644 sdk/program/src/stake/config.rs create mode 100644 sdk/program/src/stake/instruction.rs create mode 100644 sdk/program/src/stake/mod.rs create mode 100644 sdk/program/src/stake/state.rs diff --git a/programs/config/src/lib.rs b/programs/config/src/lib.rs index e170ef7659ad98..e18b8e24ed52a9 100644 --- a/programs/config/src/lib.rs +++ b/programs/config/src/lib.rs @@ -9,6 +9,7 @@ use solana_sdk::{ account::{Account, AccountSharedData}, pubkey::Pubkey, short_vec, + stake::config::Config as StakeConfig, }; solana_sdk::declare_id!("Config1111111111111111111111111111111111111"); @@ -18,6 +19,13 @@ pub trait ConfigState: serde::Serialize + Default { fn max_space() -> u64; } +// TODO move ConfigState into `solana_program` to implement trait locally +impl ConfigState for StakeConfig { + fn max_space() -> u64 { + serialized_size(&StakeConfig::default()).unwrap() + } +} + /// A collection of keys to be stored in Config account data. #[derive(Debug, Default, Deserialize, Serialize)] pub struct ConfigKeys { diff --git a/programs/stake/src/config.rs b/programs/stake/src/config.rs index ee968d40c4644a..3eee1f6a106d5f 100644 --- a/programs/stake/src/config.rs +++ b/programs/stake/src/config.rs @@ -1,51 +1,32 @@ //! config for staking //! carries variables that the stake program cares about -use bincode::{deserialize, serialized_size}; -use serde_derive::{Deserialize, Serialize}; -use solana_config_program::{create_config_account, get_config_data, ConfigState}; +use bincode::deserialize; +use solana_config_program::{create_config_account, get_config_data}; use solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, genesis_config::GenesisConfig, instruction::InstructionError, keyed_account::KeyedAccount, + stake::config::{self, Config}, }; -// stake config ID -solana_sdk::declare_id!("StakeConfig11111111111111111111111111111111"); - -// 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 DEFAULT_SLASH_PENALTY: u8 = ((5 * std::u8::MAX as usize) / 100) as u8; - -#[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 std::u8::MAX - pub slash_penalty: u8, -} - -impl Config { - pub fn from(account: &T) -> Option { +pub struct ConfigConverter; +impl ConfigConverter { + pub fn from(account: &T) -> Option { get_config_data(&account.data()) .ok() .and_then(|data| deserialize(data).ok()) } -} -impl Default for Config { - fn default() -> Self { - Self { - warmup_cooldown_rate: DEFAULT_WARMUP_COOLDOWN_RATE, - slash_penalty: DEFAULT_SLASH_PENALTY, + pub fn from_keyed_account(account: &KeyedAccount) -> Result { + if !config::check_id(account.unsigned_key()) { + return Err(InstructionError::InvalidArgument); } + ConfigConverter::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument) } -} -impl ConfigState for Config { - fn max_space() -> u64 { - serialized_size(&Config::default()).unwrap() + pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData { + create_config_account(vec![], config, lamports) } } @@ -55,22 +36,11 @@ pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 { account.set_lamports(lamports.max(1)); - genesis_config.add_account(id(), account); + genesis_config.add_account(config::id(), account); lamports } -pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData { - create_config_account(vec![], config, lamports) -} - -pub fn from_keyed_account(account: &KeyedAccount) -> Result { - if !check_id(account.unsigned_key()) { - return Err(InstructionError::InvalidArgument); - } - Config::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument) -} - #[cfg(test)] mod tests { use super::*; @@ -79,10 +49,17 @@ mod tests { #[test] fn test() { - let account = RefCell::new(create_account(0, &Config::default())); - assert_eq!(Config::from(&account.borrow()), Some(Config::default())); + let account = RefCell::new(ConfigConverter::create_account(0, &Config::default())); + assert_eq!( + ConfigConverter::from(&account.borrow()), + Some(Config::default()) + ); assert_eq!( - from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)), + ConfigConverter::from_keyed_account(&KeyedAccount::new( + &Pubkey::default(), + false, + &account + )), Err(InstructionError::InvalidArgument) ); } diff --git a/programs/stake/src/lib.rs b/programs/stake/src/lib.rs index f93ed516563f36..8362d55f966cd1 100644 --- a/programs/stake/src/lib.rs +++ b/programs/stake/src/lib.rs @@ -11,6 +11,3 @@ solana_sdk::declare_id!("Stake11111111111111111111111111111111111111"); pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 { config::add_genesis_account(genesis_config) } - -#[macro_use] -extern crate solana_frozen_abi_macro; diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index e89be82e7ab69a..4aa7994a794b74 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -1,481 +1,17 @@ -use crate::{ - config, id, - stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState}, +use { + crate::{config::ConfigConverter, stake_state::StakeAccount}, + log::*, + solana_sdk::{ + feature_set, + instruction::InstructionError, + keyed_account::{from_keyed_account, get_signers, keyed_account_at_index}, + process_instruction::{get_sysvar, InvokeContext}, + program_utils::limited_deserialize, + pubkey::Pubkey, + stake::{id, instruction::StakeInstruction}, + sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory}, + }, }; -use log::*; -use num_derive::{FromPrimitive, ToPrimitive}; -use serde_derive::{Deserialize, Serialize}; -use solana_sdk::{ - clock::{Epoch, UnixTimestamp}, - decode_error::DecodeError, - feature_set, - instruction::{AccountMeta, Instruction, InstructionError}, - keyed_account::{from_keyed_account, get_signers, keyed_account_at_index}, - process_instruction::{get_sysvar, InvokeContext}, - program_utils::limited_deserialize, - pubkey::Pubkey, - system_instruction, - sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory}, -}; -use thiserror::Error; - -/// Reasons the stake might have had an error -#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] -pub enum StakeError { - #[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, - - #[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, -} - -impl DecodeError for StakeError { - fn type_of() -> &'static str { - "StakeError" - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, 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. [] Address of config account that carries 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), -} - -#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy)] -pub struct LockupArgs { - pub unix_timestamp: Option, - pub epoch: Option, - pub custodian: Option, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] -pub struct AuthorizeWithSeedArgs { - pub new_authorized_pubkey: Pubkey, - 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 create_account_with_seed( - from_pubkey: &Pubkey, - stake_pubkey: &Pubkey, - base: &Pubkey, - seed: &str, - authorized: &Authorized, - lockup: &Lockup, - lamports: u64, -) -> Vec { - vec![ - system_instruction::create_account_with_seed( - from_pubkey, - stake_pubkey, - base, - seed, - lamports, - std::mem::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 { - vec![ - system_instruction::create_account( - from_pubkey, - stake_pubkey, - lamports, - std::mem::size_of::() as u64, - &id(), - ), - initialize(stake_pubkey, authorized, lockup), - ] -} - -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 { - vec![ - system_instruction::allocate(split_stake_pubkey, std::mem::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 { - vec![ - system_instruction::allocate_with_seed( - split_stake_pubkey, - base, - seed, - std::mem::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 { - 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 { - 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 { - 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_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 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), - AccountMeta::new_readonly(crate::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 process_instruction( _program_id: &Pubkey, @@ -580,7 +116,7 @@ pub fn process_instruction( &vote, &from_keyed_account::(keyed_account_at_index(keyed_accounts, 2)?)?, &from_keyed_account::(keyed_account_at_index(keyed_accounts, 3)?)?, - &config::from_keyed_account(keyed_account_at_index(keyed_accounts, 4)?)?, + &ConfigConverter::from_keyed_account(keyed_account_at_index(keyed_accounts, 4)?)?, &signers, can_reverse_deactivation, ) @@ -634,12 +170,19 @@ pub fn process_instruction( #[cfg(test)] mod tests { use super::*; + use crate::config::ConfigConverter; use bincode::serialize; use solana_sdk::{ account::{self, Account, AccountSharedData, WritableAccount}, + instruction::Instruction, keyed_account::KeyedAccount, process_instruction::{mock_set_sysvar, MockInvokeContext}, rent::Rent, + stake::{ + config, + instruction::{self, LockupArgs}, + state::{Authorized, Lockup, StakeAuthorize}, + }, sysvar::stake_history::StakeHistory, }; use std::cell::RefCell; @@ -686,7 +229,7 @@ mod tests { } else if sysvar::stake_history::check_id(&meta.pubkey) { account::create_account_shared_data_for_test(&StakeHistory::default()) } else if config::check_id(&meta.pubkey) { - config::create_account(0, &config::Config::default()) + ConfigConverter::create_account(0, &config::Config::default()) } else if sysvar::rent::check_id(&meta.pubkey) { account::create_account_shared_data_for_test(&Rent::default()) } else if meta.pubkey == invalid_stake_state_pubkey() { @@ -735,7 +278,7 @@ mod tests { #[test] fn test_stake_process_instruction() { assert_eq!( - process_instruction(&initialize( + process_instruction(&instruction::initialize( &Pubkey::default(), &Authorized::default(), &Lockup::default() @@ -743,7 +286,7 @@ mod tests { Err(InstructionError::InvalidAccountData), ); assert_eq!( - process_instruction(&authorize( + process_instruction(&instruction::authorize( &Pubkey::default(), &Pubkey::default(), &Pubkey::default(), @@ -754,7 +297,7 @@ mod tests { ); assert_eq!( process_instruction( - &split( + &instruction::split( &Pubkey::default(), &Pubkey::default(), 100, @@ -765,7 +308,7 @@ mod tests { ); assert_eq!( process_instruction( - &merge( + &instruction::merge( &Pubkey::default(), &invalid_stake_state_pubkey(), &Pubkey::default(), @@ -775,7 +318,7 @@ mod tests { ); assert_eq!( process_instruction( - &split_with_seed( + &instruction::split_with_seed( &Pubkey::default(), &Pubkey::default(), 100, @@ -787,7 +330,7 @@ mod tests { Err(InstructionError::InvalidAccountData), ); assert_eq!( - process_instruction(&delegate_stake( + process_instruction(&instruction::delegate_stake( &Pubkey::default(), &Pubkey::default(), &invalid_vote_state_pubkey(), @@ -795,7 +338,7 @@ mod tests { Err(InstructionError::InvalidAccountData), ); assert_eq!( - process_instruction(&withdraw( + process_instruction(&instruction::withdraw( &Pubkey::default(), &Pubkey::default(), &solana_sdk::pubkey::new_rand(), @@ -805,11 +348,14 @@ mod tests { Err(InstructionError::InvalidAccountData), ); assert_eq!( - process_instruction(&deactivate_stake(&Pubkey::default(), &Pubkey::default())), + process_instruction(&instruction::deactivate_stake( + &Pubkey::default(), + &Pubkey::default() + )), Err(InstructionError::InvalidAccountData), ); assert_eq!( - process_instruction(&set_lockup( + process_instruction(&instruction::set_lockup( &Pubkey::default(), &LockupArgs::default(), &Pubkey::default() @@ -821,7 +367,7 @@ mod tests { #[test] fn test_spoofed_stake_accounts() { assert_eq!( - process_instruction(&initialize( + process_instruction(&instruction::initialize( &spoofed_stake_state_pubkey(), &Authorized::default(), &Lockup::default() @@ -829,7 +375,7 @@ mod tests { Err(InstructionError::InvalidAccountOwner), ); assert_eq!( - process_instruction(&authorize( + process_instruction(&instruction::authorize( &spoofed_stake_state_pubkey(), &Pubkey::default(), &Pubkey::default(), @@ -840,7 +386,7 @@ mod tests { ); assert_eq!( process_instruction( - &split( + &instruction::split( &spoofed_stake_state_pubkey(), &Pubkey::default(), 100, @@ -851,7 +397,7 @@ mod tests { ); assert_eq!( process_instruction( - &split( + &instruction::split( &Pubkey::default(), &Pubkey::default(), 100, @@ -862,7 +408,7 @@ mod tests { ); assert_eq!( process_instruction( - &merge( + &instruction::merge( &spoofed_stake_state_pubkey(), &Pubkey::default(), &Pubkey::default(), @@ -872,7 +418,7 @@ mod tests { ); assert_eq!( process_instruction( - &merge( + &instruction::merge( &Pubkey::default(), &spoofed_stake_state_pubkey(), &Pubkey::default(), @@ -882,7 +428,7 @@ mod tests { ); assert_eq!( process_instruction( - &split_with_seed( + &instruction::split_with_seed( &spoofed_stake_state_pubkey(), &Pubkey::default(), 100, @@ -894,7 +440,7 @@ mod tests { Err(InstructionError::InvalidAccountOwner), ); assert_eq!( - process_instruction(&delegate_stake( + process_instruction(&instruction::delegate_stake( &spoofed_stake_state_pubkey(), &Pubkey::default(), &Pubkey::default(), @@ -902,7 +448,7 @@ mod tests { Err(InstructionError::InvalidAccountOwner), ); assert_eq!( - process_instruction(&withdraw( + process_instruction(&instruction::withdraw( &spoofed_stake_state_pubkey(), &Pubkey::default(), &solana_sdk::pubkey::new_rand(), @@ -912,14 +458,14 @@ mod tests { Err(InstructionError::InvalidAccountOwner), ); assert_eq!( - process_instruction(&deactivate_stake( + process_instruction(&instruction::deactivate_stake( &spoofed_stake_state_pubkey(), &Pubkey::default() )), Err(InstructionError::InvalidAccountOwner), ); assert_eq!( - process_instruction(&set_lockup( + process_instruction(&instruction::set_lockup( &spoofed_stake_state_pubkey(), &LockupArgs::default(), &Pubkey::default() @@ -1052,7 +598,10 @@ mod tests { &sysvar::stake_history::StakeHistory::default(), )); let config_address = config::id(); - let config_account = RefCell::new(config::create_account(0, &config::Config::default())); + let config_account = RefCell::new(ConfigConverter::create_account( + 0, + &config::Config::default(), + )); let keyed_accounts = vec![ KeyedAccount::new(&stake_address, true, &stake_account), KeyedAccount::new(&vote_address, false, &bad_vote_account), @@ -1140,30 +689,4 @@ mod tests { Err(InstructionError::NotEnoughAccountKeys), ); } - - #[test] - fn test_custom_error_decode() { - use num_traits::FromPrimitive; - fn pretty_err(err: InstructionError) -> String - where - T: 'static + std::error::Error + DecodeError + 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::NoCreditsToRedeem.into()) - ) - } } diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index 5e9e41a27e1cf5..9c7721a1d0aa10 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -3,35 +3,28 @@ //! * keep track of rewards //! * own mining pools -use crate::{ - config::Config, - id, - stake_instruction::{LockupArgs, StakeError}, -}; -use serde_derive::{Deserialize, Serialize}; -use solana_sdk::{ - account::{AccountSharedData, ReadableAccount, WritableAccount}, - account_utils::{State, StateMut}, - clock::{Clock, Epoch, UnixTimestamp}, - ic_msg, - instruction::{checked_add, InstructionError}, - keyed_account::KeyedAccount, - process_instruction::InvokeContext, - pubkey::Pubkey, - rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, - stake_history::{StakeHistory, StakeHistoryEntry}, +use { + solana_sdk::{ + account::{AccountSharedData, ReadableAccount, WritableAccount}, + account_utils::{State, StateMut}, + clock::{Clock, Epoch}, + ic_msg, + instruction::{checked_add, InstructionError}, + keyed_account::KeyedAccount, + process_instruction::InvokeContext, + pubkey::Pubkey, + rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, + stake::{ + config::Config, + id, + instruction::{LockupArgs, StakeError}, + state::{Authorized, Delegation, Lockup, Meta, Stake, StakeAuthorize, StakeState}, + }, + stake_history::{StakeHistory, StakeHistoryEntry}, + }, + solana_vote_program::vote_state::{VoteState, VoteStateVersions}, + std::{collections::HashSet, convert::TryFrom}, }; -use solana_vote_program::vote_state::{VoteState, VoteStateVersions}; -use std::{collections::HashSet, convert::TryFrom}; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -#[allow(clippy::large_enum_variant)] -pub enum StakeState { - Uninitialized, - Initialized(Meta), - Stake(Meta, Stake), - RewardsPool, -} #[derive(Debug)] pub enum SkippedReason { @@ -64,489 +57,90 @@ pub(crate) fn null_tracer() -> Option } -impl Default for StakeState { - fn default() -> Self { - StakeState::Uninitialized - } -} - -impl StakeState { - pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 { - rent.minimum_balance(std::mem::size_of::()) - } - +pub struct StakeConverter; +impl StakeConverter { // utility function, used by Stakes, tests pub fn from>(account: &T) -> Option { account.state().ok() } pub fn stake_from>(account: &T) -> Option { - Self::from(account).and_then(|state: Self| state.stake()) - } - pub fn stake(&self) -> Option { - match self { - StakeState::Stake(_meta, stake) => Some(*stake), - _ => None, - } + Self::from(account).and_then(|state: StakeState| state.stake()) } pub fn delegation_from(account: &AccountSharedData) -> Option { - Self::from(account).and_then(|state: Self| state.delegation()) - } - pub fn delegation(&self) -> Option { - match self { - StakeState::Stake(_meta, stake) => Some(stake.delegation), - _ => None, - } + Self::from(account).and_then(|state: StakeState| state.delegation()) } pub fn authorized_from(account: &AccountSharedData) -> Option { - Self::from(account).and_then(|state: Self| state.authorized()) - } - - pub fn authorized(&self) -> Option { - match self { - StakeState::Stake(meta, _stake) => Some(meta.authorized), - StakeState::Initialized(meta) => Some(meta.authorized), - _ => None, - } + Self::from(account).and_then(|state: StakeState| state.authorized()) } pub fn lockup_from>(account: &T) -> Option { - Self::from(account).and_then(|state: Self| state.lockup()) - } - - pub fn lockup(&self) -> Option { - self.meta().map(|meta| meta.lockup) + Self::from(account).and_then(|state: StakeState| state.lockup()) } pub fn meta_from(account: &AccountSharedData) -> Option { - Self::from(account).and_then(|state: Self| state.meta()) - } - - pub fn meta(&self) -> Option { - match self { - StakeState::Stake(meta, _stake) => Some(*meta), - StakeState::Initialized(meta) => Some(*meta), - _ => None, - } - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -pub enum StakeAuthorize { - Staker, - Withdrawer, -} - -#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -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 + Self::from(account).and_then(|state: StakeState| state.meta()) } -} - -#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -pub struct Authorized { - pub staker: Pubkey, - pub withdrawer: Pubkey, -} - -#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -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, - clock: Option<&Clock>, - ) -> Result<(), InstructionError> { - match clock { - None => { - // pre-stake_program_v4 behavior: custodian can set lockups at any time - if !signers.contains(&self.lockup.custodian) { - return Err(InstructionError::MissingRequiredSignature); - } - } - Some(clock) => { - // 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); - } + // TODO move VoteState into solana_program to move this function into Stake + fn redelegate( + stake: &mut Stake, + stake_lamports: u64, + voter_pubkey: &Pubkey, + vote_state: &VoteState, + clock: &Clock, + stake_history: &StakeHistory, + config: &Config, + can_reverse_deactivation: bool, + ) -> Result<(), StakeError> { + // If stake is currently active: + if stake.stake(clock.epoch, Some(stake_history), true) != 0 { + // If pubkey of new voter is the same as current, + // and we are scheduled to start deactivating this epoch, + // we rescind deactivation + if stake.delegation.voter_pubkey == *voter_pubkey + && clock.epoch == stake.delegation.deactivation_epoch + && can_reverse_deactivation + { + stake.delegation.deactivation_epoch = std::u64::MAX; + return Ok(()); + } else { + // can't redelegate to another pubkey if stake is active. + return Err(StakeError::TooSoonToRedelegate); } } - 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 rewrite_rent_exempt_reserve( - &mut self, - rent: &Rent, - data_len: usize, - ) -> Option<(u64, u64)> { - let corrected_rent_exempt_reserve = rent.minimum_balance(data_len); - if corrected_rent_exempt_reserve != self.rent_exempt_reserve { - // We forcibly update rent_excempt_reserve even - // if rent_exempt_reserve > account_balance, hoping user might restore - // rent_exempt status by depositing. - let (old, new) = (self.rent_exempt_reserve, corrected_rent_exempt_reserve); - self.rent_exempt_reserve = corrected_rent_exempt_reserve; - Some((old, new)) - } else { - None - } - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -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 - pub warmup_cooldown_rate: f64, -} + // Either the stake is freshly activated, is active but has been + // deactivated this epoch, or has fully de-activated. + // Redelegation implies either re-activation or un-deactivation -impl Default for Delegation { - fn default() -> Self { - Self { - voter_pubkey: Pubkey::default(), - stake: 0, - activation_epoch: 0, - deactivation_epoch: std::u64::MAX, - warmup_cooldown_rate: Config::default().warmup_cooldown_rate, - } + stake.delegation.stake = stake_lamports; + stake.delegation.activation_epoch = clock.epoch; + stake.delegation.deactivation_epoch = std::u64::MAX; + stake.delegation.voter_pubkey = *voter_pubkey; + stake.delegation.warmup_cooldown_rate = config.warmup_cooldown_rate; + stake.credits_observed = vote_state.credits(); + Ok(()) } -} -impl Delegation { - pub fn new( - voter_pubkey: &Pubkey, + // TODO move VoteState into solana_program to move this function into Stake + fn new_stake( stake: u64, + voter_pubkey: &Pubkey, + vote_state: &VoteState, activation_epoch: Epoch, - warmup_cooldown_rate: f64, - ) -> Self { - Self { - voter_pubkey: *voter_pubkey, - stake, - activation_epoch, - warmup_cooldown_rate, - ..Delegation::default() - } - } - pub fn is_bootstrap(&self) -> bool { - self.activation_epoch == std::u64::MAX - } - - pub fn stake( - &self, - epoch: Epoch, - history: Option<&StakeHistory>, - fix_stake_deactivate: bool, - ) -> u64 { - self.stake_activating_and_deactivating(epoch, history, fix_stake_deactivate) - .0 - } - - // returned tuple is (effective, activating, deactivating) stake - #[allow(clippy::comparison_chain)] - pub fn stake_activating_and_deactivating( - &self, - target_epoch: Epoch, - history: Option<&StakeHistory>, - fix_stake_deactivate: bool, - ) -> (u64, u64, u64) { - let delegated_stake = self.stake; - - // first, calculate an effective and activating stake - let (effective_stake, activating_stake) = - self.stake_and_activating(target_epoch, history, fix_stake_deactivate); - - // then de-activate some portion if necessary - if target_epoch < self.deactivation_epoch { - // not deactivated - (effective_stake, activating_stake, 0) - } else if target_epoch == self.deactivation_epoch { - // can only deactivate what's activated - (effective_stake, 0, effective_stake.min(delegated_stake)) - } else if let Some((history, mut prev_epoch, mut prev_cluster_stake)) = - history.and_then(|history| { - history - .get(&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; - - // 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 * self.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(¤t_epoch) { - prev_epoch = current_epoch; - prev_cluster_stake = current_cluster_stake; - } else { - break; - } - } - - // deactivating stake should equal to all of currently remaining effective stake - (current_effective_stake, 0, current_effective_stake) - } else { - // no history or I've dropped out of history, so assume fully deactivated - (0, 0, 0) - } - } - - // returned tuple is (effective, activating) stake - fn stake_and_activating( - &self, - target_epoch: Epoch, - history: Option<&StakeHistory>, - fix_stake_deactivate: bool, - ) -> (u64, u64) { - let delegated_stake = self.stake; - - if self.is_bootstrap() { - // fully effective immediately - (delegated_stake, 0) - } else if fix_stake_deactivate && 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.and_then(|history| { - history - .get(&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; - - // portion of newly effective cluster stake I'm entitled to at current epoch - let newly_effective_cluster_stake = - prev_cluster_stake.effective as f64 * self.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(¤t_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) - } - } - - pub(crate) fn rewrite_stake( - &mut self, - account_balance: u64, - rent_exempt_balance: u64, - ) -> Option<(u64, u64)> { - // note that this will intentionally overwrite innocent - // deactivated-then-immeditealy-withdrawn stake accounts as well - // this is chosen to minimize the risks from complicated logic, - // over some unneeded rewrites - let corrected_stake = account_balance.saturating_sub(rent_exempt_balance); - if self.stake != corrected_stake { - // this could result in creating a 0-staked account; - // rewards and staking calc can handle it. - let (old, new) = (self.stake, corrected_stake); - self.stake = corrected_stake; - Some((old, new)) - } else { - None - } - } -} - -#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] -pub struct Stake { - pub delegation: Delegation, - /// credits observed is credits from vote account state when delegated or redeemed - pub credits_observed: u64, -} - -impl Authorized { - pub fn auto(authorized: &Pubkey) -> Self { - Self { - staker: *authorized, - withdrawer: *authorized, - } - } - pub fn check( - &self, - signers: &HashSet, - stake_authorize: StakeAuthorize, - ) -> Result<(), InstructionError> { - match stake_authorize { - StakeAuthorize::Staker if signers.contains(&self.staker) => Ok(()), - StakeAuthorize::Withdrawer if signers.contains(&self.withdrawer) => Ok(()), - _ => Err(InstructionError::MissingRequiredSignature), - } - } - - pub fn authorize( - &mut self, - signers: &HashSet, - 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 - } + config: &Config, + ) -> Stake { + Stake { + delegation: Delegation::new( + voter_pubkey, + stake, + activation_epoch, + config.warmup_cooldown_rate, + ), + credits_observed: vote_state.credits(), } - Ok(()) } } @@ -560,18 +154,10 @@ pub struct PointValue { pub points: u128, // over these points } -impl Stake { - pub fn stake( - &self, - epoch: Epoch, - history: Option<&StakeHistory>, - fix_stake_deactivate: bool, - ) -> u64 { - self.delegation.stake(epoch, history, fix_stake_deactivate) - } - +pub struct StakeRewardCalculator; +impl StakeRewardCalculator { pub fn redeem_rewards( - &mut self, + stake: &mut Stake, point_value: &PointValue, vote_state: &VoteState, stake_history: Option<&StakeHistory>, @@ -580,11 +166,12 @@ impl Stake { ) -> Option<(u64, u64)> { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( - self.credits_observed, + stake.credits_observed, None, )); } - self.calculate_rewards( + Self::calculate_rewards( + stake, point_value, vote_state, stake_history, @@ -594,24 +181,25 @@ impl Stake { .map(|(stakers_reward, voters_reward, credits_observed)| { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( - self.credits_observed, + stake.credits_observed, Some(credits_observed), )); } - self.credits_observed = credits_observed; - self.delegation.stake += stakers_reward; + stake.credits_observed = credits_observed; + stake.delegation.stake += stakers_reward; (stakers_reward, voters_reward) }) } pub fn calculate_points( - &self, + stake: &Stake, vote_state: &VoteState, stake_history: Option<&StakeHistory>, inflation_point_calc_tracer: &mut Option, fix_stake_deactivate: bool, ) -> u128 { - self.calculate_points_and_credits( + Self::calculate_points_and_credits( + stake, vote_state, stake_history, inflation_point_calc_tracer, @@ -624,19 +212,19 @@ impl Stake { /// points were earned (credits * stake) and new value /// for credits_observed were the points paid fn calculate_points_and_credits( - &self, + stake: &Stake, new_vote_state: &VoteState, stake_history: Option<&StakeHistory>, inflation_point_calc_tracer: &mut Option, fix_stake_deactivate: bool, ) -> (u128, u64) { // if there is no newer credits since observed, return no point - if new_vote_state.credits() <= self.credits_observed { + if new_vote_state.credits() <= stake.credits_observed { if fix_stake_deactivate { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into()); } - return (0, self.credits_observed); + return (0, stake.credits_observed); } else { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnZero.into()); @@ -646,12 +234,12 @@ impl Stake { } let mut points = 0; - let mut new_credits_observed = self.credits_observed; + let mut new_credits_observed = stake.credits_observed; for (epoch, final_epoch_credits, initial_epoch_credits) in new_vote_state.epoch_credits().iter().copied() { - let stake = u128::from(self.delegation.stake( + let stake_amount = u128::from(stake.delegation.stake( epoch, stake_history, fix_stake_deactivate, @@ -659,10 +247,10 @@ impl Stake { // figure out how much this stake has seen that // for which the vote account has a record - let earned_credits = if self.credits_observed < initial_epoch_credits { + let earned_credits = if stake.credits_observed < initial_epoch_credits { // the staker observed the entire epoch final_epoch_credits - initial_epoch_credits - } else if self.credits_observed < final_epoch_credits { + } else if stake.credits_observed < final_epoch_credits { // the staker registered sometime during the epoch, partial credit final_epoch_credits - new_credits_observed } else { @@ -676,13 +264,13 @@ impl Stake { new_credits_observed = new_credits_observed.max(final_epoch_credits); // finally calculate points for this epoch - let earned_points = stake * earned_credits; + let earned_points = stake_amount * earned_credits; points += earned_points; if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints( epoch, - stake, + stake_amount, earned_credits, earned_points, )); @@ -699,14 +287,15 @@ impl Stake { /// * new value for credits_observed in the stake /// returns None if there's no payout or if any deserved payout is < 1 lamport pub fn calculate_rewards( - &self, + stake: &Stake, point_value: &PointValue, vote_state: &VoteState, stake_history: Option<&StakeHistory>, inflation_point_calc_tracer: &mut Option, fix_stake_deactivate: bool, ) -> Option<(u64, u64, u64)> { - let (points, credits_observed) = self.calculate_points_and_credits( + let (points, credits_observed) = Self::calculate_points_and_credits( + stake, vote_state, stake_history, inflation_point_calc_tracer, @@ -765,91 +354,6 @@ impl Stake { Some((staker_rewards, voter_rewards, credits_observed)) } - - fn redelegate( - &mut self, - stake_lamports: u64, - voter_pubkey: &Pubkey, - vote_state: &VoteState, - clock: &Clock, - stake_history: &StakeHistory, - config: &Config, - can_reverse_deactivation: bool, - ) -> Result<(), StakeError> { - // If stake is currently active: - if self.stake(clock.epoch, Some(stake_history), true) != 0 { - // If pubkey of new voter is the same as current, - // and we are scheduled to start deactivating this epoch, - // we rescind deactivation - if self.delegation.voter_pubkey == *voter_pubkey - && clock.epoch == self.delegation.deactivation_epoch - && can_reverse_deactivation - { - self.delegation.deactivation_epoch = std::u64::MAX; - return Ok(()); - } else { - // can't redelegate to another pubkey if stake is active. - return Err(StakeError::TooSoonToRedelegate); - } - } - // Either the stake is freshly activated, is active but has been - // deactivated this epoch, or has fully de-activated. - // Redelegation implies either re-activation or un-deactivation - - self.delegation.stake = stake_lamports; - self.delegation.activation_epoch = clock.epoch; - self.delegation.deactivation_epoch = std::u64::MAX; - self.delegation.voter_pubkey = *voter_pubkey; - self.delegation.warmup_cooldown_rate = config.warmup_cooldown_rate; - self.credits_observed = vote_state.credits(); - Ok(()) - } - - fn split( - &mut self, - remaining_stake_delta: u64, - split_stake_amount: u64, - ) -> Result { - 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) - } - - fn new( - stake: u64, - voter_pubkey: &Pubkey, - vote_state: &VoteState, - activation_epoch: Epoch, - config: &Config, - ) -> Self { - Self { - delegation: Delegation::new( - voter_pubkey, - stake, - activation_epoch, - config.warmup_cooldown_rate, - ), - credits_observed: vote_state.credits(), - } - } - - fn deactivate(&mut self, epoch: Epoch) -> Result<(), StakeError> { - if self.delegation.deactivation_epoch != std::u64::MAX { - Err(StakeError::AlreadyDeactivated) - } else { - self.delegation.deactivation_epoch = epoch; - Ok(()) - } - } } pub trait StakeAccount { @@ -1035,7 +539,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> { match self.state()? { StakeState::Initialized(meta) => { meta.authorized.check(signers, StakeAuthorize::Staker)?; - let stake = Stake::new( + let stake = StakeConverter::new_stake( self.lamports()?.saturating_sub(meta.rent_exempt_reserve), // can't stake the rent ;) vote_account.unsigned_key(), &State::::state(vote_account)?.convert_to_current(), @@ -1046,7 +550,8 @@ impl<'a> StakeAccount for KeyedAccount<'a> { } StakeState::Stake(meta, mut stake) => { meta.authorized.check(signers, StakeAuthorize::Staker)?; - stake.redelegate( + StakeConverter::redelegate( + &mut stake, self.lamports()?.saturating_sub(meta.rent_exempt_reserve), // can't stake the rent ;) vote_account.unsigned_key(), &State::::state(vote_account)?.convert_to_current(), @@ -1551,7 +1056,8 @@ pub fn redeem_rewards( )); } - if let Some((stakers_reward, voters_reward)) = stake.redeem_rewards( + if let Some((stakers_reward, voters_reward)) = StakeRewardCalculator::redeem_rewards( + &mut stake, point_value, &vote_state, stake_history, @@ -1583,7 +1089,8 @@ pub fn calculate_points( let vote_state: VoteState = StateMut::::state(vote_account)?.convert_to_current(); - Ok(stake.calculate_points( + Ok(StakeRewardCalculator::calculate_points( + &stake, &vote_state, stake_history, &mut null_tracer(), @@ -1762,7 +1269,7 @@ fn do_create_account( rent_exempt_reserve, ..Meta::default() }, - Stake::new( + StakeConverter::new_stake( lamports - rent_exempt_reserve, // underflow is an error, is basically: assert!(lamports > rent_exempt_reserve); voter_pubkey, &vote_state, @@ -1781,6 +1288,7 @@ mod tests { use crate::id; use solana_sdk::{ account::{AccountSharedData, WritableAccount}, + clock::UnixTimestamp, native_token, process_instruction::MockInvokeContext, pubkey::Pubkey, @@ -1789,15 +1297,6 @@ mod tests { use solana_vote_program::vote_state; use std::{cell::RefCell, iter::FromIterator}; - impl Meta { - pub fn auto(authorized: &Pubkey) -> Self { - Self { - authorized: Authorized::auto(authorized), - ..Meta::default() - } - } - } - #[test] fn test_authorized_authorize() { let staker = solana_sdk::pubkey::new_rand(); @@ -1944,7 +1443,7 @@ mod tests { .set_state(&StakeState::default()) .expect("set_state"); - assert_eq!(StakeState::stake_from(&stake_account), None); + assert_eq!(StakeConverter::stake_from(&stake_account), None); } #[test] @@ -2051,7 +1550,7 @@ mod tests { .is_ok()); // verify that delegate() looks right, compare against hand-rolled - let stake = StakeState::stake_from(&stake_keyed_account.account.borrow()).unwrap(); + let stake = StakeConverter::stake_from(&stake_keyed_account.account.borrow()).unwrap(); assert_eq!( stake, Stake { @@ -2112,7 +1611,7 @@ mod tests { .unwrap(); // verify that deactivation has been cleared - let stake = StakeState::stake_from(&stake_keyed_account.account.borrow()).unwrap(); + let stake = StakeConverter::stake_from(&stake_keyed_account.account.borrow()).unwrap(); assert_eq!(stake.delegation.deactivation_epoch, std::u64::MAX); // verify that delegate to a different vote account fails @@ -2167,7 +1666,7 @@ mod tests { ); // verify that delegate() looks right, compare against hand-rolled - let stake = StakeState::stake_from(&stake_keyed_account.account.borrow()).unwrap(); + let stake = StakeConverter::stake_from(&stake_keyed_account.account.borrow()).unwrap(); assert_eq!( stake, Stake { @@ -2858,7 +2357,7 @@ mod tests { ); // check that we see what we expect assert_eq!( - StakeState::from(&stake_keyed_account.account.borrow()).unwrap(), + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap(), StakeState::Initialized(Meta { lockup: Lockup { unix_timestamp: 0, @@ -3147,7 +2646,7 @@ mod tests { ); if let StakeState::Initialized(Meta { lockup, .. }) = - StakeState::from(&stake_keyed_account.account.borrow()).unwrap() + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(lockup.unix_timestamp, 2); assert_eq!(lockup.epoch, 1); @@ -3170,7 +2669,7 @@ mod tests { ); if let StakeState::Initialized(Meta { lockup, .. }) = - StakeState::from(&stake_keyed_account.account.borrow()).unwrap() + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(lockup.unix_timestamp, 2); assert_eq!(lockup.epoch, 3); @@ -3194,7 +2693,7 @@ mod tests { ); if let StakeState::Initialized(Meta { lockup, .. }) = - StakeState::from(&stake_keyed_account.account.borrow()).unwrap() + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(lockup.unix_timestamp, 2); assert_eq!(lockup.epoch, 3); @@ -3595,7 +3094,7 @@ mod tests { None, 0..future.epoch, &[ - StakeState::stake_from(&stake_keyed_account.account.borrow()) + StakeConverter::stake_from(&stake_keyed_account.account.borrow()) .unwrap() .delegation, ], @@ -3893,7 +3392,7 @@ mod tests { // assume stake.stake() is right // bootstrap means fully-vested stake at epoch 0 let stake_lamports = 1; - let mut stake = Stake::new( + let mut stake = StakeConverter::new_stake( stake_lamports, &Pubkey::default(), &vote_state, @@ -3904,7 +3403,8 @@ mod tests { // this one can't collect now, credits_observed == vote_state.credits() assert_eq!( None, - stake.redeem_rewards( + StakeRewardCalculator::redeem_rewards( + &mut stake, &PointValue { rewards: 1_000_000_000, points: 1 @@ -3923,7 +3423,8 @@ mod tests { // this one should be able to collect exactly 2 assert_eq!( Some((stake_lamports * 2, 0)), - stake.redeem_rewards( + StakeRewardCalculator::redeem_rewards( + &mut stake, &PointValue { rewards: 1, points: 1 @@ -3948,7 +3449,7 @@ mod tests { // bootstrap means fully-vested stake at epoch 0 with // 10_000_000 SOL is a big but not unreasaonable stake - let stake = Stake::new( + let stake = StakeConverter::new_stake( native_token::sol_to_lamports(10_000_000f64), &Pubkey::default(), &vote_state, @@ -3959,7 +3460,8 @@ mod tests { // this one can't collect now, credits_observed == vote_state.credits() assert_eq!( None, - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 1_000_000_000, points: 1 @@ -3981,7 +3483,13 @@ mod tests { // no overflow on points assert_eq!( u128::from(stake.delegation.stake) * epoch_slots, - stake.calculate_points(&vote_state, None, &mut null_tracer(), true) + StakeRewardCalculator::calculate_points( + &stake, + &vote_state, + None, + &mut null_tracer(), + true + ) ); } @@ -3990,7 +3498,7 @@ mod tests { let mut vote_state = VoteState::default(); // assume stake.stake() is right // bootstrap means fully-vested stake at epoch 0 - let mut stake = Stake::new( + let mut stake = StakeConverter::new_stake( 1, &Pubkey::default(), &vote_state, @@ -4001,7 +3509,8 @@ mod tests { // this one can't collect now, credits_observed == vote_state.credits() assert_eq!( None, - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 1_000_000_000, points: 1 @@ -4020,7 +3529,8 @@ mod tests { // this one should be able to collect exactly 2 assert_eq!( Some((stake.delegation.stake * 2, 0, 2)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 2, points: 2 // all his @@ -4036,7 +3546,8 @@ mod tests { // this one should be able to collect exactly 1 (already observed one) assert_eq!( Some((stake.delegation.stake, 0, 2)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 1, points: 1 @@ -4055,7 +3566,8 @@ mod tests { // this one should be able to collect the one just added assert_eq!( Some((stake.delegation.stake, 0, 3)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 2, points: 2 @@ -4072,7 +3584,8 @@ mod tests { // this one should be able to collect 2 now assert_eq!( Some((stake.delegation.stake * 2, 0, 4)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 2, points: 2 @@ -4095,7 +3608,8 @@ mod tests { 0, 4 )), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 4, points: 4 @@ -4112,7 +3626,8 @@ mod tests { vote_state.commission = 1; assert_eq!( None, // would be Some((0, 2 * 1 + 1 * 2, 4)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 4, points: 4 @@ -4126,7 +3641,8 @@ mod tests { vote_state.commission = 99; assert_eq!( None, // would be Some((0, 2 * 1 + 1 * 2, 4)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 4, points: 4 @@ -4143,7 +3659,8 @@ mod tests { // paying rewards when inflation is turned on. assert_eq!( Some((0, 0, 4)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 0, points: 4 @@ -4160,7 +3677,8 @@ mod tests { stake.credits_observed = 4; assert_eq!( Some((0, 0, 4)), - stake.calculate_rewards( + StakeRewardCalculator::calculate_rewards( + &stake, &PointValue { rewards: 0, points: 4 @@ -4175,11 +3693,23 @@ mod tests { // assert the previous behavior is preserved where fix_stake_deactivate=false assert_eq!( (0, 0), - stake.calculate_points_and_credits(&vote_state, None, &mut null_tracer(), false) + StakeRewardCalculator::calculate_points_and_credits( + &stake, + &vote_state, + None, + &mut null_tracer(), + false + ) ); assert_eq!( (0, 4), - stake.calculate_points_and_credits(&vote_state, None, &mut null_tracer(), true) + StakeRewardCalculator::calculate_points_and_credits( + &stake, + &vote_state, + None, + &mut null_tracer(), + true + ) ); } @@ -4254,7 +3784,7 @@ mod tests { Ok(()) ); if let StakeState::Initialized(Meta { authorized, .. }) = - StakeState::from(&stake_keyed_account.account.borrow()).unwrap() + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(authorized.staker, stake_pubkey0); assert_eq!(authorized.withdrawer, stake_pubkey0); @@ -4292,7 +3822,7 @@ mod tests { Ok(()) ); if let StakeState::Initialized(Meta { authorized, .. }) = - StakeState::from(&stake_keyed_account.account.borrow()).unwrap() + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(authorized.staker, stake_pubkey2); } @@ -4309,7 +3839,7 @@ mod tests { Ok(()) ); if let StakeState::Initialized(Meta { authorized, .. }) = - StakeState::from(&stake_keyed_account.account.borrow()).unwrap() + StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(authorized.staker, stake_pubkey2); } @@ -4584,7 +4114,10 @@ mod tests { let stake_lamports = 42; let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, - &StakeState::Stake(Meta::auto(&stake_pubkey), Stake::just_stake(stake_lamports)), + &StakeState::Stake( + Meta::auto(&stake_pubkey), + StakeConverter::just_stake(stake_lamports), + ), std::mem::size_of::(), &id(), ) @@ -4608,9 +4141,9 @@ mod tests { Err(InstructionError::InvalidAccountData) ); } - impl Stake { - fn just_stake(stake: u64) -> Self { - Self { + impl StakeConverter { + fn just_stake(stake: u64) -> Stake { + Stake { delegation: Delegation { stake, ..Delegation::default() @@ -4628,7 +4161,7 @@ mod tests { stake_lamports, &StakeState::Stake( Meta::auto(&stake_pubkey), - Stake::just_stake(stake_lamports / 2 - 1), + StakeConverter::just_stake(stake_lamports / 2 - 1), ), std::mem::size_of::(), &id(), @@ -4673,7 +4206,7 @@ mod tests { StakeState::Initialized(meta), StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ), ] { let stake_account = AccountSharedData::new_ref_data_with_space( @@ -4769,7 +4302,10 @@ mod tests { // test splitting both an Initialized stake and a Staked stake for state in &[ StakeState::Initialized(Meta::auto(&stake_pubkey)), - StakeState::Stake(Meta::auto(&stake_pubkey), Stake::just_stake(stake_lamports)), + StakeState::Stake( + Meta::auto(&stake_pubkey), + StakeConverter::just_stake(stake_lamports), + ), ] { let split_stake_account = AccountSharedData::new_ref_data_with_space( 0, @@ -4874,7 +4410,10 @@ mod tests { let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, - &StakeState::Stake(Meta::auto(&stake_pubkey), Stake::just_stake(stake_lamports)), + &StakeState::Stake( + Meta::auto(&stake_pubkey), + StakeConverter::just_stake(stake_lamports), + ), std::mem::size_of::(), &id(), ) @@ -4905,7 +4444,7 @@ mod tests { let state = StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ); // Test various account prefunding, including empty, less than rent_exempt_reserve, exactly // rent_exempt_reserve, and more than rent_exempt_reserve. The empty case is not covered in @@ -5008,7 +4547,7 @@ mod tests { let state = StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ); let expected_rent_exempt_reserve = calculate_split_rent_exempt_reserve( @@ -5135,7 +4674,7 @@ mod tests { let state = StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ); let split_lamport_balances = vec![ @@ -5198,7 +4737,7 @@ mod tests { StakeState::Initialized(meta), StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ), ] { let split_stake_account = AccountSharedData::new_ref_data_with_space( @@ -5284,7 +4823,7 @@ mod tests { let state = StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ); // Test various account prefunding, including empty, less than rent_exempt_reserve, exactly // rent_exempt_reserve, and more than rent_exempt_reserve. Technically, the empty case is @@ -5363,7 +4902,7 @@ mod tests { StakeState::Initialized(meta), StakeState::Stake( meta, - Stake::just_stake(stake_lamports - rent_exempt_reserve), + StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), ), ] { // Test that splitting to a larger account fails @@ -5486,14 +5025,14 @@ mod tests { StakeState::Initialized(Meta::auto(&authorized_pubkey)), StakeState::Stake( Meta::auto(&authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), ] { for source_state in &[ StakeState::Initialized(Meta::auto(&authorized_pubkey)), StakeState::Stake( Meta::auto(&authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), ] { let stake_account = AccountSharedData::new_ref_data_with_space( @@ -5649,14 +5188,14 @@ mod tests { StakeState::Initialized(Meta::auto(&authorized_pubkey)), StakeState::Stake( Meta::auto(&authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), ] { for source_state in &[ StakeState::Initialized(Meta::auto(&wrong_authorized_pubkey)), StakeState::Stake( Meta::auto(&wrong_authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), ] { let stake_account = AccountSharedData::new_ref_data_with_space( @@ -5720,7 +5259,7 @@ mod tests { StakeState::Initialized(Meta::auto(&authorized_pubkey)), StakeState::Stake( Meta::auto(&authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), ] { for source_state in &[StakeState::Uninitialized, StakeState::RewardsPool] { @@ -5771,7 +5310,7 @@ mod tests { stake_lamports, &StakeState::Stake( Meta::auto(&authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), std::mem::size_of::(), &id(), @@ -5783,7 +5322,7 @@ mod tests { stake_lamports, &StakeState::Stake( Meta::auto(&authorized_pubkey), - Stake::just_stake(stake_lamports), + StakeConverter::just_stake(stake_lamports), ), std::mem::size_of::(), &solana_sdk::pubkey::new_rand(), @@ -6191,7 +5730,8 @@ mod tests { Ok(()) ); let authorized = - StakeState::authorized_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap(); + StakeConverter::authorized_from(&stake_keyed_account.try_account_ref().unwrap()) + .unwrap(); assert_eq!(authorized.staker, new_staker_pubkey); let other_pubkey = solana_sdk::pubkey::new_rand(); @@ -6238,7 +5778,7 @@ mod tests { Ok(()) ); let stake = - StakeState::stake_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap(); + StakeConverter::stake_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap(); assert_eq!(stake.delegation.voter_pubkey, new_voter_pubkey); // Test another staking action @@ -6324,7 +5864,7 @@ mod tests { true, ) .unwrap(); - let stake = StakeState::stake_from(&stake_account.borrow()).unwrap(); + let stake = StakeConverter::stake_from(&stake_account.borrow()).unwrap(); assert_eq!( stake.delegation.stake, stake_keyed_account.lamports().unwrap() - rent_exempt_reserve, @@ -6351,7 +5891,7 @@ mod tests { true, ) .unwrap(); - let stake = StakeState::stake_from(&stake_account.borrow()).unwrap(); + let stake = StakeConverter::stake_from(&stake_account.borrow()).unwrap(); assert_eq!( stake.delegation.stake, stake_keyed_account.lamports().unwrap() - rent_exempt_reserve, diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 8bc14cf9533f40..bed762359d87a8 100755 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -43,6 +43,7 @@ pub mod serialize_utils; pub mod short_vec; pub mod slot_hashes; pub mod slot_history; +pub mod stake; pub mod stake_history; pub mod system_instruction; pub mod system_program; diff --git a/sdk/program/src/stake/config.rs b/sdk/program/src/stake/config.rs new file mode 100644 index 00000000000000..9470b2940a27fc --- /dev/null +++ b/sdk/program/src/stake/config.rs @@ -0,0 +1,28 @@ +//! config for staking +//! carries variables that the stake program cares about +use serde_derive::{Deserialize, Serialize}; + +// stake config ID +crate::declare_id!("StakeConfig11111111111111111111111111111111"); + +// 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 DEFAULT_SLASH_PENALTY: u8 = ((5 * std::u8::MAX as usize) / 100) as u8; + +#[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 std::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, + } + } +} diff --git a/sdk/program/src/stake/instruction.rs b/sdk/program/src/stake/instruction.rs new file mode 100644 index 00000000000000..cbb4e82bb413cb --- /dev/null +++ b/sdk/program/src/stake/instruction.rs @@ -0,0 +1,507 @@ +use { + crate::stake::{ + config, id, + state::{Authorized, Lockup, StakeAuthorize, StakeState}, + }, + crate::{ + clock::{Epoch, UnixTimestamp}, + decode_error::DecodeError, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_instruction, sysvar, + }, + log::*, + num_derive::{FromPrimitive, ToPrimitive}, + serde_derive::{Deserialize, Serialize}, + thiserror::Error, +}; + +/// Reasons the stake might have had an error +#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] +pub enum StakeError { + #[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, + + #[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, +} + +impl DecodeError for StakeError { + fn type_of() -> &'static str { + "StakeError" + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, 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. [] Address of config account that carries 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), +} + +#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy)] +pub struct LockupArgs { + pub unix_timestamp: Option, + pub epoch: Option, + pub custodian: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub struct AuthorizeWithSeedArgs { + pub new_authorized_pubkey: Pubkey, + 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 create_account_with_seed( + from_pubkey: &Pubkey, + stake_pubkey: &Pubkey, + base: &Pubkey, + seed: &str, + authorized: &Authorized, + lockup: &Lockup, + lamports: u64, +) -> Vec { + vec![ + system_instruction::create_account_with_seed( + from_pubkey, + stake_pubkey, + base, + seed, + lamports, + std::mem::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 { + vec![ + system_instruction::create_account( + from_pubkey, + stake_pubkey, + lamports, + std::mem::size_of::() as u64, + &id(), + ), + initialize(stake_pubkey, authorized, lockup), + ] +} + +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 { + vec![ + system_instruction::allocate(split_stake_pubkey, std::mem::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 { + vec![ + system_instruction::allocate_with_seed( + split_stake_pubkey, + base, + seed, + std::mem::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 { + 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 { + 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 { + 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_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 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), + 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) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::instruction::InstructionError; + + #[test] + fn test_custom_error_decode() { + use num_traits::FromPrimitive; + fn pretty_err(err: InstructionError) -> String + where + T: 'static + std::error::Error + DecodeError + 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::NoCreditsToRedeem.into()) + ) + } +} diff --git a/sdk/program/src/stake/mod.rs b/sdk/program/src/stake/mod.rs new file mode 100644 index 00000000000000..29fa8eb874d162 --- /dev/null +++ b/sdk/program/src/stake/mod.rs @@ -0,0 +1,5 @@ +pub mod config; +pub mod instruction; +pub mod state; + +crate::declare_id!("Stake11111111111111111111111111111111111111"); diff --git a/sdk/program/src/stake/state.rs b/sdk/program/src/stake/state.rs new file mode 100644 index 00000000000000..ec4c35878107cb --- /dev/null +++ b/sdk/program/src/stake/state.rs @@ -0,0 +1,532 @@ +use { + crate::{ + clock::{Clock, Epoch, UnixTimestamp}, + instruction::InstructionError, + pubkey::Pubkey, + rent::Rent, + stake::{ + config::Config, + instruction::{LockupArgs, StakeError}, + }, + stake_history::StakeHistory, + }, + std::collections::HashSet, +}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +#[allow(clippy::large_enum_variant)] +pub enum StakeState { + Uninitialized, + Initialized(Meta), + Stake(Meta, Stake), + RewardsPool, +} + +impl Default for StakeState { + fn default() -> Self { + StakeState::Uninitialized + } +} + +impl StakeState { + pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 { + rent.minimum_balance(std::mem::size_of::()) + } + + pub fn stake(&self) -> Option { + match self { + StakeState::Stake(_meta, stake) => Some(*stake), + _ => None, + } + } + + pub fn delegation(&self) -> Option { + match self { + StakeState::Stake(_meta, stake) => Some(stake.delegation), + _ => None, + } + } + + pub fn authorized(&self) -> Option { + match self { + StakeState::Stake(meta, _stake) => Some(meta.authorized), + StakeState::Initialized(meta) => Some(meta.authorized), + _ => None, + } + } + + pub fn lockup(&self) -> Option { + self.meta().map(|meta| meta.lockup) + } + + pub fn meta(&self) -> Option { + match self { + StakeState::Stake(meta, _stake) => Some(*meta), + StakeState::Initialized(meta) => Some(*meta), + _ => None, + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +pub enum StakeAuthorize { + Staker, + Withdrawer, +} + +#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +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 + } +} + +#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +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, + stake_authorize: StakeAuthorize, + ) -> Result<(), InstructionError> { + match stake_authorize { + StakeAuthorize::Staker if signers.contains(&self.staker) => Ok(()), + StakeAuthorize::Withdrawer if signers.contains(&self.withdrawer) => Ok(()), + _ => Err(InstructionError::MissingRequiredSignature), + } + } + + pub fn authorize( + &mut self, + signers: &HashSet, + 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(()) + } +} + +#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +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, + clock: Option<&Clock>, + ) -> Result<(), InstructionError> { + match clock { + None => { + // pre-stake_program_v4 behavior: custodian can set lockups at any time + if !signers.contains(&self.lockup.custodian) { + return Err(InstructionError::MissingRequiredSignature); + } + } + Some(clock) => { + // 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 rewrite_rent_exempt_reserve( + &mut self, + rent: &Rent, + data_len: usize, + ) -> Option<(u64, u64)> { + let corrected_rent_exempt_reserve = rent.minimum_balance(data_len); + if corrected_rent_exempt_reserve != self.rent_exempt_reserve { + // We forcibly update rent_excempt_reserve even + // if rent_exempt_reserve > account_balance, hoping user might restore + // rent_exempt status by depositing. + let (old, new) = (self.rent_exempt_reserve, corrected_rent_exempt_reserve); + self.rent_exempt_reserve = corrected_rent_exempt_reserve; + Some((old, new)) + } else { + None + } + } + + pub fn auto(authorized: &Pubkey) -> Self { + Self { + authorized: Authorized::auto(authorized), + ..Meta::default() + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +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 + pub warmup_cooldown_rate: f64, +} + +impl Default for Delegation { + fn default() -> Self { + Self { + voter_pubkey: Pubkey::default(), + stake: 0, + activation_epoch: 0, + deactivation_epoch: std::u64::MAX, + warmup_cooldown_rate: Config::default().warmup_cooldown_rate, + } + } +} + +impl Delegation { + pub fn new( + voter_pubkey: &Pubkey, + stake: u64, + activation_epoch: Epoch, + warmup_cooldown_rate: f64, + ) -> Self { + Self { + voter_pubkey: *voter_pubkey, + stake, + activation_epoch, + warmup_cooldown_rate, + ..Delegation::default() + } + } + pub fn is_bootstrap(&self) -> bool { + self.activation_epoch == std::u64::MAX + } + + pub fn stake( + &self, + epoch: Epoch, + history: Option<&StakeHistory>, + fix_stake_deactivate: bool, + ) -> u64 { + self.stake_activating_and_deactivating(epoch, history, fix_stake_deactivate) + .0 + } + + // returned tuple is (effective, activating, deactivating) stake + #[allow(clippy::comparison_chain)] + pub fn stake_activating_and_deactivating( + &self, + target_epoch: Epoch, + history: Option<&StakeHistory>, + fix_stake_deactivate: bool, + ) -> (u64, u64, u64) { + let delegated_stake = self.stake; + + // first, calculate an effective and activating stake + let (effective_stake, activating_stake) = + self.stake_and_activating(target_epoch, history, fix_stake_deactivate); + + // then de-activate some portion if necessary + if target_epoch < self.deactivation_epoch { + // not deactivated + (effective_stake, activating_stake, 0) + } else if target_epoch == self.deactivation_epoch { + // can only deactivate what's activated + (effective_stake, 0, effective_stake.min(delegated_stake)) + } else if let Some((history, mut prev_epoch, mut prev_cluster_stake)) = + history.and_then(|history| { + history + .get(&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; + + // 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 * self.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(¤t_epoch) { + prev_epoch = current_epoch; + prev_cluster_stake = current_cluster_stake; + } else { + break; + } + } + + // deactivating stake should equal to all of currently remaining effective stake + (current_effective_stake, 0, current_effective_stake) + } else { + // no history or I've dropped out of history, so assume fully deactivated + (0, 0, 0) + } + } + + // returned tuple is (effective, activating) stake + fn stake_and_activating( + &self, + target_epoch: Epoch, + history: Option<&StakeHistory>, + fix_stake_deactivate: bool, + ) -> (u64, u64) { + let delegated_stake = self.stake; + + if self.is_bootstrap() { + // fully effective immediately + (delegated_stake, 0) + } else if fix_stake_deactivate && 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.and_then(|history| { + history + .get(&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; + + // portion of newly effective cluster stake I'm entitled to at current epoch + let newly_effective_cluster_stake = + prev_cluster_stake.effective as f64 * self.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(¤t_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) + } + } + + pub fn rewrite_stake( + &mut self, + account_balance: u64, + rent_exempt_balance: u64, + ) -> Option<(u64, u64)> { + // note that this will intentionally overwrite innocent + // deactivated-then-immeditealy-withdrawn stake accounts as well + // this is chosen to minimize the risks from complicated logic, + // over some unneeded rewrites + let corrected_stake = account_balance.saturating_sub(rent_exempt_balance); + if self.stake != corrected_stake { + // this could result in creating a 0-staked account; + // rewards and staking calc can handle it. + let (old, new) = (self.stake, corrected_stake); + self.stake = corrected_stake; + Some((old, new)) + } else { + None + } + } +} + +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] +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( + &self, + epoch: Epoch, + history: Option<&StakeHistory>, + fix_stake_deactivate: bool, + ) -> u64 { + self.delegation.stake(epoch, history, fix_stake_deactivate) + } + + pub fn split( + &mut self, + remaining_stake_delta: u64, + split_stake_amount: u64, + ) -> Result { + 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 != std::u64::MAX { + Err(StakeError::AlreadyDeactivated) + } else { + self.delegation.deactivation_epoch = epoch; + Ok(()) + } + } +} From 547f443a1dff323e0f1aa6e57d9ea24e5124edcc Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 11 Jun 2021 23:50:02 +0200 Subject: [PATCH 02/14] Update account-decoder --- Cargo.lock | 1 - account-decoder/Cargo.toml | 1 - account-decoder/src/parse_account_data.rs | 4 ++-- account-decoder/src/parse_config.rs | 6 +++--- account-decoder/src/parse_stake.rs | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83fc19c1202060..f860208e590c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4125,7 +4125,6 @@ dependencies = [ "serde_json", "solana-config-program", "solana-sdk", - "solana-stake-program", "solana-vote-program", "spl-token", "thiserror", diff --git a/account-decoder/Cargo.toml b/account-decoder/Cargo.toml index 664e36f41a7255..3b91cea7a3c135 100644 --- a/account-decoder/Cargo.toml +++ b/account-decoder/Cargo.toml @@ -21,7 +21,6 @@ serde_derive = "1.0.103" serde_json = "1.0.64" solana-config-program = { path = "../programs/config", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-vote-program = { path = "../programs/vote", version = "=1.8.0" } spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] } thiserror = "1.0" diff --git a/account-decoder/src/parse_account_data.rs b/account-decoder/src/parse_account_data.rs index 9b649dc8fec4ed..53ca713f90582d 100644 --- a/account-decoder/src/parse_account_data.rs +++ b/account-decoder/src/parse_account_data.rs @@ -9,14 +9,14 @@ use crate::{ }; use inflector::Inflector; use serde_json::Value; -use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar}; +use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar}; use std::collections::HashMap; use thiserror::Error; lazy_static! { static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id(); static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id(); - static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id(); + static ref STAKE_PROGRAM_ID: Pubkey = stake::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id(); static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); diff --git a/account-decoder/src/parse_config.rs b/account-decoder/src/parse_config.rs index 3a9d6151b5eac7..de98890cc45b30 100644 --- a/account-decoder/src/parse_config.rs +++ b/account-decoder/src/parse_config.rs @@ -6,10 +6,10 @@ use bincode::deserialize; use serde_json::Value; use solana_config_program::{get_config_data, ConfigKeys}; use solana_sdk::pubkey::Pubkey; -use solana_stake_program::config::Config as StakeConfig; +use solana_sdk::stake::config::{self as stake_config, Config as StakeConfig}; pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result { - let parsed_account = if pubkey == &solana_stake_program::config::id() { + let parsed_account = if pubkey == &stake_config::id() { get_config_data(data) .ok() .and_then(|data| deserialize::(data).ok()) @@ -103,7 +103,7 @@ mod test { assert_eq!( parse_config( &stake_config_account.data(), - &solana_stake_program::config::id() + &stake_config::id() ) .unwrap(), ConfigAccountType::StakeConfig(UiStakeConfig { diff --git a/account-decoder/src/parse_stake.rs b/account-decoder/src/parse_stake.rs index 86dc88e80a1031..fa3d3def6a25da 100644 --- a/account-decoder/src/parse_stake.rs +++ b/account-decoder/src/parse_stake.rs @@ -4,7 +4,7 @@ use crate::{ }; use bincode::deserialize; use solana_sdk::clock::{Epoch, UnixTimestamp}; -use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState}; +use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState}; pub fn parse_stake(data: &[u8]) -> Result { let stake_state: StakeState = deserialize(data) From 82d991dfa8ed58e10a5c05e512e7329707fa6d05 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Sat, 12 Jun 2021 00:22:03 +0200 Subject: [PATCH 03/14] Update cli and runtime --- Cargo.lock | 2 -- account-decoder/src/parse_config.rs | 6 +--- cli-output/Cargo.toml | 1 - cli-output/src/cli_output.rs | 2 +- cli-output/src/display.rs | 9 +++--- cli/Cargo.toml | 1 - cli/src/cli.rs | 21 +++++++------ cli/src/cluster_query.rs | 9 +++--- cli/src/stake.rs | 29 ++++++++---------- cli/tests/stake.rs | 14 ++++----- cli/tests/transfer.rs | 3 +- programs/stake/src/lib.rs | 2 -- programs/stake/src/stake_state.rs | 2 +- runtime/src/bank.rs | 17 +++++------ runtime/src/builtins.rs | 4 +-- runtime/src/genesis_utils.rs | 2 +- runtime/src/non_circulating_supply.rs | 20 +++++++----- runtime/src/stakes.rs | 22 ++++++++------ runtime/tests/stake.rs | 44 ++++++++++++--------------- 19 files changed, 101 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f860208e590c24..7327440adc3b0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4403,7 +4403,6 @@ dependencies = [ "solana-net-utils", "solana-remote-wallet", "solana-sdk", - "solana-stake-program", "solana-transaction-status", "solana-version", "solana-vote-program", @@ -4444,7 +4443,6 @@ dependencies = [ "solana-clap-utils", "solana-client", "solana-sdk", - "solana-stake-program", "solana-transaction-status", "solana-vote-program", "spl-memo", diff --git a/account-decoder/src/parse_config.rs b/account-decoder/src/parse_config.rs index de98890cc45b30..c545c8c0d85324 100644 --- a/account-decoder/src/parse_config.rs +++ b/account-decoder/src/parse_config.rs @@ -101,11 +101,7 @@ mod test { }; let stake_config_account = create_config_account(vec![], &stake_config, 10); assert_eq!( - parse_config( - &stake_config_account.data(), - &stake_config::id() - ) - .unwrap(), + parse_config(&stake_config_account.data(), &stake_config::id()).unwrap(), ConfigAccountType::StakeConfig(UiStakeConfig { warmup_cooldown_rate: 0.25, slash_penalty: 50, diff --git a/cli-output/Cargo.toml b/cli-output/Cargo.toml index 1f25d3bb239077..2a3dffa7e4114b 100644 --- a/cli-output/Cargo.toml +++ b/cli-output/Cargo.toml @@ -23,7 +23,6 @@ solana-account-decoder = { path = "../account-decoder", version = "=1.8.0" } solana-clap-utils = { path = "../clap-utils", version = "=1.8.0" } solana-client = { path = "../client", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" } solana-vote-program = { path = "../programs/vote", version = "=1.8.0" } spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] } diff --git a/cli-output/src/cli_output.rs b/cli-output/src/cli_output.rs index 7532a41d934937..a1605b587a0240 100644 --- a/cli-output/src/cli_output.rs +++ b/cli-output/src/cli_output.rs @@ -25,10 +25,10 @@ use { native_token::lamports_to_sol, pubkey::Pubkey, signature::Signature, + stake::state::{Authorized, Lockup}, stake_history::StakeHistoryEntry, transaction::{Transaction, TransactionError}, }, - solana_stake_program::stake_state::{Authorized, Lockup}, solana_transaction_status::{ EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus, UiTransactionStatusMeta, diff --git a/cli-output/src/display.rs b/cli-output/src/display.rs index ec4f8b4a41030a..3b0c37242317b4 100644 --- a/cli-output/src/display.rs +++ b/cli-output/src/display.rs @@ -5,7 +5,7 @@ use { indicatif::{ProgressBar, ProgressStyle}, solana_sdk::{ clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol, - program_utils::limited_deserialize, pubkey::Pubkey, transaction::Transaction, + program_utils::limited_deserialize, pubkey::Pubkey, stake, transaction::Transaction, }, solana_transaction_status::UiTransactionStatusMeta, spl_memo::id as spl_memo_id, @@ -244,10 +244,9 @@ pub fn write_transaction( writeln!(w, "{} {:?}", prefix, vote_instruction)?; raw = false; } - } else if program_pubkey == solana_stake_program::id() { - if let Ok(stake_instruction) = limited_deserialize::< - solana_stake_program::stake_instruction::StakeInstruction, - >(&instruction.data) + } else if program_pubkey == stake::id() { + if let Ok(stake_instruction) = + limited_deserialize::(&instruction.data) { writeln!(w, "{} {:?}", prefix, stake_instruction)?; raw = false; diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a0cf8b45c412d7..47add1d8610241 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -41,7 +41,6 @@ solana-net-utils = { path = "../net-utils", version = "=1.8.0" } solana_rbpf = "=0.2.12" solana-remote-wallet = { path = "../remote-wallet", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" } solana-version = { path = "../version", version = "=1.8.0" } solana-vote-program = { path = "../programs/vote", version = "=1.8.0" } diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 78aaf760dce2de..9102706d7a360d 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -45,14 +45,15 @@ use solana_sdk::{ message::Message, pubkey::Pubkey, signature::{Signature, Signer, SignerError}, + stake::{ + self, + instruction::LockupArgs, + state::{Lockup, StakeAuthorize}, + }, system_instruction::{self, SystemError}, system_program, transaction::{Transaction, TransactionError}, }; -use solana_stake_program::{ - stake_instruction::LockupArgs, - stake_state::{Lockup, StakeAuthorize}, -}; use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding}; use solana_vote_program::vote_state::VoteAuthorize; use std::{ @@ -932,7 +933,7 @@ pub type ProcessResult = Result>; fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option { matches.value_of(arg_name).and_then(|v| match v { "NONCE" => Some(system_program::id()), - "STAKE" => Some(solana_stake_program::id()), + "STAKE" => Some(stake::id()), "VOTE" => Some(solana_vote_program::id()), _ => pubkey_of(matches, arg_name), }) @@ -2487,7 +2488,7 @@ mod tests { let from_pubkey = Some(solana_sdk::pubkey::new_rand()); let from_str = from_pubkey.unwrap().to_string(); for (name, program_id) in &[ - ("STAKE", solana_stake_program::id()), + ("STAKE", stake::id()), ("VOTE", solana_vote_program::id()), ("NONCE", system_program::id()), ] { @@ -2523,7 +2524,7 @@ mod tests { command: CliCommand::CreateAddressWithSeed { from_pubkey: None, seed: "seed".to_string(), - program_id: solana_stake_program::id(), + program_id: stake::id(), }, signers: vec![read_keypair_file(&keypair_file).unwrap().into()], } @@ -2786,11 +2787,11 @@ mod tests { config.command = CliCommand::CreateAddressWithSeed { from_pubkey: Some(from_pubkey), seed: "seed".to_string(), - program_id: solana_stake_program::id(), + program_id: stake::id(), }; let address = process_command(&config); let expected_address = - Pubkey::create_with_seed(&from_pubkey, "seed", &solana_stake_program::id()).unwrap(); + Pubkey::create_with_seed(&from_pubkey, "seed", &stake::id()).unwrap(); assert_eq!(address.unwrap(), expected_address.to_string()); // Need airdrop cases @@ -3177,7 +3178,7 @@ mod tests { memo: None, fee_payer: 0, derived_address_seed: Some(derived_address_seed), - derived_address_program_id: Some(solana_stake_program::id()), + derived_address_program_id: Some(stake::id()), }, signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),], } diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index ff5d0cc0f73ffa..ae110257c95830 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -46,7 +46,9 @@ use solana_sdk::{ rent::Rent, rpc_port::DEFAULT_RPC_PORT_STR, signature::Signature, - slot_history, system_instruction, system_program, + slot_history, + stake::{self, state::StakeState}, + system_instruction, system_program, sysvar::{ self, slot_history::SlotHistory, @@ -55,7 +57,6 @@ use solana_sdk::{ timing, transaction::Transaction, }; -use solana_stake_program::stake_state::StakeState; use solana_transaction_status::UiTransactionEncoding; use solana_vote_program::vote_state::VoteState; use std::{ @@ -1703,8 +1704,8 @@ pub fn process_show_stakes( ]); } } - let all_stake_accounts = rpc_client - .get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?; + let all_stake_accounts = + rpc_client.get_program_accounts_with_config(&stake::id(), program_accounts_config)?; let stake_history_account = rpc_client.get_account(&stake_history::id())?; let clock_account = rpc_client.get_account(&sysvar::clock::id())?; let clock: Clock = from_account(&clock_account).ok_or_else(|| { diff --git a/cli/src/stake.rs b/cli/src/stake.rs index 1bdb3c302f06eb..1f48c3e22d3f86 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -36,6 +36,11 @@ use solana_sdk::{ feature, feature_set, message::Message, pubkey::Pubkey, + stake::{ + self, + instruction::{self, LockupArgs, StakeError}, + state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState}, + }, system_instruction::SystemError, sysvar::{ clock, @@ -43,10 +48,6 @@ use solana_sdk::{ }, transaction::Transaction, }; -use solana_stake_program::{ - stake_instruction::{self, LockupArgs, StakeError}, - stake_state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState}, -}; use solana_vote_program::vote_state::VoteState; use std::{ops::Deref, sync::Arc}; @@ -971,7 +972,7 @@ pub fn process_create_stake_account( ) -> ProcessResult { let stake_account = config.signers[stake_account]; let stake_account_address = if let Some(seed) = seed { - Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &solana_stake_program::id())? + Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &stake::id())? } else { stake_account.pubkey() }; @@ -1039,7 +1040,7 @@ pub fn process_create_stake_account( if !sign_only { if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) { - let err_msg = if stake_account.owner == solana_stake_program::id() { + let err_msg = if stake_account.owner == stake::id() { format!("Stake account {} already exists", stake_account_address) } else { format!( @@ -1195,7 +1196,7 @@ pub fn process_deactivate_stake_account( let stake_authority = config.signers[stake_authority]; let stake_account_address = if let Some(seed) = seed { - Pubkey::create_with_seed(&stake_account_pubkey, seed, &solana_stake_program::id())? + Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::id())? } else { *stake_account_pubkey }; @@ -1273,7 +1274,7 @@ pub fn process_withdraw_stake( let custodian = custodian.map(|index| config.signers[index]); let stake_account_address = if let Some(seed) = seed { - Pubkey::create_with_seed(&stake_account_pubkey, seed, &solana_stake_program::id())? + Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::id())? } else { *stake_account_pubkey }; @@ -1394,18 +1395,14 @@ pub fn process_split_stake( let stake_authority = config.signers[stake_authority]; let split_stake_account_address = if let Some(seed) = split_stake_account_seed { - Pubkey::create_with_seed( - &split_stake_account.pubkey(), - &seed, - &solana_stake_program::id(), - )? + Pubkey::create_with_seed(&split_stake_account.pubkey(), &seed, &stake::id())? } else { split_stake_account.pubkey() }; if !sign_only { if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) { - let err_msg = if stake_account.owner == solana_stake_program::id() { + let err_msg = if stake_account.owner == stake::id() { format!( "Stake account {} already exists", split_stake_account_address @@ -1540,7 +1537,7 @@ pub fn process_merge_stake( if !sign_only { for stake_account_address in &[stake_account_pubkey, source_stake_account_pubkey] { if let Ok(stake_account) = rpc_client.get_account(stake_account_address) { - if stake_account.owner != solana_stake_program::id() { + if stake_account.owner != stake::id() { return Err(CliError::BadParameter(format!( "Account {} is not a stake account", stake_account_address @@ -1876,7 +1873,7 @@ pub fn process_show_stake_account( with_rewards: Option, ) -> ProcessResult { let stake_account = rpc_client.get_account(stake_account_address)?; - if stake_account.owner != solana_stake_program::id() { + if stake_account.owner != stake::id() { return Err(CliError::RpcRequestError(format!( "{:?} is not a stake account", stake_account_address, diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 51c3bd97705ff9..57b22212100af4 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -17,10 +17,11 @@ use solana_sdk::{ nonce::State as NonceState, pubkey::Pubkey, signature::{keypair_from_seed, Keypair, Signer}, -}; -use solana_stake_program::{ - stake_instruction::LockupArgs, - stake_state::{Lockup, StakeAuthorize, StakeState}, + stake::{ + self, + instruction::LockupArgs, + state::{Lockup, StakeAuthorize, StakeState}, + }, }; #[test] @@ -139,7 +140,7 @@ fn test_seed_stake_delegation_and_deactivation() { let stake_address = Pubkey::create_with_seed( &config_validator.signers[0].pubkey(), "hi there", - &solana_stake_program::id(), + &stake::id(), ) .expect("bad seed"); @@ -1556,7 +1557,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { from: 0, }; process_command(&config).unwrap(); - let seed_address = - Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap(); + let seed_address = Pubkey::create_with_seed(&stake_pubkey, seed, &stake::id()).unwrap(); check_recent_balance(50_000, &rpc_client, &seed_address); } diff --git a/cli/tests/transfer.rs b/cli/tests/transfer.rs index 3d971588305578..aeeb958df5e431 100644 --- a/cli/tests/transfer.rs +++ b/cli/tests/transfer.rs @@ -16,6 +16,7 @@ use solana_sdk::{ nonce::State as NonceState, pubkey::Pubkey, signature::{keypair_from_seed, Keypair, NullSigner, Signer}, + stake, }; #[test] @@ -513,7 +514,7 @@ fn test_transfer_with_seed() { let sender_pubkey = config.signers[0].pubkey(); let recipient_pubkey = Pubkey::new(&[1u8; 32]); let derived_address_seed = "seed".to_string(); - let derived_address_program_id = solana_stake_program::id(); + let derived_address_program_id = stake::id(); let derived_address = Pubkey::create_with_seed( &sender_pubkey, &derived_address_seed, diff --git a/programs/stake/src/lib.rs b/programs/stake/src/lib.rs index 8362d55f966cd1..8a03e59ee737a7 100644 --- a/programs/stake/src/lib.rs +++ b/programs/stake/src/lib.rs @@ -6,8 +6,6 @@ pub mod config; pub mod stake_instruction; pub mod stake_state; -solana_sdk::declare_id!("Stake11111111111111111111111111111111111111"); - pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 { config::add_genesis_account(genesis_config) } diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index 9c7721a1d0aa10..76d9cc7a0a1ee6 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -1285,13 +1285,13 @@ fn do_create_account( #[cfg(test)] mod tests { use super::*; - use crate::id; use solana_sdk::{ account::{AccountSharedData, WritableAccount}, clock::UnixTimestamp, native_token, process_instruction::MockInvokeContext, pubkey::Pubkey, + stake::id, system_program, }; use solana_vote_program::vote_state; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c144b0f6c52f51..4e6052e1fa3f93 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -96,6 +96,7 @@ use solana_sdk::{ signature::{Keypair, Signature}, slot_hashes::SlotHashes, slot_history::SlotHistory, + stake::{self, state::Delegation}, stake_weighted_timestamp::{ calculate_stake_weighted_timestamp, MaxAllowableDrift, MAX_ALLOWABLE_DRIFT_PERCENTAGE, MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW, @@ -105,9 +106,7 @@ use solana_sdk::{ timing::years_as_slots, transaction::{self, Result, Transaction, TransactionError}, }; -use solana_stake_program::stake_state::{ - self, Delegation, InflationPointCalculationEvent, PointValue, -}; +use solana_stake_program::stake_state::{self, InflationPointCalculationEvent, PointValue}; use solana_vote_program::vote_instruction::VoteInstruction; use std::{ borrow::Cow, @@ -1908,7 +1907,7 @@ impl Bank { if self .feature_set .is_active(&feature_set::filter_stake_delegation_accounts::id()) - && (stake_account.owner() != &solana_stake_program::id() + && (stake_account.owner() != &stake::id() || vote_account.owner() != &solana_vote_program::id()) { datapoint_warn!( @@ -5324,15 +5323,15 @@ pub(crate) mod tests { process_instruction::InvokeContext, rent::Rent, signature::{keypair_from_seed, Keypair, Signer}, + stake::{ + instruction as stake_instruction, + state::{Authorized, Delegation, Lockup, Stake}, + }, system_instruction::{self, SystemError}, system_program, sysvar::{fees::Fees, rewards::Rewards}, timing::duration_as_s, }; - use solana_stake_program::{ - stake_instruction, - stake_state::{self, Authorized, Delegation, Lockup, Stake}, - }; use solana_vote_program::{ vote_instruction, vote_state::{ @@ -9520,7 +9519,7 @@ pub(crate) mod tests { let pubkey = solana_sdk::pubkey::new_rand(); genesis_config.add_account( pubkey, - solana_stake_program::stake_state::create_lockup_stake_account( + stake_state::create_lockup_stake_account( &Authorized::auto(&pubkey), &Lockup::default(), &Rent::default(), diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index 899ad9a04e98c0..7b5b7b1d43c93d 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -7,7 +7,7 @@ use solana_sdk::{ instruction::InstructionError, process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext}, pubkey::Pubkey, - system_program, + stake, system_program, }; fn process_instruction_with_program_logging( @@ -56,7 +56,7 @@ fn genesis_builtins() -> Vec { ), Builtin::new( "stake_program", - solana_stake_program::id(), + stake::id(), with_program_logging!(solana_stake_program::stake_instruction::process_instruction), ), Builtin::new( diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index 25dec5e47bb459..29457764cf3a1c 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -8,10 +8,10 @@ use solana_sdk::{ pubkey::Pubkey, rent::Rent, signature::{Keypair, Signer}, + stake::state::StakeState, system_program, }; use solana_stake_program::stake_state; -use solana_stake_program::stake_state::StakeState; use solana_vote_program::vote_state; use std::borrow::Borrow; diff --git a/runtime/src/non_circulating_supply.rs b/runtime/src/non_circulating_supply.rs index fee9a314d2f493..06122f1aed8efa 100644 --- a/runtime/src/non_circulating_supply.rs +++ b/runtime/src/non_circulating_supply.rs @@ -4,8 +4,12 @@ use { bank::Bank, }, log::*, - solana_sdk::{account::ReadableAccount, pubkey::Pubkey}, - solana_stake_program::stake_state::StakeState, + solana_sdk::{ + account::ReadableAccount, + pubkey::Pubkey, + stake::{self, state::StakeState}, + }, + solana_stake_program::stake_state::StakeConverter, std::{collections::HashSet, sync::Arc}, }; @@ -32,18 +36,18 @@ pub fn calculate_non_circulating_supply(bank: &Arc) -> NonCirculatingSuppl .contains(&AccountIndex::ProgramId) { bank.get_filtered_indexed_accounts( - &IndexKey::ProgramId(solana_stake_program::id()), + &IndexKey::ProgramId(stake::id()), // The program-id account index checks for Account owner on inclusion. However, due to // the current AccountsDb implementation, an account may remain in storage as a // zero-lamport Account::Default() after being wiped and reinitialized in later // updates. We include the redundant filter here to avoid returning these accounts. - |account| account.owner() == &solana_stake_program::id(), + |account| account.owner() == &stake::id(), ) } else { - bank.get_program_accounts(&solana_stake_program::id()) + bank.get_program_accounts(&stake::id()) }; for (pubkey, account) in stake_accounts.iter() { - let stake_account = StakeState::from(account).unwrap_or_default(); + let stake_account = StakeConverter::from(account).unwrap_or_default(); match stake_account { StakeState::Initialized(meta) => { if meta.lockup.is_in_force(&clock, None) @@ -195,8 +199,8 @@ mod tests { account::AccountSharedData, epoch_schedule::EpochSchedule, genesis_config::{ClusterType, GenesisConfig}, + stake::state::{Authorized, Lockup, Meta}, }; - use solana_stake_program::stake_state::{Authorized, Lockup, Meta, StakeState}; use std::{collections::BTreeMap, sync::Arc}; fn new_from_parent(parent: &Arc) -> Bank { @@ -235,7 +239,7 @@ mod tests { balance, &StakeState::Initialized(meta), std::mem::size_of::(), - &solana_stake_program::id(), + &stake::id(), ) .unwrap(); accounts.insert(pubkey, stake_account); diff --git a/runtime/src/stakes.rs b/runtime/src/stakes.rs index 69dc59053a50bc..c05d992ff3dce9 100644 --- a/runtime/src/stakes.rs +++ b/runtime/src/stakes.rs @@ -5,9 +5,13 @@ use solana_sdk::{ account::{AccountSharedData, ReadableAccount}, clock::Epoch, pubkey::Pubkey, + stake::{ + self, + state::{Delegation, StakeState}, + }, sysvar::stake_history::StakeHistory, }; -use solana_stake_program::stake_state::{new_stake_history_entry, Delegation, StakeState}; +use solana_stake_program::stake_state::{new_stake_history_entry, StakeConverter}; use solana_vote_program::vote_state::VoteState; use std::{borrow::Borrow, collections::HashMap}; @@ -111,7 +115,7 @@ impl Stakes { pub fn is_stake(account: &AccountSharedData) -> bool { solana_vote_program::check_id(account.owner()) - || solana_stake_program::check_id(account.owner()) + || stake::check_id(account.owner()) && account.data().len() >= std::mem::size_of::() } @@ -148,7 +152,7 @@ impl Stakes { .insert(*pubkey, (stake, ArcVoteAccount::from(account.clone()))); } old.map(|(_, account)| account) - } else if solana_stake_program::check_id(account.owner()) { + } else if stake::check_id(account.owner()) { // old_stake is stake lamports and voter_pubkey from the pre-store() version let old_stake = self.stake_delegations.get(pubkey).map(|delegation| { ( @@ -157,7 +161,7 @@ impl Stakes { ) }); - let delegation = StakeState::delegation_from(account); + let delegation = StakeConverter::delegation_from(account); let stake = delegation.map(|delegation| { ( @@ -308,7 +312,7 @@ pub mod tests { stakes.store(&vote_pubkey, &vote_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeState::stake_from(&stake_account).unwrap(); + let stake = StakeConverter::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); assert!(vote_accounts.get(&vote_pubkey).is_some()); @@ -332,7 +336,7 @@ pub mod tests { // activate more let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey); stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeState::stake_from(&stake_account).unwrap(); + let stake = StakeConverter::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); assert!(vote_accounts.get(&vote_pubkey).is_some()); @@ -463,7 +467,7 @@ pub mod tests { // delegates to vote_pubkey stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeState::stake_from(&stake_account).unwrap(); + let stake = StakeConverter::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); @@ -523,7 +527,7 @@ pub mod tests { stakes.store(&vote_pubkey, &vote_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeState::stake_from(&stake_account).unwrap(); + let stake = StakeConverter::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); @@ -564,7 +568,7 @@ pub mod tests { // not a stake account, and whacks above entry stakes.store( &stake_pubkey, - &AccountSharedData::new(1, 0, &solana_stake_program::id()), + &AccountSharedData::new(1, 0, &stake::id()), true, true, ); diff --git a/runtime/tests/stake.rs b/runtime/tests/stake.rs index 5f1d36bd1d41e9..2274735bc524b1 100644 --- a/runtime/tests/stake.rs +++ b/runtime/tests/stake.rs @@ -11,12 +11,13 @@ use solana_sdk::{ message::Message, pubkey::Pubkey, signature::{Keypair, Signer}, + stake::{ + self, instruction as stake_instruction, + state::{Authorized, Lockup, StakeState}, + }, sysvar::{self, stake_history::StakeHistory}, }; -use solana_stake_program::{ - stake_instruction::{self}, - stake_state::{self, StakeState}, -}; +use solana_stake_program::stake_state::StakeConverter; use solana_vote_program::{ vote_instruction, vote_state::{Vote, VoteInit, VoteState, VoteStateVersions}, @@ -69,7 +70,7 @@ fn fill_epoch_with_votes( } fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool { - let stake = StakeState::stake_from(&bank.get_account(stake_pubkey).unwrap()).unwrap(); + let stake = StakeConverter::stake_from(&bank.get_account(stake_pubkey).unwrap()).unwrap(); stake.delegation.stake == stake.stake( @@ -85,7 +86,7 @@ fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool { } fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 { - StakeState::stake_from(&bank.get_account(stake_pubkey).unwrap()) + StakeConverter::stake_from(&bank.get_account(stake_pubkey).unwrap()) .unwrap() .stake( bank.epoch(), @@ -117,10 +118,9 @@ fn test_stake_create_and_split_single_signature() { let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); - let stake_address = - Pubkey::create_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap(); + let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::id()).unwrap(); - let authorized = stake_state::Authorized::auto(&staker_pubkey); + let authorized = Authorized::auto(&staker_pubkey); let lamports = 1_000_000; @@ -132,7 +132,7 @@ fn test_stake_create_and_split_single_signature() { &staker_pubkey, // base "stake", // seed &authorized, - &stake_state::Lockup::default(), + &Lockup::default(), lamports, ), Some(&staker_pubkey), @@ -145,8 +145,7 @@ fn test_stake_create_and_split_single_signature() { // split the stake let split_stake_address = - Pubkey::create_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id()) - .unwrap(); + Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::id()).unwrap(); // Test split let message = Message::new( &stake_instruction::split_with_seed( @@ -188,10 +187,9 @@ fn test_stake_create_and_split_to_existing_system_account() { let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); - let stake_address = - Pubkey::create_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap(); + let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::id()).unwrap(); - let authorized = stake_state::Authorized::auto(&staker_pubkey); + let authorized = Authorized::auto(&staker_pubkey); let lamports = 1_000_000; @@ -203,7 +201,7 @@ fn test_stake_create_and_split_to_existing_system_account() { &staker_pubkey, // base "stake", // seed &authorized, - &stake_state::Lockup::default(), + &Lockup::default(), lamports, ), Some(&staker_pubkey), @@ -214,8 +212,7 @@ fn test_stake_create_and_split_to_existing_system_account() { .expect("failed to create and delegate stake account"); let split_stake_address = - Pubkey::create_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id()) - .unwrap(); + Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::id()).unwrap(); // First, put a system account where we want the new stake account let existing_lamports = 42; @@ -290,7 +287,7 @@ fn test_stake_account_lifetime() { .send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message) .expect("failed to create vote account"); - let authorized = stake_state::Authorized::auto(&stake_pubkey); + let authorized = Authorized::auto(&stake_pubkey); // Create stake account and delegate to vote account let message = Message::new( &stake_instruction::create_account_and_delegate_stake( @@ -298,7 +295,7 @@ fn test_stake_account_lifetime() { &stake_pubkey, &vote_pubkey, &authorized, - &stake_state::Lockup::default(), + &Lockup::default(), 1_000_000, ), Some(&mint_pubkey), @@ -516,8 +513,7 @@ fn test_create_stake_account_from_seed() { let bank_client = BankClient::new_shared(&bank); let seed = "test-string"; - let stake_pubkey = - Pubkey::create_with_seed(&mint_pubkey, seed, &solana_stake_program::id()).unwrap(); + let stake_pubkey = Pubkey::create_with_seed(&mint_pubkey, seed, &stake::id()).unwrap(); // Create Vote Account let message = Message::new( @@ -538,7 +534,7 @@ fn test_create_stake_account_from_seed() { .send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message) .expect("failed to create vote account"); - let authorized = stake_state::Authorized::auto(&mint_pubkey); + let authorized = Authorized::auto(&mint_pubkey); // Create stake account and delegate to vote account let message = Message::new( &stake_instruction::create_account_with_seed_and_delegate_stake( @@ -548,7 +544,7 @@ fn test_create_stake_account_from_seed() { seed, &vote_pubkey, &authorized, - &stake_state::Lockup::default(), + &Lockup::default(), 1_000_000, ), Some(&mint_pubkey), From f688eff94de09b4beaa3f6336580349a251c4df6 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Sat, 12 Jun 2021 01:07:37 +0200 Subject: [PATCH 04/14] Update all other parts --- Cargo.lock | 6 --- core/Cargo.toml | 2 +- .../developing/runtime-facilities/programs.md | 2 +- genesis/src/main.rs | 3 +- genesis/src/stakes.rs | 32 +++++++----- ledger-tool/src/main.rs | 8 +-- ledger/Cargo.toml | 2 - ledger/src/staking_utils.rs | 8 +-- local-cluster/src/local_cluster.rs | 13 ++--- local-cluster/tests/local_cluster.rs | 2 +- perf/Cargo.toml | 1 - perf/src/test_tx.rs | 18 ++++--- program-test/Cargo.toml | 1 - program-test/tests/warp.rs | 8 +-- rpc/Cargo.toml | 2 +- rpc/src/rpc.rs | 2 +- rpc/src/rpc_pubsub.rs | 13 ++--- rpc/src/rpc_subscriptions.rs | 12 ++--- stake-accounts/src/main.rs | 8 ++- stake-accounts/src/stake_accounts.rs | 31 ++++++----- stake-monitor/Cargo.toml | 1 - stake-monitor/src/lib.rs | 14 +++-- tokens/Cargo.toml | 1 - tokens/src/commands.rs | 14 ++--- transaction-status/Cargo.toml | 1 - transaction-status/src/parse_instruction.rs | 4 +- transaction-status/src/parse_stake.rs | 51 +++++++++---------- 27 files changed, 133 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7327440adc3b0e..ba0bbb1a4507ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4904,7 +4904,6 @@ dependencies = [ "solana-rayon-threadlimit", "solana-runtime", "solana-sdk", - "solana-stake-program", "solana-storage-bigtable", "solana-storage-proto", "solana-transaction-status", @@ -5141,7 +5140,6 @@ dependencies = [ "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", - "solana-stake-program", ] [[package]] @@ -5269,7 +5267,6 @@ dependencies = [ "solana-logger 1.8.0", "solana-runtime", "solana-sdk", - "solana-stake-program", "solana-vote-program", "thiserror", "tokio 1.6.1", @@ -5527,7 +5524,6 @@ dependencies = [ "solana-metrics", "solana-rpc", "solana-sdk", - "solana-stake-program", "solana-transaction-status", "solana-version", "tempfile", @@ -5664,7 +5660,6 @@ dependencies = [ "solana-remote-wallet", "solana-runtime", "solana-sdk", - "solana-stake-program", "solana-transaction-status", "solana-version", "spl-associated-token-account", @@ -5688,7 +5683,6 @@ dependencies = [ "solana-account-decoder", "solana-runtime", "solana-sdk", - "solana-stake-program", "solana-vote-program", "spl-associated-token-account", "spl-memo", diff --git a/core/Cargo.toml b/core/Cargo.toml index d797cd518f6bf1..d4903cfd1f9c95 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -63,7 +63,6 @@ solana-runtime = { path = "../runtime", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } solana-frozen-abi = { path = "../frozen-abi", version = "=1.8.0" } solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-streamer = { path = "../streamer", version = "=1.8.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" } solana-vote-program = { path = "../programs/vote", version = "=1.8.0" } @@ -80,6 +79,7 @@ num_cpus = "1.13.0" reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] } serde_json = "1.0.56" serial_test = "0.5.1" +solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-version = { path = "../version", version = "=1.8.0" } symlink = "0.1.0" systemstat = "0.1.7" diff --git a/docs/src/developing/runtime-facilities/programs.md b/docs/src/developing/runtime-facilities/programs.md index 74cda44ee06285..c66afe9841fb20 100644 --- a/docs/src/developing/runtime-facilities/programs.md +++ b/docs/src/developing/runtime-facilities/programs.md @@ -41,7 +41,7 @@ Create and manage accounts representing stake and rewards for delegations to validators. - Program id: `Stake11111111111111111111111111111111111111` -- Instructions: [StakeInstruction](https://docs.rs/solana-stake-program/VERSION_FOR_DOCS_RS/solana_stake_program/stake_instruction/enum.StakeInstruction.html) +- Instructions: [StakeInstruction](https://docs.rs/solana-sdk/VERSION_FOR_DOCS_RS/solana_sdk/stake/instruction/enum.StakeInstruction.html) ## Vote Program diff --git a/genesis/src/main.rs b/genesis/src/main.rs index 63a83930e9bf49..cb4ed366c75657 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -26,9 +26,10 @@ use solana_sdk::{ pubkey::Pubkey, rent::Rent, signature::{Keypair, Signer}, + stake::state::StakeState, system_program, timing, }; -use solana_stake_program::stake_state::{self, StakeState}; +use solana_stake_program::stake_state; use solana_vote_program::vote_state::{self, VoteState}; use std::{ collections::HashMap, diff --git a/genesis/src/stakes.rs b/genesis/src/stakes.rs index db9104b7ebf8ef..898e8e507ead45 100644 --- a/genesis/src/stakes.rs +++ b/genesis/src/stakes.rs @@ -1,15 +1,22 @@ //! stakes generator -use crate::{ - address_generator::AddressGenerator, - unlocks::{UnlockInfo, Unlocks}, -}; -use solana_sdk::{ - account::Account, clock::Slot, genesis_config::GenesisConfig, pubkey::Pubkey, system_program, - timing::years_as_slots, -}; -use solana_stake_program::{ - self, - stake_state::{create_lockup_stake_account, Authorized, Lockup, StakeState}, +use { + crate::{ + address_generator::AddressGenerator, + unlocks::{UnlockInfo, Unlocks}, + }, + solana_sdk::{ + account::Account, + clock::Slot, + genesis_config::GenesisConfig, + pubkey::Pubkey, + stake::{ + self, + state::{Authorized, Lockup, StakeState}, + }, + system_program, + timing::years_as_slots, + }, + solana_stake_program::stake_state::create_lockup_stake_account, }; #[derive(Debug)] @@ -98,8 +105,7 @@ pub fn create_and_add_stakes( genesis_config.ticks_per_slot, ); - let mut address_generator = - AddressGenerator::new(&authorized.staker, &solana_stake_program::id()); + let mut address_generator = AddressGenerator::new(&authorized.staker, &stake::id()); let stake_rent_reserve = StakeState::get_rent_exempt_reserve(&genesis_config.rent); diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index 1084e69047185d..875d93ed864669 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -44,9 +44,10 @@ use solana_sdk::{ pubkey::Pubkey, rent::Rent, shred_version::compute_shred_version, + stake::{self, state::StakeState}, system_program, }; -use solana_stake_program::stake_state::{self, PointValue, StakeState}; +use solana_stake_program::stake_state::{self, PointValue}; use solana_vote_program::{ self, vote_state::{self, VoteState}, @@ -2038,9 +2039,8 @@ fn main() { } if remove_stake_accounts { - for (address, mut account) in bank - .get_program_accounts(&solana_stake_program::id()) - .into_iter() + for (address, mut account) in + bank.get_program_accounts(&stake::id()).into_iter() { account.set_lamports(0); bank.store_account(&address, &account); diff --git a/ledger/Cargo.toml b/ledger/Cargo.toml index 84dc3fe11eeedc..ba63754fd97dfc 100644 --- a/ledger/Cargo.toml +++ b/ledger/Cargo.toml @@ -45,7 +45,6 @@ solana-perf = { path = "../perf", version = "=1.8.0" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.8.0" } solana-runtime = { path = "../runtime", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.8.0" } solana-storage-proto = { path = "../storage-proto", version = "=1.8.0" } solana-vote-program = { path = "../programs/vote", version = "=1.8.0" } @@ -74,7 +73,6 @@ features = ["lz4"] assert_matches = "1.3.0" matches = "0.1.6" solana-account-decoder = { path = "../account-decoder", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } [build-dependencies] rustc_version = "0.4" diff --git a/ledger/src/staking_utils.rs b/ledger/src/staking_utils.rs index 7b7c24bb968003..82d06ce3680519 100644 --- a/ledger/src/staking_utils.rs +++ b/ledger/src/staking_utils.rs @@ -74,13 +74,13 @@ pub(crate) mod tests { pubkey::Pubkey, signature::{Keypair, Signer}, signers::Signers, + stake::{ + instruction as stake_instruction, + state::{Authorized, Delegation, Lockup, Stake}, + }, sysvar::stake_history::{self, StakeHistory}, transaction::Transaction, }; - use solana_stake_program::{ - stake_instruction, - stake_state::{Authorized, Delegation, Lockup, Stake}, - }; use solana_vote_program::{ vote_instruction, vote_state::{VoteInit, VoteState, VoteStateVersions}, diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index 080adae3473929..90af1316551911 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -29,13 +29,14 @@ use solana_sdk::{ poh_config::PohConfig, pubkey::Pubkey, signature::{Keypair, Signer}, + stake::{ + config as stake_config, instruction as stake_instruction, + state::{Authorized, Lockup}, + }, system_transaction, transaction::Transaction, }; -use solana_stake_program::{ - config as stake_config, stake_instruction, - stake_state::{Authorized, Lockup, StakeState}, -}; +use solana_stake_program::{config::ConfigConverter, stake_state::StakeConverter}; use solana_vote_program::{ vote_instruction, vote_state::{VoteInit, VoteState}, @@ -190,7 +191,7 @@ impl LocalCluster { // Replace staking config genesis_config.add_account( stake_config::id(), - stake_config::create_account( + ConfigConverter::create_account( 1, &stake_config::Config { warmup_cooldown_rate: 1_000_000_000.0f64, @@ -568,7 +569,7 @@ impl LocalCluster { ) { (Ok(Some(stake_account)), Ok(Some(vote_account))) => { match ( - StakeState::stake_from(&stake_account), + StakeConverter::stake_from(&stake_account), VoteState::from(&vote_account), ) { (Some(stake_state), Some(vote_state)) => { diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index c227470fa6a455..d8c5a581293019 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -1402,7 +1402,7 @@ fn test_mainnet_beta_cluster_type() { for program_id in [ &solana_config_program::id(), &solana_sdk::system_program::id(), - &solana_stake_program::id(), + &solana_sdk::stake::id(), &solana_vote_program::id(), &solana_sdk::bpf_loader_deprecated::id(), &solana_sdk::bpf_loader::id(), diff --git a/perf/Cargo.toml b/perf/Cargo.toml index 197bb75da3a8a3..fd3394b633ae6a 100644 --- a/perf/Cargo.toml +++ b/perf/Cargo.toml @@ -23,7 +23,6 @@ solana-logger = { path = "../logger", version = "=1.8.0" } solana-metrics = { path = "../metrics", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } [lib] name = "solana_perf" diff --git a/perf/src/test_tx.rs b/perf/src/test_tx.rs index a571ec9f85cb98..fa23f009a45455 100644 --- a/perf/src/test_tx.rs +++ b/perf/src/test_tx.rs @@ -1,10 +1,12 @@ -use solana_sdk::hash::Hash; -use solana_sdk::instruction::CompiledInstruction; -use solana_sdk::signature::{Keypair, Signer}; -use solana_sdk::system_instruction::SystemInstruction; -use solana_sdk::system_program; -use solana_sdk::system_transaction; -use solana_sdk::transaction::Transaction; +use solana_sdk::{ + hash::Hash, + instruction::CompiledInstruction, + signature::{Keypair, Signer}, + stake, + system_instruction::SystemInstruction, + system_program, system_transaction, + transaction::Transaction, +}; pub fn test_tx() -> Transaction { let keypair1 = Keypair::new(); @@ -22,7 +24,7 @@ pub fn test_multisig_tx() -> Transaction { let transfer_instruction = SystemInstruction::Transfer { lamports }; - let program_ids = vec![system_program::id(), solana_stake_program::id()]; + let program_ids = vec![system_program::id(), stake::id()]; let instructions = vec![CompiledInstruction::new( 0, diff --git a/program-test/Cargo.toml b/program-test/Cargo.toml index e3dee598f43076..0db187166f20fc 100644 --- a/program-test/Cargo.toml +++ b/program-test/Cargo.toml @@ -29,4 +29,3 @@ tokio = { version = "1", features = ["full"] } [dev-dependencies] assert_matches = "1.3.0" -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } diff --git a/program-test/tests/warp.rs b/program-test/tests/warp.rs index 9ed46aac1038b9..f3dee52f45d9c2 100644 --- a/program-test/tests/warp.rs +++ b/program-test/tests/warp.rs @@ -12,6 +12,10 @@ use { pubkey::Pubkey, rent::Rent, signature::{Keypair, Signer}, + stake::{ + instruction as stake_instruction, + state::{Authorized, Lockup, StakeState}, + }, system_instruction, system_program, sysvar::{ clock, @@ -20,10 +24,6 @@ use { }, transaction::{Transaction, TransactionError}, }, - solana_stake_program::{ - stake_instruction, - stake_state::{Authorized, Lockup, StakeState}, - }, solana_vote_program::{ vote_instruction, vote_state::{VoteInit, VoteState}, diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 4b101ef776e5d0..0fc953abd3cd69 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -38,7 +38,6 @@ solana-perf = { path = "../perf", version = "=1.8.0" } solana-poh = { path = "../poh", version = "=1.8.0" } solana-runtime = { path = "../runtime", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.8.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" } solana-version = { path = "../version", version = "=1.8.0" } @@ -52,6 +51,7 @@ tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to sta serial_test = "0.4.0" solana-logger = { path = "../logger", version = "=1.8.0" } solana-net-utils = { path = "../net-utils", version = "=1.8.0" } +solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } symlink = "0.1.0" [lib] diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index ed9822944f718f..3643fc7da1b5b4 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -62,12 +62,12 @@ use { pubkey::Pubkey, sanitize::Sanitize, signature::{Keypair, Signature, Signer}, + stake::state::StakeState, stake_history::StakeHistory, system_instruction, sysvar::stake_history, transaction::{self, Transaction}, }, - solana_stake_program::stake_state::StakeState, solana_transaction_status::{ EncodedConfirmedTransaction, Reward, RewardType, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding, diff --git a/rpc/src/rpc_pubsub.rs b/rpc/src/rpc_pubsub.rs index 7ab789a87de649..7a41fed3dcc034 100644 --- a/rpc/src/rpc_pubsub.rs +++ b/rpc/src/rpc_pubsub.rs @@ -569,13 +569,14 @@ mod tests { message::Message, pubkey::Pubkey, signature::{Keypair, Signer}, + stake::{ + self, instruction as stake_instruction, + state::{Authorized, Lockup, StakeAuthorize}, + }, system_instruction, system_program, system_transaction, transaction::{self, Transaction}, }, - solana_stake_program::{ - self, stake_instruction, - stake_state::{Authorized, Lockup, StakeAuthorize, StakeState}, - }, + solana_stake_program::stake_state::StakeConverter, solana_vote_program::vote_state::Vote, std::{ sync::{atomic::AtomicBool, RwLock}, @@ -791,7 +792,7 @@ mod tests { let stake_authority = Keypair::new(); let from = Keypair::new(); let stake_account = Keypair::new(); - let stake_program_id = solana_stake_program::id(); + let stake_program_id = stake::id(); let bank = Bank::new(&genesis_config); let blockhash = bank.last_blockhash(); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); @@ -887,7 +888,7 @@ mod tests { let bank = bank_forks.read().unwrap()[1].clone(); let account = bank.get_account(&stake_account.pubkey()).unwrap(); assert_eq!( - StakeState::authorized_from(&account).unwrap().staker, + StakeConverter::authorized_from(&account).unwrap().staker, new_stake_authority ); } diff --git a/rpc/src/rpc_subscriptions.rs b/rpc/src/rpc_subscriptions.rs index d2aedd5eadf185..25f04f71c7bc98 100644 --- a/rpc/src/rpc_subscriptions.rs +++ b/rpc/src/rpc_subscriptions.rs @@ -1343,7 +1343,7 @@ pub(crate) mod tests { solana_sdk::{ message::Message, signature::{Keypair, Signer}, - system_instruction, system_program, system_transaction, + stake, system_instruction, system_program, system_transaction, transaction::Transaction, }, std::{fmt::Debug, sync::mpsc::channel}, @@ -1544,7 +1544,7 @@ pub(crate) mod tests { blockhash, 1, 16, - &solana_stake_program::id(), + &stake::id(), ); bank_forks .write() @@ -1567,7 +1567,7 @@ pub(crate) mod tests { optimistically_confirmed_bank, ); subscriptions.add_program_subscription( - solana_stake_program::id(), + stake::id(), Some(RpcProgramAccountsConfig { account_config: RpcAccountInfoConfig { commitment: Some(CommitmentConfig::processed()), @@ -1584,7 +1584,7 @@ pub(crate) mod tests { .program_subscriptions .read() .unwrap() - .contains_key(&solana_stake_program::id())); + .contains_key(&stake::id())); subscriptions.notify_subscribers(CommitmentSlots::default()); let (response, _) = robust_poll_or_panic(transport_receiver); @@ -1616,7 +1616,7 @@ pub(crate) mod tests { .program_subscriptions .read() .unwrap() - .contains_key(&solana_stake_program::id())); + .contains_key(&stake::id())); } #[test] @@ -2044,7 +2044,7 @@ pub(crate) mod tests { blockhash, 1, 16, - &solana_stake_program::id(), + &stake::id(), ); // Add the transaction to the 1st bank and then freeze the bank diff --git a/stake-accounts/src/main.rs b/stake-accounts/src/main.rs index 37a4da0cb8be18..bf4d7afd49e40f 100644 --- a/stake-accounts/src/main.rs +++ b/stake-accounts/src/main.rs @@ -16,12 +16,10 @@ use solana_sdk::{ pubkey::Pubkey, signature::{unique_signers, Signature, Signer}, signers::Signers, + stake::{instruction::LockupArgs, state::Lockup}, transaction::Transaction, }; -use solana_stake_program::{ - stake_instruction::LockupArgs, - stake_state::{Lockup, StakeState}, -}; +use solana_stake_program::stake_state::StakeConverter; use std::env; use std::error::Error; @@ -52,7 +50,7 @@ fn get_balances( fn get_lockup(client: &RpcClient, address: &Pubkey) -> Result { client .get_account(address) - .map(|account| StakeState::lockup_from(&account).unwrap()) + .map(|account| StakeConverter::lockup_from(&account).unwrap()) } fn get_lockups( diff --git a/stake-accounts/src/stake_accounts.rs b/stake-accounts/src/stake_accounts.rs index 86dd6f956954a4..09bb51a6e0cf8a 100644 --- a/stake-accounts/src/stake_accounts.rs +++ b/stake-accounts/src/stake_accounts.rs @@ -1,16 +1,20 @@ use solana_sdk::{ - clock::SECONDS_PER_DAY, instruction::Instruction, message::Message, pubkey::Pubkey, -}; -use solana_stake_program::{ - stake_instruction::{self, LockupArgs}, - stake_state::{Authorized, Lockup, StakeAuthorize}, + clock::SECONDS_PER_DAY, + instruction::Instruction, + message::Message, + pubkey::Pubkey, + stake::{ + self, + instruction::{self as stake_instruction, LockupArgs}, + state::{Authorized, Lockup, StakeAuthorize}, + }, }; const DAYS_PER_YEAR: f64 = 365.25; const SECONDS_PER_YEAR: i64 = (SECONDS_PER_DAY as f64 * DAYS_PER_YEAR) as i64; pub(crate) fn derive_stake_account_address(base_pubkey: &Pubkey, i: usize) -> Pubkey { - Pubkey::create_with_seed(base_pubkey, &i.to_string(), &solana_stake_program::id()).unwrap() + Pubkey::create_with_seed(base_pubkey, &i.to_string(), &stake::id()).unwrap() } // Return derived addresses @@ -284,8 +288,9 @@ mod tests { client::SyncClient, genesis_config::create_genesis_config, signature::{Keypair, Signer}, + stake::state::StakeState, }; - use solana_stake_program::stake_state::StakeState; + use solana_stake_program::stake_state::StakeConverter; fn create_bank(lamports: u64) -> (Bank, Keypair, u64) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); @@ -338,7 +343,7 @@ mod tests { let address = derive_stake_account_address(&base_pubkey, i); let account = AccountSharedData::from(client.get_account(&address).unwrap().unwrap()); - (address, StakeState::lockup_from(&account).unwrap()) + (address, StakeConverter::lockup_from(&account).unwrap()) }) .collect() } @@ -375,7 +380,7 @@ mod tests { let account = get_account_at(&bank_client, &base_pubkey, 0); assert_eq!(account.lamports(), lamports); - let authorized = StakeState::authorized_from(&account).unwrap(); + let authorized = StakeConverter::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, stake_authority_pubkey); assert_eq!(authorized.withdrawer, withdraw_authority_pubkey); } @@ -437,7 +442,7 @@ mod tests { } let account = get_account_at(&bank_client, &base_pubkey, 0); - let authorized = StakeState::authorized_from(&account).unwrap(); + let authorized = StakeConverter::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, new_stake_authority_pubkey); assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey); } @@ -493,7 +498,7 @@ mod tests { } let account = get_account_at(&bank_client, &base_pubkey, 0); - let lockup = StakeState::lockup_from(&account).unwrap(); + let lockup = StakeConverter::lockup_from(&account).unwrap(); assert_eq!(lockup.unix_timestamp, 1); assert_eq!(lockup.epoch, 0); @@ -586,7 +591,7 @@ mod tests { // Ensure the new accounts are duplicates of the previous ones. let account = get_account_at(&bank_client, &new_base_pubkey, 0); - let authorized = StakeState::authorized_from(&account).unwrap(); + let authorized = StakeConverter::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, stake_authority_pubkey); assert_eq!(authorized.withdrawer, withdraw_authority_pubkey); } @@ -655,7 +660,7 @@ mod tests { // Ensure the new accounts have the new authorities. let account = get_account_at(&bank_client, &new_base_pubkey, 0); - let authorized = StakeState::authorized_from(&account).unwrap(); + let authorized = StakeConverter::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, new_stake_authority_pubkey); assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey); } diff --git a/stake-monitor/Cargo.toml b/stake-monitor/Cargo.toml index 9b576cd36e8bb7..202373f24386d1 100644 --- a/stake-monitor/Cargo.toml +++ b/stake-monitor/Cargo.toml @@ -22,7 +22,6 @@ solana-logger = { path = "../logger", version = "=1.8.0" } solana-metrics = { path = "../metrics", version = "=1.8.0" } solana-rpc = { path = "../rpc", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" } solana-version = { path = "../version", version = "=1.8.0" } diff --git a/stake-monitor/src/lib.rs b/stake-monitor/src/lib.rs index c6a27e7865d4d9..6dff4a1721f10c 100644 --- a/stake-monitor/src/lib.rs +++ b/stake-monitor/src/lib.rs @@ -4,10 +4,14 @@ use serde::{Deserialize, Serialize}; use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient}; use solana_metrics::{datapoint_error, datapoint_info}; use solana_sdk::{ - clock::Slot, native_token::LAMPORTS_PER_SOL, program_utils::limited_deserialize, - pubkey::Pubkey, signature::Signature, transaction::Transaction, + clock::Slot, + native_token::LAMPORTS_PER_SOL, + program_utils::limited_deserialize, + pubkey::Pubkey, + signature::Signature, + stake::{self, instruction::StakeInstruction, state::Lockup}, + transaction::Transaction, }; -use solana_stake_program::{stake_instruction::StakeInstruction, stake_state::Lockup}; use solana_transaction_status::{ EncodedConfirmedBlock, UiTransactionEncoding, UiTransactionStatusMeta, }; @@ -78,7 +82,7 @@ fn process_transaction( // Look for stake operations for instruction in message.instructions.iter().rev() { let program_pubkey = message.account_keys[instruction.program_id_index as usize]; - if program_pubkey != solana_stake_program::id() { + if program_pubkey != stake::id() { continue; } @@ -368,10 +372,10 @@ mod test { message::Message, native_token::sol_to_lamports, signature::{Keypair, Signer}, + stake::{instruction as stake_instruction, state::Authorized}, system_transaction, transaction::Transaction, }; - use solana_stake_program::{stake_instruction, stake_state::Authorized}; #[test] #[serial] diff --git a/tokens/Cargo.toml b/tokens/Cargo.toml index c9792e8ef4940e..2264c2264099cd 100644 --- a/tokens/Cargo.toml +++ b/tokens/Cargo.toml @@ -27,7 +27,6 @@ solana-client = { path = "../client", version = "=1.8.0" } solana-remote-wallet = { path = "../remote-wallet", version = "=1.8.0" } solana-runtime = { path = "../runtime", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" } solana-version = { path = "../version", version = "=1.8.0" } spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2" } diff --git a/tokens/src/commands.rs b/tokens/src/commands.rs index d512bf90fe2d02..67dbc2bbe53fba 100644 --- a/tokens/src/commands.rs +++ b/tokens/src/commands.rs @@ -27,13 +27,13 @@ use solana_sdk::{ message::Message, native_token::{lamports_to_sol, sol_to_lamports}, signature::{unique_signers, Signature, Signer}, + stake::{ + instruction::{self as stake_instruction, LockupArgs}, + state::{Authorized, Lockup, StakeAuthorize}, + }, system_instruction, transaction::Transaction, }; -use solana_stake_program::{ - stake_instruction::{self, LockupArgs}, - stake_state::{Authorized, Lockup, StakeAuthorize}, -}; use solana_transaction_status::TransactionStatus; use spl_associated_token_account_v1_0::get_associated_token_address; use spl_token_v2_0::solana_program::program_error::ProgramError; @@ -1204,8 +1204,10 @@ pub fn test_process_distribute_stake_with_client(client: &RpcClient, sender_keyp mod tests { use super::*; use solana_core::test_validator::TestValidator; - use solana_sdk::signature::{read_keypair_file, write_keypair_file, Signer}; - use solana_stake_program::stake_instruction::StakeInstruction; + use solana_sdk::{ + signature::{read_keypair_file, write_keypair_file, Signer}, + stake::instruction::StakeInstruction, + }; use solana_transaction_status::TransactionConfirmationStatus; #[test] diff --git a/transaction-status/Cargo.toml b/transaction-status/Cargo.toml index ebabf6abe8960a..b84efbfc0f5b2c 100644 --- a/transaction-status/Cargo.toml +++ b/transaction-status/Cargo.toml @@ -21,7 +21,6 @@ serde_json = "1.0.64" solana-account-decoder = { path = "../account-decoder", version = "=1.8.0" } solana-sdk = { path = "../sdk", version = "=1.8.0" } solana-runtime = { path = "../runtime", version = "=1.8.0" } -solana-stake-program = { path = "../programs/stake", version = "=1.8.0" } solana-vote-program = { path = "../programs/vote", version = "=1.8.0" } spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2", features = ["no-entrypoint"] } spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] } diff --git a/transaction-status/src/parse_instruction.rs b/transaction-status/src/parse_instruction.rs index 4e2874ee54bb67..82a06d5c03accf 100644 --- a/transaction-status/src/parse_instruction.rs +++ b/transaction-status/src/parse_instruction.rs @@ -9,7 +9,7 @@ use crate::{ use inflector::Inflector; use serde_json::Value; use solana_account_decoder::parse_token::spl_token_id_v2_0; -use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, system_program}; +use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, stake, system_program}; use std::{collections::HashMap, str::from_utf8}; use thiserror::Error; @@ -19,7 +19,7 @@ lazy_static! { static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id(); static ref MEMO_V1_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::v1::id().to_bytes()); static ref MEMO_V3_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::id().to_bytes()); - static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id(); + static ref STAKE_PROGRAM_ID: Pubkey = stake::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id(); diff --git a/transaction-status/src/parse_stake.rs b/transaction-status/src/parse_stake.rs index 1f733459e3aeb5..d6a6c2332ca990 100644 --- a/transaction-status/src/parse_stake.rs +++ b/transaction-status/src/parse_stake.rs @@ -3,8 +3,9 @@ use crate::parse_instruction::{ }; use bincode::deserialize; use serde_json::{json, Map}; -use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey}; -use solana_stake_program::stake_instruction::StakeInstruction; +use solana_sdk::{ + instruction::CompiledInstruction, pubkey::Pubkey, stake::instruction::StakeInstruction, +}; pub fn parse_stake( instruction: &CompiledInstruction, @@ -195,10 +196,13 @@ fn check_num_stake_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInst #[cfg(test)] mod test { use super::*; - use solana_sdk::{message::Message, pubkey::Pubkey}; - use solana_stake_program::{ - stake_instruction::{self, LockupArgs}, - stake_state::{Authorized, Lockup, StakeAuthorize}, + use solana_sdk::{ + message::Message, + pubkey::Pubkey, + stake::{ + instruction::{self, LockupArgs}, + state::{Authorized, Lockup, StakeAuthorize}, + }, }; #[test] @@ -221,7 +225,7 @@ mod test { let lamports = 55; let instructions = - stake_instruction::create_account(&keys[0], &keys[1], &authorized, &lockup, lamports); + instruction::create_account(&keys[0], &keys[1], &authorized, &lockup, lamports); let message = Message::new(&instructions, None); assert_eq!( parse_stake(&message.instructions[1], &keys[0..3]).unwrap(), @@ -244,13 +248,8 @@ mod test { ); assert!(parse_stake(&message.instructions[1], &keys[0..2]).is_err()); - let instruction = stake_instruction::authorize( - &keys[1], - &keys[0], - &keys[3], - StakeAuthorize::Staker, - None, - ); + let instruction = + instruction::authorize(&keys[1], &keys[0], &keys[3], StakeAuthorize::Staker, None); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..3]).unwrap(), @@ -267,7 +266,7 @@ mod test { ); assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err()); - let instruction = stake_instruction::authorize( + let instruction = instruction::authorize( &keys[1], &keys[0], &keys[3], @@ -291,7 +290,7 @@ mod test { ); assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err()); - let instruction = stake_instruction::delegate_stake(&keys[1], &keys[0], &keys[2]); + let instruction = instruction::delegate_stake(&keys[1], &keys[0], &keys[2]); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..6]).unwrap(), @@ -313,7 +312,7 @@ mod test { // * split account (signer, allocate + assign first) // * stake authority (signer) // * stake account - let instructions = stake_instruction::split(&keys[2], &keys[1], lamports, &keys[0]); + let instructions = instruction::split(&keys[2], &keys[1], lamports, &keys[0]); let message = Message::new(&instructions, None); assert_eq!( parse_stake(&message.instructions[2], &keys[0..3]).unwrap(), @@ -329,7 +328,7 @@ mod test { ); assert!(parse_stake(&message.instructions[2], &keys[0..2]).is_err()); - let instruction = stake_instruction::withdraw(&keys[1], &keys[0], &keys[2], lamports, None); + let instruction = instruction::withdraw(&keys[1], &keys[0], &keys[2], lamports, None); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..5]).unwrap(), @@ -346,7 +345,7 @@ mod test { } ); let instruction = - stake_instruction::withdraw(&keys[2], &keys[0], &keys[3], lamports, Some(&keys[1])); + instruction::withdraw(&keys[2], &keys[0], &keys[3], lamports, Some(&keys[1])); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..6]).unwrap(), @@ -365,7 +364,7 @@ mod test { ); assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err()); - let instruction = stake_instruction::deactivate_stake(&keys[1], &keys[0]); + let instruction = instruction::deactivate_stake(&keys[1], &keys[0]); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..3]).unwrap(), @@ -380,7 +379,7 @@ mod test { ); assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err()); - let instructions = stake_instruction::merge(&keys[1], &keys[0], &keys[2]); + let instructions = instruction::merge(&keys[1], &keys[0], &keys[2]); let message = Message::new(&instructions, None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..5]).unwrap(), @@ -398,7 +397,7 @@ mod test { assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err()); let seed = "test_seed"; - let instruction = stake_instruction::authorize_with_seed( + let instruction = instruction::authorize_with_seed( &keys[1], &keys[0], seed.to_string(), @@ -425,7 +424,7 @@ mod test { ); assert!(parse_stake(&message.instructions[0], &keys[0..1]).is_err()); - let instruction = stake_instruction::authorize_with_seed( + let instruction = instruction::authorize_with_seed( &keys[1], &keys[0], seed.to_string(), @@ -470,7 +469,7 @@ mod test { epoch: None, custodian: None, }; - let instruction = stake_instruction::set_lockup(&keys[1], &lockup, &keys[0]); + let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..2]).unwrap(), @@ -491,7 +490,7 @@ mod test { epoch: Some(epoch), custodian: None, }; - let instruction = stake_instruction::set_lockup(&keys[1], &lockup, &keys[0]); + let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..2]).unwrap(), @@ -513,7 +512,7 @@ mod test { epoch: Some(epoch), custodian: Some(custodian), }; - let instruction = stake_instruction::set_lockup(&keys[1], &lockup, &keys[0]); + let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]); let message = Message::new(&[instruction], None); assert_eq!( parse_stake(&message.instructions[0], &keys[0..2]).unwrap(), From abf28a50a38a59009096a358d0298f388ca709de Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Sat, 12 Jun 2021 01:26:01 +0200 Subject: [PATCH 05/14] Commit Cargo.lock changes in programs/bpf --- programs/bpf/Cargo.lock | 3 --- 1 file changed, 3 deletions(-) diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index b979dbf876a26c..a5b16b60ea8ec2 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -2730,7 +2730,6 @@ dependencies = [ "serde_json", "solana-config-program", "solana-sdk", - "solana-stake-program", "solana-vote-program", "spl-token", "thiserror", @@ -3142,7 +3141,6 @@ dependencies = [ "solana-clap-utils", "solana-client", "solana-sdk", - "solana-stake-program", "solana-transaction-status", "solana-vote-program", "spl-memo", @@ -3641,7 +3639,6 @@ dependencies = [ "solana-account-decoder", "solana-runtime", "solana-sdk", - "solana-stake-program", "solana-vote-program", "spl-associated-token-account", "spl-memo", From 03375de9cc32a8ba85d0c0f9481e371c7f235d18 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Sat, 12 Jun 2021 01:37:09 +0200 Subject: [PATCH 06/14] Update cli stake instruction import --- cli/src/stake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/stake.rs b/cli/src/stake.rs index 1f48c3e22d3f86..8cada1f9cd3962 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -38,7 +38,7 @@ use solana_sdk::{ pubkey::Pubkey, stake::{ self, - instruction::{self, LockupArgs, StakeError}, + instruction::{self as stake_instruction, LockupArgs, StakeError}, state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState}, }, system_instruction::SystemError, From 09057c644e7949efada86ac3be33d594a3862399 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Sat, 12 Jun 2021 01:52:13 +0200 Subject: [PATCH 07/14] Allow integer arithmetic --- sdk/program/src/stake/state.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/program/src/stake/state.rs b/sdk/program/src/stake/state.rs index ec4c35878107cb..ed3096d0054120 100644 --- a/sdk/program/src/stake/state.rs +++ b/sdk/program/src/stake/state.rs @@ -1,3 +1,4 @@ +#![allow(clippy::integer_arithmetic)] use { crate::{ clock::{Clock, Epoch, UnixTimestamp}, From 65878f34f0295e255df058bd4394ba4921df83e1 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 14 Jun 2021 14:21:22 +0200 Subject: [PATCH 08/14] Update ABI digest --- runtime/src/serde_snapshot/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/serde_snapshot/tests.rs b/runtime/src/serde_snapshot/tests.rs index 40f727eadda27f..6d8436f313e80c 100644 --- a/runtime/src/serde_snapshot/tests.rs +++ b/runtime/src/serde_snapshot/tests.rs @@ -293,7 +293,7 @@ mod test_bank_serialize { // This some what long test harness is required to freeze the ABI of // Bank's serialization due to versioned nature - #[frozen_abi(digest = "DuRGntVwLGNAv5KooafUSpxk67BPAx2yC7Z8A9c8wr2G")] + #[frozen_abi(digest = "6msodEzE7YzFtorBhiP6ax4PKBaPZTkmYdGAdpoxLCvV")] #[derive(Serialize, AbiExample)] pub struct BankAbiTestWrapperFuture { #[serde(serialize_with = "wrapper_future")] From fcf344d0a8932008e30d277d97c483077309f496 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 14 Jun 2021 16:56:00 +0200 Subject: [PATCH 09/14] Bump rust mem instruction count --- programs/bpf/tests/programs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 3a5806d091163f..1ceeb39f8f625c 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1297,7 +1297,7 @@ fn assert_instruction_count() { ("solana_bpf_rust_external_spend", 504), ("solana_bpf_rust_iter", 724), ("solana_bpf_rust_many_args", 233), - ("solana_bpf_rust_mem", 3096), + ("solana_bpf_rust_mem", 3117), ("solana_bpf_rust_membuiltins", 4065), ("solana_bpf_rust_noop", 478), ("solana_bpf_rust_param_passing", 46), From 0d298a952f03744a425632b6e180ccee33e2bc06 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 14 Jun 2021 21:40:58 +0200 Subject: [PATCH 10/14] Remove useless structs --- local-cluster/src/local_cluster.rs | 6 +- programs/stake/src/config.rs | 40 +- programs/stake/src/stake_instruction.rs | 19 +- programs/stake/src/stake_state.rs | 689 +++++++++++------------- rpc/src/rpc_pubsub.rs | 4 +- runtime/src/non_circulating_supply.rs | 4 +- runtime/src/stakes.rs | 14 +- runtime/tests/stake.rs | 6 +- stake-accounts/src/main.rs | 4 +- stake-accounts/src/stake_accounts.rs | 14 +- 10 files changed, 353 insertions(+), 447 deletions(-) diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index 90af1316551911..d455daefbbeba8 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -36,7 +36,7 @@ use solana_sdk::{ system_transaction, transaction::Transaction, }; -use solana_stake_program::{config::ConfigConverter, stake_state::StakeConverter}; +use solana_stake_program::{config::create_account as create_stake_config_account, stake_state}; use solana_vote_program::{ vote_instruction, vote_state::{VoteInit, VoteState}, @@ -191,7 +191,7 @@ impl LocalCluster { // Replace staking config genesis_config.add_account( stake_config::id(), - ConfigConverter::create_account( + create_stake_config_account( 1, &stake_config::Config { warmup_cooldown_rate: 1_000_000_000.0f64, @@ -569,7 +569,7 @@ impl LocalCluster { ) { (Ok(Some(stake_account)), Ok(Some(vote_account))) => { match ( - StakeConverter::stake_from(&stake_account), + stake_state::stake_from(&stake_account), VoteState::from(&vote_account), ) { (Some(stake_state), Some(vote_state)) => { diff --git a/programs/stake/src/config.rs b/programs/stake/src/config.rs index 3eee1f6a106d5f..7564fde4bf3e1a 100644 --- a/programs/stake/src/config.rs +++ b/programs/stake/src/config.rs @@ -10,24 +10,21 @@ use solana_sdk::{ stake::config::{self, Config}, }; -pub struct ConfigConverter; -impl ConfigConverter { - pub fn from(account: &T) -> Option { - get_config_data(&account.data()) - .ok() - .and_then(|data| deserialize(data).ok()) - } +pub fn from(account: &T) -> Option { + get_config_data(&account.data()) + .ok() + .and_then(|data| deserialize(data).ok()) +} - pub fn from_keyed_account(account: &KeyedAccount) -> Result { - if !config::check_id(account.unsigned_key()) { - return Err(InstructionError::InvalidArgument); - } - ConfigConverter::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument) +pub fn from_keyed_account(account: &KeyedAccount) -> Result { + if !config::check_id(account.unsigned_key()) { + return Err(InstructionError::InvalidArgument); } + from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument) +} - pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData { - create_config_account(vec![], config, lamports) - } +pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData { + create_config_account(vec![], config, lamports) } pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 { @@ -49,17 +46,10 @@ mod tests { #[test] fn test() { - let account = RefCell::new(ConfigConverter::create_account(0, &Config::default())); - assert_eq!( - ConfigConverter::from(&account.borrow()), - Some(Config::default()) - ); + let account = RefCell::new(create_account(0, &Config::default())); + assert_eq!(from(&account.borrow()), Some(Config::default())); assert_eq!( - ConfigConverter::from_keyed_account(&KeyedAccount::new( - &Pubkey::default(), - false, - &account - )), + from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)), Err(InstructionError::InvalidArgument) ); } diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 4aa7994a794b74..29ddf10960b410 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -1,5 +1,5 @@ use { - crate::{config::ConfigConverter, stake_state::StakeAccount}, + crate::{config, stake_state::StakeAccount}, log::*, solana_sdk::{ feature_set, @@ -116,7 +116,7 @@ pub fn process_instruction( &vote, &from_keyed_account::(keyed_account_at_index(keyed_accounts, 2)?)?, &from_keyed_account::(keyed_account_at_index(keyed_accounts, 3)?)?, - &ConfigConverter::from_keyed_account(keyed_account_at_index(keyed_accounts, 4)?)?, + &config::from_keyed_account(keyed_account_at_index(keyed_accounts, 4)?)?, &signers, can_reverse_deactivation, ) @@ -170,7 +170,6 @@ pub fn process_instruction( #[cfg(test)] mod tests { use super::*; - use crate::config::ConfigConverter; use bincode::serialize; use solana_sdk::{ account::{self, Account, AccountSharedData, WritableAccount}, @@ -179,7 +178,7 @@ mod tests { process_instruction::{mock_set_sysvar, MockInvokeContext}, rent::Rent, stake::{ - config, + config as stake_config, instruction::{self, LockupArgs}, state::{Authorized, Lockup, StakeAuthorize}, }, @@ -228,8 +227,8 @@ mod tests { )) } else if sysvar::stake_history::check_id(&meta.pubkey) { account::create_account_shared_data_for_test(&StakeHistory::default()) - } else if config::check_id(&meta.pubkey) { - ConfigConverter::create_account(0, &config::Config::default()) + } else if stake_config::check_id(&meta.pubkey) { + config::create_account(0, &stake_config::Config::default()) } else if sysvar::rent::check_id(&meta.pubkey) { account::create_account_shared_data_for_test(&Rent::default()) } else if meta.pubkey == invalid_stake_state_pubkey() { @@ -597,11 +596,9 @@ mod tests { let stake_history_account = RefCell::new(account::create_account_shared_data_for_test( &sysvar::stake_history::StakeHistory::default(), )); - let config_address = config::id(); - let config_account = RefCell::new(ConfigConverter::create_account( - 0, - &config::Config::default(), - )); + let config_address = stake_config::id(); + let config_account = + RefCell::new(config::create_account(0, &stake_config::Config::default())); let keyed_accounts = vec![ KeyedAccount::new(&stake_address, true, &stake_account), KeyedAccount::new(&vote_address, false, &bad_vote_account), diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index 76d9cc7a0a1ee6..fd72d7d282b844 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -57,90 +57,85 @@ pub(crate) fn null_tracer() -> Option } -pub struct StakeConverter; -impl StakeConverter { - // utility function, used by Stakes, tests - pub fn from>(account: &T) -> Option { - account.state().ok() - } +// utility function, used by Stakes, tests +pub fn from>(account: &T) -> Option { + account.state().ok() +} - pub fn stake_from>(account: &T) -> Option { - Self::from(account).and_then(|state: StakeState| state.stake()) - } +pub fn stake_from>(account: &T) -> Option { + from(account).and_then(|state: StakeState| state.stake()) +} - pub fn delegation_from(account: &AccountSharedData) -> Option { - Self::from(account).and_then(|state: StakeState| state.delegation()) - } +pub fn delegation_from(account: &AccountSharedData) -> Option { + from(account).and_then(|state: StakeState| state.delegation()) +} - pub fn authorized_from(account: &AccountSharedData) -> Option { - Self::from(account).and_then(|state: StakeState| state.authorized()) - } +pub fn authorized_from(account: &AccountSharedData) -> Option { + from(account).and_then(|state: StakeState| state.authorized()) +} - pub fn lockup_from>(account: &T) -> Option { - Self::from(account).and_then(|state: StakeState| state.lockup()) - } +pub fn lockup_from>(account: &T) -> Option { + from(account).and_then(|state: StakeState| state.lockup()) +} - pub fn meta_from(account: &AccountSharedData) -> Option { - Self::from(account).and_then(|state: StakeState| state.meta()) - } +pub fn meta_from(account: &AccountSharedData) -> Option { + from(account).and_then(|state: StakeState| state.meta()) +} - // TODO move VoteState into solana_program to move this function into Stake - fn redelegate( - stake: &mut Stake, - stake_lamports: u64, - voter_pubkey: &Pubkey, - vote_state: &VoteState, - clock: &Clock, - stake_history: &StakeHistory, - config: &Config, - can_reverse_deactivation: bool, - ) -> Result<(), StakeError> { - // If stake is currently active: - if stake.stake(clock.epoch, Some(stake_history), true) != 0 { - // If pubkey of new voter is the same as current, - // and we are scheduled to start deactivating this epoch, - // we rescind deactivation - if stake.delegation.voter_pubkey == *voter_pubkey - && clock.epoch == stake.delegation.deactivation_epoch - && can_reverse_deactivation - { - stake.delegation.deactivation_epoch = std::u64::MAX; - return Ok(()); - } else { - // can't redelegate to another pubkey if stake is active. - return Err(StakeError::TooSoonToRedelegate); - } +fn redelegate( + stake: &mut Stake, + stake_lamports: u64, + voter_pubkey: &Pubkey, + vote_state: &VoteState, + clock: &Clock, + stake_history: &StakeHistory, + config: &Config, + can_reverse_deactivation: bool, +) -> Result<(), StakeError> { + // If stake is currently active: + if stake.stake(clock.epoch, Some(stake_history), true) != 0 { + // If pubkey of new voter is the same as current, + // and we are scheduled to start deactivating this epoch, + // we rescind deactivation + if stake.delegation.voter_pubkey == *voter_pubkey + && clock.epoch == stake.delegation.deactivation_epoch + && can_reverse_deactivation + { + stake.delegation.deactivation_epoch = std::u64::MAX; + return Ok(()); + } else { + // can't redelegate to another pubkey if stake is active. + return Err(StakeError::TooSoonToRedelegate); } - // Either the stake is freshly activated, is active but has been - // deactivated this epoch, or has fully de-activated. - // Redelegation implies either re-activation or un-deactivation - - stake.delegation.stake = stake_lamports; - stake.delegation.activation_epoch = clock.epoch; - stake.delegation.deactivation_epoch = std::u64::MAX; - stake.delegation.voter_pubkey = *voter_pubkey; - stake.delegation.warmup_cooldown_rate = config.warmup_cooldown_rate; - stake.credits_observed = vote_state.credits(); - Ok(()) } + // Either the stake is freshly activated, is active but has been + // deactivated this epoch, or has fully de-activated. + // Redelegation implies either re-activation or un-deactivation + + stake.delegation.stake = stake_lamports; + stake.delegation.activation_epoch = clock.epoch; + stake.delegation.deactivation_epoch = std::u64::MAX; + stake.delegation.voter_pubkey = *voter_pubkey; + stake.delegation.warmup_cooldown_rate = config.warmup_cooldown_rate; + stake.credits_observed = vote_state.credits(); + Ok(()) +} - // TODO move VoteState into solana_program to move this function into Stake - fn new_stake( - stake: u64, - voter_pubkey: &Pubkey, - vote_state: &VoteState, - activation_epoch: Epoch, - config: &Config, - ) -> Stake { - Stake { - delegation: Delegation::new( - voter_pubkey, - stake, - activation_epoch, - config.warmup_cooldown_rate, - ), - credits_observed: vote_state.credits(), - } +fn new_stake( + stake: u64, + voter_pubkey: &Pubkey, + vote_state: &VoteState, + activation_epoch: Epoch, + config: &Config, +) -> Stake { + Stake { + delegation: Delegation::new( + voter_pubkey, + stake, + activation_epoch, + config.warmup_cooldown_rate, + ), + credits_observed: vote_state.credits(), } } @@ -154,206 +149,203 @@ pub struct PointValue { pub points: u128, // over these points } -pub struct StakeRewardCalculator; -impl StakeRewardCalculator { - pub fn redeem_rewards( - stake: &mut Stake, - point_value: &PointValue, - vote_state: &VoteState, - stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, - fix_stake_deactivate: bool, - ) -> Option<(u64, u64)> { +fn redeem_stake_rewards( + stake: &mut Stake, + point_value: &PointValue, + vote_state: &VoteState, + stake_history: Option<&StakeHistory>, + inflation_point_calc_tracer: &mut Option, + fix_stake_deactivate: bool, +) -> Option<(u64, u64)> { + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( + stake.credits_observed, + None, + )); + } + calculate_stake_rewards( + stake, + point_value, + vote_state, + stake_history, + inflation_point_calc_tracer, + fix_stake_deactivate, + ) + .map(|(stakers_reward, voters_reward, credits_observed)| { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( stake.credits_observed, - None, + Some(credits_observed), )); } - Self::calculate_rewards( - stake, - point_value, - vote_state, - stake_history, - inflation_point_calc_tracer, - fix_stake_deactivate, - ) - .map(|(stakers_reward, voters_reward, credits_observed)| { + stake.credits_observed = credits_observed; + stake.delegation.stake += stakers_reward; + (stakers_reward, voters_reward) + }) +} + +fn calculate_stake_points( + stake: &Stake, + vote_state: &VoteState, + stake_history: Option<&StakeHistory>, + inflation_point_calc_tracer: &mut Option, + fix_stake_deactivate: bool, +) -> u128 { + calculate_points_and_credits( + stake, + vote_state, + stake_history, + inflation_point_calc_tracer, + fix_stake_deactivate, + ) + .0 +} + +/// for a given stake and vote_state, calculate how many +/// points were earned (credits * stake) and new value +/// for credits_observed were the points paid +fn calculate_points_and_credits( + stake: &Stake, + new_vote_state: &VoteState, + stake_history: Option<&StakeHistory>, + inflation_point_calc_tracer: &mut Option, + fix_stake_deactivate: bool, +) -> (u128, u64) { + // if there is no newer credits since observed, return no point + if new_vote_state.credits() <= stake.credits_observed { + if fix_stake_deactivate { + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into()); + } + return (0, stake.credits_observed); + } else { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( - stake.credits_observed, - Some(credits_observed), - )); + inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnZero.into()); } - stake.credits_observed = credits_observed; - stake.delegation.stake += stakers_reward; - (stakers_reward, voters_reward) - }) + return (0, 0); + } } - pub fn calculate_points( - stake: &Stake, - vote_state: &VoteState, - stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, - fix_stake_deactivate: bool, - ) -> u128 { - Self::calculate_points_and_credits( - stake, - vote_state, + let mut points = 0; + let mut new_credits_observed = stake.credits_observed; + + for (epoch, final_epoch_credits, initial_epoch_credits) in + new_vote_state.epoch_credits().iter().copied() + { + let stake_amount = u128::from(stake.delegation.stake( + epoch, stake_history, - inflation_point_calc_tracer, fix_stake_deactivate, - ) - .0 - } + )); - /// for a given stake and vote_state, calculate how many - /// points were earned (credits * stake) and new value - /// for credits_observed were the points paid - fn calculate_points_and_credits( - stake: &Stake, - new_vote_state: &VoteState, - stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, - fix_stake_deactivate: bool, - ) -> (u128, u64) { - // if there is no newer credits since observed, return no point - if new_vote_state.credits() <= stake.credits_observed { - if fix_stake_deactivate { - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into()); - } - return (0, stake.credits_observed); - } else { - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnZero.into()); - } - return (0, 0); - } - } + // figure out how much this stake has seen that + // for which the vote account has a record + let earned_credits = if stake.credits_observed < initial_epoch_credits { + // the staker observed the entire epoch + final_epoch_credits - initial_epoch_credits + } else if stake.credits_observed < final_epoch_credits { + // the staker registered sometime during the epoch, partial credit + final_epoch_credits - new_credits_observed + } else { + // the staker has already observed or been redeemed this epoch + // or was activated after this epoch + 0 + }; + let earned_credits = u128::from(earned_credits); - let mut points = 0; - let mut new_credits_observed = stake.credits_observed; + // don't want to assume anything about order of the iterator... + new_credits_observed = new_credits_observed.max(final_epoch_credits); - for (epoch, final_epoch_credits, initial_epoch_credits) in - new_vote_state.epoch_credits().iter().copied() - { - let stake_amount = u128::from(stake.delegation.stake( + // finally calculate points for this epoch + let earned_points = stake_amount * earned_credits; + points += earned_points; + + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints( epoch, - stake_history, - fix_stake_deactivate, + stake_amount, + earned_credits, + earned_points, )); - - // figure out how much this stake has seen that - // for which the vote account has a record - let earned_credits = if stake.credits_observed < initial_epoch_credits { - // the staker observed the entire epoch - final_epoch_credits - initial_epoch_credits - } else if stake.credits_observed < final_epoch_credits { - // the staker registered sometime during the epoch, partial credit - final_epoch_credits - new_credits_observed - } else { - // the staker has already observed or been redeemed this epoch - // or was activated after this epoch - 0 - }; - let earned_credits = u128::from(earned_credits); - - // don't want to assume anything about order of the iterator... - new_credits_observed = new_credits_observed.max(final_epoch_credits); - - // finally calculate points for this epoch - let earned_points = stake_amount * earned_credits; - points += earned_points; - - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints( - epoch, - stake_amount, - earned_credits, - earned_points, - )); - } } - - (points, new_credits_observed) } - /// for a given stake and vote_state, calculate what distributions and what updates should be made - /// returns a tuple in the case of a payout of: - /// * staker_rewards to be distributed - /// * voter_rewards to be distributed - /// * new value for credits_observed in the stake - /// returns None if there's no payout or if any deserved payout is < 1 lamport - pub fn calculate_rewards( - stake: &Stake, - point_value: &PointValue, - vote_state: &VoteState, - stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, - fix_stake_deactivate: bool, - ) -> Option<(u64, u64, u64)> { - let (points, credits_observed) = Self::calculate_points_and_credits( - stake, - vote_state, - stake_history, - inflation_point_calc_tracer, - fix_stake_deactivate, - ); + (points, new_credits_observed) +} - // Drive credits_observed forward unconditionally when rewards are disabled - if point_value.rewards == 0 && fix_stake_deactivate { - return Some((0, 0, credits_observed)); - } +/// for a given stake and vote_state, calculate what distributions and what updates should be made +/// returns a tuple in the case of a payout of: +/// * staker_rewards to be distributed +/// * voter_rewards to be distributed +/// * new value for credits_observed in the stake +/// returns None if there's no payout or if any deserved payout is < 1 lamport +pub fn calculate_stake_rewards( + stake: &Stake, + point_value: &PointValue, + vote_state: &VoteState, + stake_history: Option<&StakeHistory>, + inflation_point_calc_tracer: &mut Option, + fix_stake_deactivate: bool, +) -> Option<(u64, u64, u64)> { + let (points, credits_observed) = calculate_points_and_credits( + stake, + vote_state, + stake_history, + inflation_point_calc_tracer, + fix_stake_deactivate, + ); - if points == 0 { - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&SkippedReason::ZeroPoints.into()); - } - return None; + // Drive credits_observed forward unconditionally when rewards are disabled + if point_value.rewards == 0 && fix_stake_deactivate { + return Some((0, 0, credits_observed)); + } + + if points == 0 { + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + inflation_point_calc_tracer(&SkippedReason::ZeroPoints.into()); } - if point_value.points == 0 { - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&SkippedReason::ZeroPointValue.into()); - } - return None; + return None; + } + if point_value.points == 0 { + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + inflation_point_calc_tracer(&SkippedReason::ZeroPointValue.into()); } + return None; + } - let rewards = points - .checked_mul(u128::from(point_value.rewards)) - .unwrap() - .checked_div(point_value.points) - .unwrap(); + let rewards = points + .checked_mul(u128::from(point_value.rewards)) + .unwrap() + .checked_div(point_value.points) + .unwrap(); - let rewards = u64::try_from(rewards).unwrap(); + let rewards = u64::try_from(rewards).unwrap(); - // don't bother trying to split if fractional lamports got truncated - if rewards == 0 { - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&SkippedReason::ZeroReward.into()); - } - return None; - } - let (voter_rewards, staker_rewards, is_split) = vote_state.commission_split(rewards); + // don't bother trying to split if fractional lamports got truncated + if rewards == 0 { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { - inflation_point_calc_tracer(&InflationPointCalculationEvent::SplitRewards( - rewards, - voter_rewards, - staker_rewards, - (*point_value).clone(), - )); - } - - if (voter_rewards == 0 || staker_rewards == 0) && is_split { - // don't collect if we lose a whole lamport somewhere - // is_split means there should be tokens on both sides, - // uncool to move credits_observed if one side didn't get paid - return None; + inflation_point_calc_tracer(&SkippedReason::ZeroReward.into()); } + return None; + } + let (voter_rewards, staker_rewards, is_split) = vote_state.commission_split(rewards); + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + inflation_point_calc_tracer(&InflationPointCalculationEvent::SplitRewards( + rewards, + voter_rewards, + staker_rewards, + (*point_value).clone(), + )); + } - Some((staker_rewards, voter_rewards, credits_observed)) + if (voter_rewards == 0 || staker_rewards == 0) && is_split { + // don't collect if we lose a whole lamport somewhere + // is_split means there should be tokens on both sides, + // uncool to move credits_observed if one side didn't get paid + return None; } + + Some((staker_rewards, voter_rewards, credits_observed)) } pub trait StakeAccount { @@ -539,7 +531,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> { match self.state()? { StakeState::Initialized(meta) => { meta.authorized.check(signers, StakeAuthorize::Staker)?; - let stake = StakeConverter::new_stake( + let stake = new_stake( self.lamports()?.saturating_sub(meta.rent_exempt_reserve), // can't stake the rent ;) vote_account.unsigned_key(), &State::::state(vote_account)?.convert_to_current(), @@ -550,7 +542,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> { } StakeState::Stake(meta, mut stake) => { meta.authorized.check(signers, StakeAuthorize::Staker)?; - StakeConverter::redelegate( + redelegate( &mut stake, self.lamports()?.saturating_sub(meta.rent_exempt_reserve), // can't stake the rent ;) vote_account.unsigned_key(), @@ -1056,7 +1048,7 @@ pub fn redeem_rewards( )); } - if let Some((stakers_reward, voters_reward)) = StakeRewardCalculator::redeem_rewards( + if let Some((stakers_reward, voters_reward)) = redeem_stake_rewards( &mut stake, point_value, &vote_state, @@ -1089,7 +1081,7 @@ pub fn calculate_points( let vote_state: VoteState = StateMut::::state(vote_account)?.convert_to_current(); - Ok(StakeRewardCalculator::calculate_points( + Ok(calculate_stake_points( &stake, &vote_state, stake_history, @@ -1269,7 +1261,7 @@ fn do_create_account( rent_exempt_reserve, ..Meta::default() }, - StakeConverter::new_stake( + new_stake( lamports - rent_exempt_reserve, // underflow is an error, is basically: assert!(lamports > rent_exempt_reserve); voter_pubkey, &vote_state, @@ -1443,7 +1435,7 @@ mod tests { .set_state(&StakeState::default()) .expect("set_state"); - assert_eq!(StakeConverter::stake_from(&stake_account), None); + assert_eq!(stake_from(&stake_account), None); } #[test] @@ -1550,7 +1542,7 @@ mod tests { .is_ok()); // verify that delegate() looks right, compare against hand-rolled - let stake = StakeConverter::stake_from(&stake_keyed_account.account.borrow()).unwrap(); + let stake = stake_from(&stake_keyed_account.account.borrow()).unwrap(); assert_eq!( stake, Stake { @@ -1611,7 +1603,7 @@ mod tests { .unwrap(); // verify that deactivation has been cleared - let stake = StakeConverter::stake_from(&stake_keyed_account.account.borrow()).unwrap(); + let stake = stake_from(&stake_keyed_account.account.borrow()).unwrap(); assert_eq!(stake.delegation.deactivation_epoch, std::u64::MAX); // verify that delegate to a different vote account fails @@ -1666,7 +1658,7 @@ mod tests { ); // verify that delegate() looks right, compare against hand-rolled - let stake = StakeConverter::stake_from(&stake_keyed_account.account.borrow()).unwrap(); + let stake = stake_from(&stake_keyed_account.account.borrow()).unwrap(); assert_eq!( stake, Stake { @@ -2357,7 +2349,7 @@ mod tests { ); // check that we see what we expect assert_eq!( - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap(), + from(&stake_keyed_account.account.borrow()).unwrap(), StakeState::Initialized(Meta { lockup: Lockup { unix_timestamp: 0, @@ -2646,7 +2638,7 @@ mod tests { ); if let StakeState::Initialized(Meta { lockup, .. }) = - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() + from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(lockup.unix_timestamp, 2); assert_eq!(lockup.epoch, 1); @@ -2669,7 +2661,7 @@ mod tests { ); if let StakeState::Initialized(Meta { lockup, .. }) = - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() + from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(lockup.unix_timestamp, 2); assert_eq!(lockup.epoch, 3); @@ -2693,7 +2685,7 @@ mod tests { ); if let StakeState::Initialized(Meta { lockup, .. }) = - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() + from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(lockup.unix_timestamp, 2); assert_eq!(lockup.epoch, 3); @@ -3093,11 +3085,9 @@ mod tests { let stake_history = create_stake_history_from_delegations( None, 0..future.epoch, - &[ - StakeConverter::stake_from(&stake_keyed_account.account.borrow()) - .unwrap() - .delegation, - ], + &[stake_from(&stake_keyed_account.account.borrow()) + .unwrap() + .delegation], ); // Try to withdraw stake @@ -3392,7 +3382,7 @@ mod tests { // assume stake.stake() is right // bootstrap means fully-vested stake at epoch 0 let stake_lamports = 1; - let mut stake = StakeConverter::new_stake( + let mut stake = new_stake( stake_lamports, &Pubkey::default(), &vote_state, @@ -3403,7 +3393,7 @@ mod tests { // this one can't collect now, credits_observed == vote_state.credits() assert_eq!( None, - StakeRewardCalculator::redeem_rewards( + redeem_stake_rewards( &mut stake, &PointValue { rewards: 1_000_000_000, @@ -3423,7 +3413,7 @@ mod tests { // this one should be able to collect exactly 2 assert_eq!( Some((stake_lamports * 2, 0)), - StakeRewardCalculator::redeem_rewards( + redeem_stake_rewards( &mut stake, &PointValue { rewards: 1, @@ -3449,7 +3439,7 @@ mod tests { // bootstrap means fully-vested stake at epoch 0 with // 10_000_000 SOL is a big but not unreasaonable stake - let stake = StakeConverter::new_stake( + let stake = new_stake( native_token::sol_to_lamports(10_000_000f64), &Pubkey::default(), &vote_state, @@ -3460,7 +3450,7 @@ mod tests { // this one can't collect now, credits_observed == vote_state.credits() assert_eq!( None, - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 1_000_000_000, @@ -3483,13 +3473,7 @@ mod tests { // no overflow on points assert_eq!( u128::from(stake.delegation.stake) * epoch_slots, - StakeRewardCalculator::calculate_points( - &stake, - &vote_state, - None, - &mut null_tracer(), - true - ) + calculate_stake_points(&stake, &vote_state, None, &mut null_tracer(), true) ); } @@ -3498,7 +3482,7 @@ mod tests { let mut vote_state = VoteState::default(); // assume stake.stake() is right // bootstrap means fully-vested stake at epoch 0 - let mut stake = StakeConverter::new_stake( + let mut stake = new_stake( 1, &Pubkey::default(), &vote_state, @@ -3509,7 +3493,7 @@ mod tests { // this one can't collect now, credits_observed == vote_state.credits() assert_eq!( None, - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 1_000_000_000, @@ -3529,7 +3513,7 @@ mod tests { // this one should be able to collect exactly 2 assert_eq!( Some((stake.delegation.stake * 2, 0, 2)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 2, @@ -3546,7 +3530,7 @@ mod tests { // this one should be able to collect exactly 1 (already observed one) assert_eq!( Some((stake.delegation.stake, 0, 2)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 1, @@ -3566,7 +3550,7 @@ mod tests { // this one should be able to collect the one just added assert_eq!( Some((stake.delegation.stake, 0, 3)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 2, @@ -3584,7 +3568,7 @@ mod tests { // this one should be able to collect 2 now assert_eq!( Some((stake.delegation.stake * 2, 0, 4)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 2, @@ -3608,7 +3592,7 @@ mod tests { 0, 4 )), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 4, @@ -3626,7 +3610,7 @@ mod tests { vote_state.commission = 1; assert_eq!( None, // would be Some((0, 2 * 1 + 1 * 2, 4)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 4, @@ -3641,7 +3625,7 @@ mod tests { vote_state.commission = 99; assert_eq!( None, // would be Some((0, 2 * 1 + 1 * 2, 4)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 4, @@ -3659,7 +3643,7 @@ mod tests { // paying rewards when inflation is turned on. assert_eq!( Some((0, 0, 4)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 0, @@ -3677,7 +3661,7 @@ mod tests { stake.credits_observed = 4; assert_eq!( Some((0, 0, 4)), - StakeRewardCalculator::calculate_rewards( + calculate_stake_rewards( &stake, &PointValue { rewards: 0, @@ -3693,23 +3677,11 @@ mod tests { // assert the previous behavior is preserved where fix_stake_deactivate=false assert_eq!( (0, 0), - StakeRewardCalculator::calculate_points_and_credits( - &stake, - &vote_state, - None, - &mut null_tracer(), - false - ) + calculate_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), false) ); assert_eq!( (0, 4), - StakeRewardCalculator::calculate_points_and_credits( - &stake, - &vote_state, - None, - &mut null_tracer(), - true - ) + calculate_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), true) ); } @@ -3784,7 +3756,7 @@ mod tests { Ok(()) ); if let StakeState::Initialized(Meta { authorized, .. }) = - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() + from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(authorized.staker, stake_pubkey0); assert_eq!(authorized.withdrawer, stake_pubkey0); @@ -3822,7 +3794,7 @@ mod tests { Ok(()) ); if let StakeState::Initialized(Meta { authorized, .. }) = - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() + from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(authorized.staker, stake_pubkey2); } @@ -3839,7 +3811,7 @@ mod tests { Ok(()) ); if let StakeState::Initialized(Meta { authorized, .. }) = - StakeConverter::from(&stake_keyed_account.account.borrow()).unwrap() + from(&stake_keyed_account.account.borrow()).unwrap() { assert_eq!(authorized.staker, stake_pubkey2); } @@ -4114,10 +4086,7 @@ mod tests { let stake_lamports = 42; let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, - &StakeState::Stake( - Meta::auto(&stake_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + &StakeState::Stake(Meta::auto(&stake_pubkey), just_stake(stake_lamports)), std::mem::size_of::(), &id(), ) @@ -4141,15 +4110,13 @@ mod tests { Err(InstructionError::InvalidAccountData) ); } - impl StakeConverter { - fn just_stake(stake: u64) -> Stake { - Stake { - delegation: Delegation { - stake, - ..Delegation::default() - }, - ..Stake::default() - } + fn just_stake(stake: u64) -> Stake { + Stake { + delegation: Delegation { + stake, + ..Delegation::default() + }, + ..Stake::default() } } @@ -4161,7 +4128,7 @@ mod tests { stake_lamports, &StakeState::Stake( Meta::auto(&stake_pubkey), - StakeConverter::just_stake(stake_lamports / 2 - 1), + just_stake(stake_lamports / 2 - 1), ), std::mem::size_of::(), &id(), @@ -4204,10 +4171,7 @@ mod tests { // test splitting both an Initialized stake and a Staked stake for state in &[ StakeState::Initialized(meta), - StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ), + StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)), ] { let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, @@ -4302,10 +4266,7 @@ mod tests { // test splitting both an Initialized stake and a Staked stake for state in &[ StakeState::Initialized(Meta::auto(&stake_pubkey)), - StakeState::Stake( - Meta::auto(&stake_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + StakeState::Stake(Meta::auto(&stake_pubkey), just_stake(stake_lamports)), ] { let split_stake_account = AccountSharedData::new_ref_data_with_space( 0, @@ -4410,10 +4371,7 @@ mod tests { let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, - &StakeState::Stake( - Meta::auto(&stake_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + &StakeState::Stake(Meta::auto(&stake_pubkey), just_stake(stake_lamports)), std::mem::size_of::(), &id(), ) @@ -4442,10 +4400,7 @@ mod tests { ..Meta::default() }; - let state = StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ); + let state = StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)); // Test various account prefunding, including empty, less than rent_exempt_reserve, exactly // rent_exempt_reserve, and more than rent_exempt_reserve. The empty case is not covered in // test_split, since that test uses a Meta with rent_exempt_reserve = 0 @@ -4545,10 +4500,7 @@ mod tests { ..Meta::default() }; - let state = StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ); + let state = StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)); let expected_rent_exempt_reserve = calculate_split_rent_exempt_reserve( meta.rent_exempt_reserve, @@ -4672,10 +4624,7 @@ mod tests { let stake_lamports = expected_rent_exempt_reserve + 1; let split_amount = stake_lamports - (rent_exempt_reserve + 1); // Enough so that split stake is > 0 - let state = StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ); + let state = StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)); let split_lamport_balances = vec![ 0, @@ -4735,10 +4684,7 @@ mod tests { // test splitting both an Initialized stake and a Staked stake for state in &[ StakeState::Initialized(meta), - StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ), + StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)), ] { let split_stake_account = AccountSharedData::new_ref_data_with_space( 0, @@ -4821,10 +4767,7 @@ mod tests { ..Meta::default() }; - let state = StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ); + let state = StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)); // Test various account prefunding, including empty, less than rent_exempt_reserve, exactly // rent_exempt_reserve, and more than rent_exempt_reserve. Technically, the empty case is // covered in test_split_100_percent_of_source, but included here as well for readability @@ -4900,10 +4843,7 @@ mod tests { for state in &[ StakeState::Initialized(meta), - StakeState::Stake( - meta, - StakeConverter::just_stake(stake_lamports - rent_exempt_reserve), - ), + StakeState::Stake(meta, just_stake(stake_lamports - rent_exempt_reserve)), ] { // Test that splitting to a larger account fails let split_stake_account = AccountSharedData::new_ref_data_with_space( @@ -5023,17 +4963,11 @@ mod tests { for state in &[ StakeState::Initialized(Meta::auto(&authorized_pubkey)), - StakeState::Stake( - Meta::auto(&authorized_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + StakeState::Stake(Meta::auto(&authorized_pubkey), just_stake(stake_lamports)), ] { for source_state in &[ StakeState::Initialized(Meta::auto(&authorized_pubkey)), - StakeState::Stake( - Meta::auto(&authorized_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + StakeState::Stake(Meta::auto(&authorized_pubkey), just_stake(stake_lamports)), ] { let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, @@ -5186,16 +5120,13 @@ mod tests { for state in &[ StakeState::Initialized(Meta::auto(&authorized_pubkey)), - StakeState::Stake( - Meta::auto(&authorized_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + StakeState::Stake(Meta::auto(&authorized_pubkey), just_stake(stake_lamports)), ] { for source_state in &[ StakeState::Initialized(Meta::auto(&wrong_authorized_pubkey)), StakeState::Stake( Meta::auto(&wrong_authorized_pubkey), - StakeConverter::just_stake(stake_lamports), + just_stake(stake_lamports), ), ] { let stake_account = AccountSharedData::new_ref_data_with_space( @@ -5257,10 +5188,7 @@ mod tests { StakeState::Uninitialized, StakeState::RewardsPool, StakeState::Initialized(Meta::auto(&authorized_pubkey)), - StakeState::Stake( - Meta::auto(&authorized_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + StakeState::Stake(Meta::auto(&authorized_pubkey), just_stake(stake_lamports)), ] { for source_state in &[StakeState::Uninitialized, StakeState::RewardsPool] { let stake_account = AccountSharedData::new_ref_data_with_space( @@ -5308,10 +5236,7 @@ mod tests { let stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, - &StakeState::Stake( - Meta::auto(&authorized_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + &StakeState::Stake(Meta::auto(&authorized_pubkey), just_stake(stake_lamports)), std::mem::size_of::(), &id(), ) @@ -5320,10 +5245,7 @@ mod tests { let source_stake_account = AccountSharedData::new_ref_data_with_space( stake_lamports, - &StakeState::Stake( - Meta::auto(&authorized_pubkey), - StakeConverter::just_stake(stake_lamports), - ), + &StakeState::Stake(Meta::auto(&authorized_pubkey), just_stake(stake_lamports)), std::mem::size_of::(), &solana_sdk::pubkey::new_rand(), ) @@ -5729,9 +5651,7 @@ mod tests { ), Ok(()) ); - let authorized = - StakeConverter::authorized_from(&stake_keyed_account.try_account_ref().unwrap()) - .unwrap(); + let authorized = authorized_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap(); assert_eq!(authorized.staker, new_staker_pubkey); let other_pubkey = solana_sdk::pubkey::new_rand(); @@ -5777,8 +5697,7 @@ mod tests { ), Ok(()) ); - let stake = - StakeConverter::stake_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap(); + let stake = stake_from(&stake_keyed_account.try_account_ref().unwrap()).unwrap(); assert_eq!(stake.delegation.voter_pubkey, new_voter_pubkey); // Test another staking action @@ -5864,7 +5783,7 @@ mod tests { true, ) .unwrap(); - let stake = StakeConverter::stake_from(&stake_account.borrow()).unwrap(); + let stake = stake_from(&stake_account.borrow()).unwrap(); assert_eq!( stake.delegation.stake, stake_keyed_account.lamports().unwrap() - rent_exempt_reserve, @@ -5891,7 +5810,7 @@ mod tests { true, ) .unwrap(); - let stake = StakeConverter::stake_from(&stake_account.borrow()).unwrap(); + let stake = stake_from(&stake_account.borrow()).unwrap(); assert_eq!( stake.delegation.stake, stake_keyed_account.lamports().unwrap() - rent_exempt_reserve, diff --git a/rpc/src/rpc_pubsub.rs b/rpc/src/rpc_pubsub.rs index 7a41fed3dcc034..341afaf226815e 100644 --- a/rpc/src/rpc_pubsub.rs +++ b/rpc/src/rpc_pubsub.rs @@ -576,7 +576,7 @@ mod tests { system_instruction, system_program, system_transaction, transaction::{self, Transaction}, }, - solana_stake_program::stake_state::StakeConverter, + solana_stake_program::stake_state, solana_vote_program::vote_state::Vote, std::{ sync::{atomic::AtomicBool, RwLock}, @@ -888,7 +888,7 @@ mod tests { let bank = bank_forks.read().unwrap()[1].clone(); let account = bank.get_account(&stake_account.pubkey()).unwrap(); assert_eq!( - StakeConverter::authorized_from(&account).unwrap().staker, + stake_state::authorized_from(&account).unwrap().staker, new_stake_authority ); } diff --git a/runtime/src/non_circulating_supply.rs b/runtime/src/non_circulating_supply.rs index 06122f1aed8efa..16187f83afeb53 100644 --- a/runtime/src/non_circulating_supply.rs +++ b/runtime/src/non_circulating_supply.rs @@ -9,7 +9,7 @@ use { pubkey::Pubkey, stake::{self, state::StakeState}, }, - solana_stake_program::stake_state::StakeConverter, + solana_stake_program::stake_state, std::{collections::HashSet, sync::Arc}, }; @@ -47,7 +47,7 @@ pub fn calculate_non_circulating_supply(bank: &Arc) -> NonCirculatingSuppl bank.get_program_accounts(&stake::id()) }; for (pubkey, account) in stake_accounts.iter() { - let stake_account = StakeConverter::from(account).unwrap_or_default(); + let stake_account = stake_state::from(account).unwrap_or_default(); match stake_account { StakeState::Initialized(meta) => { if meta.lockup.is_in_force(&clock, None) diff --git a/runtime/src/stakes.rs b/runtime/src/stakes.rs index c05d992ff3dce9..583ab569208cf4 100644 --- a/runtime/src/stakes.rs +++ b/runtime/src/stakes.rs @@ -11,7 +11,7 @@ use solana_sdk::{ }, sysvar::stake_history::StakeHistory, }; -use solana_stake_program::stake_state::{new_stake_history_entry, StakeConverter}; +use solana_stake_program::stake_state; use solana_vote_program::vote_state::VoteState; use std::{borrow::Borrow, collections::HashMap}; @@ -46,7 +46,7 @@ impl Stakes { let mut stake_history_upto_prev_epoch = self.stake_history.clone(); stake_history_upto_prev_epoch.add( prev_epoch, - new_stake_history_entry( + stake_state::new_stake_history_entry( prev_epoch, self.stake_delegations .iter() @@ -161,7 +161,7 @@ impl Stakes { ) }); - let delegation = StakeConverter::delegation_from(account); + let delegation = stake_state::delegation_from(account); let stake = delegation.map(|delegation| { ( @@ -312,7 +312,7 @@ pub mod tests { stakes.store(&vote_pubkey, &vote_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeConverter::stake_from(&stake_account).unwrap(); + let stake = stake_state::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); assert!(vote_accounts.get(&vote_pubkey).is_some()); @@ -336,7 +336,7 @@ pub mod tests { // activate more let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey); stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeConverter::stake_from(&stake_account).unwrap(); + let stake = stake_state::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); assert!(vote_accounts.get(&vote_pubkey).is_some()); @@ -467,7 +467,7 @@ pub mod tests { // delegates to vote_pubkey stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeConverter::stake_from(&stake_account).unwrap(); + let stake = stake_state::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); @@ -527,7 +527,7 @@ pub mod tests { stakes.store(&vote_pubkey, &vote_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true); - let stake = StakeConverter::stake_from(&stake_account).unwrap(); + let stake = stake_state::stake_from(&stake_account).unwrap(); { let vote_accounts = stakes.vote_accounts(); diff --git a/runtime/tests/stake.rs b/runtime/tests/stake.rs index 2274735bc524b1..f2ddfdea9cfb4b 100644 --- a/runtime/tests/stake.rs +++ b/runtime/tests/stake.rs @@ -17,7 +17,7 @@ use solana_sdk::{ }, sysvar::{self, stake_history::StakeHistory}, }; -use solana_stake_program::stake_state::StakeConverter; +use solana_stake_program::stake_state; use solana_vote_program::{ vote_instruction, vote_state::{Vote, VoteInit, VoteState, VoteStateVersions}, @@ -70,7 +70,7 @@ fn fill_epoch_with_votes( } fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool { - let stake = StakeConverter::stake_from(&bank.get_account(stake_pubkey).unwrap()).unwrap(); + let stake = stake_state::stake_from(&bank.get_account(stake_pubkey).unwrap()).unwrap(); stake.delegation.stake == stake.stake( @@ -86,7 +86,7 @@ fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool { } fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 { - StakeConverter::stake_from(&bank.get_account(stake_pubkey).unwrap()) + stake_state::stake_from(&bank.get_account(stake_pubkey).unwrap()) .unwrap() .stake( bank.epoch(), diff --git a/stake-accounts/src/main.rs b/stake-accounts/src/main.rs index bf4d7afd49e40f..2b478785ffdc99 100644 --- a/stake-accounts/src/main.rs +++ b/stake-accounts/src/main.rs @@ -19,7 +19,7 @@ use solana_sdk::{ stake::{instruction::LockupArgs, state::Lockup}, transaction::Transaction, }; -use solana_stake_program::stake_state::StakeConverter; +use solana_stake_program::stake_state; use std::env; use std::error::Error; @@ -50,7 +50,7 @@ fn get_balances( fn get_lockup(client: &RpcClient, address: &Pubkey) -> Result { client .get_account(address) - .map(|account| StakeConverter::lockup_from(&account).unwrap()) + .map(|account| stake_state::lockup_from(&account).unwrap()) } fn get_lockups( diff --git a/stake-accounts/src/stake_accounts.rs b/stake-accounts/src/stake_accounts.rs index 09bb51a6e0cf8a..d52ddbdcdbfae8 100644 --- a/stake-accounts/src/stake_accounts.rs +++ b/stake-accounts/src/stake_accounts.rs @@ -290,7 +290,7 @@ mod tests { signature::{Keypair, Signer}, stake::state::StakeState, }; - use solana_stake_program::stake_state::StakeConverter; + use solana_stake_program::stake_state; fn create_bank(lamports: u64) -> (Bank, Keypair, u64) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); @@ -343,7 +343,7 @@ mod tests { let address = derive_stake_account_address(&base_pubkey, i); let account = AccountSharedData::from(client.get_account(&address).unwrap().unwrap()); - (address, StakeConverter::lockup_from(&account).unwrap()) + (address, stake_state::lockup_from(&account).unwrap()) }) .collect() } @@ -380,7 +380,7 @@ mod tests { let account = get_account_at(&bank_client, &base_pubkey, 0); assert_eq!(account.lamports(), lamports); - let authorized = StakeConverter::authorized_from(&account).unwrap(); + let authorized = stake_state::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, stake_authority_pubkey); assert_eq!(authorized.withdrawer, withdraw_authority_pubkey); } @@ -442,7 +442,7 @@ mod tests { } let account = get_account_at(&bank_client, &base_pubkey, 0); - let authorized = StakeConverter::authorized_from(&account).unwrap(); + let authorized = stake_state::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, new_stake_authority_pubkey); assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey); } @@ -498,7 +498,7 @@ mod tests { } let account = get_account_at(&bank_client, &base_pubkey, 0); - let lockup = StakeConverter::lockup_from(&account).unwrap(); + let lockup = stake_state::lockup_from(&account).unwrap(); assert_eq!(lockup.unix_timestamp, 1); assert_eq!(lockup.epoch, 0); @@ -591,7 +591,7 @@ mod tests { // Ensure the new accounts are duplicates of the previous ones. let account = get_account_at(&bank_client, &new_base_pubkey, 0); - let authorized = StakeConverter::authorized_from(&account).unwrap(); + let authorized = stake_state::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, stake_authority_pubkey); assert_eq!(authorized.withdrawer, withdraw_authority_pubkey); } @@ -660,7 +660,7 @@ mod tests { // Ensure the new accounts have the new authorities. let account = get_account_at(&bank_client, &new_base_pubkey, 0); - let authorized = StakeConverter::authorized_from(&account).unwrap(); + let authorized = stake_state::authorized_from(&account).unwrap(); assert_eq!(authorized.staker, new_stake_authority_pubkey); assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey); } From 2cedf3084947d341312deb1db8b33ab3f2569e15 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 14 Jun 2021 22:27:49 +0200 Subject: [PATCH 11/14] Move stake::id() -> stake::program::id() --- account-decoder/src/parse_account_data.rs | 2 +- cli-output/src/display.rs | 2 +- cli/src/cli.rs | 12 ++++++------ cli/src/cluster_query.rs | 2 +- cli/src/stake.rs | 16 ++++++++-------- cli/tests/stake.rs | 4 ++-- cli/tests/transfer.rs | 2 +- genesis/src/stakes.rs | 2 +- ledger-tool/src/main.rs | 2 +- local-cluster/tests/local_cluster.rs | 2 +- perf/src/test_tx.rs | 2 +- programs/stake/src/stake_instruction.rs | 2 +- programs/stake/src/stake_state.rs | 2 +- rpc/src/rpc_pubsub.rs | 2 +- rpc/src/rpc_subscriptions.rs | 10 +++++----- runtime/src/bank.rs | 2 +- runtime/src/builtins.rs | 2 +- runtime/src/non_circulating_supply.rs | 8 ++++---- runtime/src/stakes.rs | 6 +++--- runtime/tests/stake.rs | 10 +++++----- sdk/program/src/stake/instruction.rs | 2 +- sdk/program/src/stake/mod.rs | 3 +-- sdk/program/src/stake/program.rs | 1 + stake-accounts/src/stake_accounts.rs | 2 +- stake-monitor/src/lib.rs | 2 +- transaction-status/src/parse_instruction.rs | 2 +- 26 files changed, 52 insertions(+), 52 deletions(-) create mode 100644 sdk/program/src/stake/program.rs diff --git a/account-decoder/src/parse_account_data.rs b/account-decoder/src/parse_account_data.rs index 53ca713f90582d..0c26b4003ea8f9 100644 --- a/account-decoder/src/parse_account_data.rs +++ b/account-decoder/src/parse_account_data.rs @@ -16,7 +16,7 @@ use thiserror::Error; lazy_static! { static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id(); static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id(); - static ref STAKE_PROGRAM_ID: Pubkey = stake::id(); + static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id(); static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); diff --git a/cli-output/src/display.rs b/cli-output/src/display.rs index 3b0c37242317b4..4961feb0f66fdc 100644 --- a/cli-output/src/display.rs +++ b/cli-output/src/display.rs @@ -244,7 +244,7 @@ pub fn write_transaction( writeln!(w, "{} {:?}", prefix, vote_instruction)?; raw = false; } - } else if program_pubkey == stake::id() { + } else if program_pubkey == stake::program::id() { if let Ok(stake_instruction) = limited_deserialize::(&instruction.data) { diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 9102706d7a360d..a306d8c63e6c5b 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -933,7 +933,7 @@ pub type ProcessResult = Result>; fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option { matches.value_of(arg_name).and_then(|v| match v { "NONCE" => Some(system_program::id()), - "STAKE" => Some(stake::id()), + "STAKE" => Some(stake::program::id()), "VOTE" => Some(solana_vote_program::id()), _ => pubkey_of(matches, arg_name), }) @@ -2488,7 +2488,7 @@ mod tests { let from_pubkey = Some(solana_sdk::pubkey::new_rand()); let from_str = from_pubkey.unwrap().to_string(); for (name, program_id) in &[ - ("STAKE", stake::id()), + ("STAKE", stake::program::id()), ("VOTE", solana_vote_program::id()), ("NONCE", system_program::id()), ] { @@ -2524,7 +2524,7 @@ mod tests { command: CliCommand::CreateAddressWithSeed { from_pubkey: None, seed: "seed".to_string(), - program_id: stake::id(), + program_id: stake::program::id(), }, signers: vec![read_keypair_file(&keypair_file).unwrap().into()], } @@ -2787,11 +2787,11 @@ mod tests { config.command = CliCommand::CreateAddressWithSeed { from_pubkey: Some(from_pubkey), seed: "seed".to_string(), - program_id: stake::id(), + program_id: stake::program::id(), }; let address = process_command(&config); let expected_address = - Pubkey::create_with_seed(&from_pubkey, "seed", &stake::id()).unwrap(); + Pubkey::create_with_seed(&from_pubkey, "seed", &stake::program::id()).unwrap(); assert_eq!(address.unwrap(), expected_address.to_string()); // Need airdrop cases @@ -3178,7 +3178,7 @@ mod tests { memo: None, fee_payer: 0, derived_address_seed: Some(derived_address_seed), - derived_address_program_id: Some(stake::id()), + derived_address_program_id: Some(stake::program::id()), }, signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),], } diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index ae110257c95830..282440b923848e 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -1705,7 +1705,7 @@ pub fn process_show_stakes( } } let all_stake_accounts = - rpc_client.get_program_accounts_with_config(&stake::id(), program_accounts_config)?; + rpc_client.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?; let stake_history_account = rpc_client.get_account(&stake_history::id())?; let clock_account = rpc_client.get_account(&sysvar::clock::id())?; let clock: Clock = from_account(&clock_account).ok_or_else(|| { diff --git a/cli/src/stake.rs b/cli/src/stake.rs index 8cada1f9cd3962..42d21fea41863a 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -972,7 +972,7 @@ pub fn process_create_stake_account( ) -> ProcessResult { let stake_account = config.signers[stake_account]; let stake_account_address = if let Some(seed) = seed { - Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &stake::id())? + Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &stake::program::id())? } else { stake_account.pubkey() }; @@ -1040,7 +1040,7 @@ pub fn process_create_stake_account( if !sign_only { if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) { - let err_msg = if stake_account.owner == stake::id() { + let err_msg = if stake_account.owner == stake::program::id() { format!("Stake account {} already exists", stake_account_address) } else { format!( @@ -1196,7 +1196,7 @@ pub fn process_deactivate_stake_account( let stake_authority = config.signers[stake_authority]; let stake_account_address = if let Some(seed) = seed { - Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::id())? + Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::program::id())? } else { *stake_account_pubkey }; @@ -1274,7 +1274,7 @@ pub fn process_withdraw_stake( let custodian = custodian.map(|index| config.signers[index]); let stake_account_address = if let Some(seed) = seed { - Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::id())? + Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::program::id())? } else { *stake_account_pubkey }; @@ -1395,14 +1395,14 @@ pub fn process_split_stake( let stake_authority = config.signers[stake_authority]; let split_stake_account_address = if let Some(seed) = split_stake_account_seed { - Pubkey::create_with_seed(&split_stake_account.pubkey(), &seed, &stake::id())? + Pubkey::create_with_seed(&split_stake_account.pubkey(), &seed, &stake::program::id())? } else { split_stake_account.pubkey() }; if !sign_only { if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) { - let err_msg = if stake_account.owner == stake::id() { + let err_msg = if stake_account.owner == stake::program::id() { format!( "Stake account {} already exists", split_stake_account_address @@ -1537,7 +1537,7 @@ pub fn process_merge_stake( if !sign_only { for stake_account_address in &[stake_account_pubkey, source_stake_account_pubkey] { if let Ok(stake_account) = rpc_client.get_account(stake_account_address) { - if stake_account.owner != stake::id() { + if stake_account.owner != stake::program::id() { return Err(CliError::BadParameter(format!( "Account {} is not a stake account", stake_account_address @@ -1873,7 +1873,7 @@ pub fn process_show_stake_account( with_rewards: Option, ) -> ProcessResult { let stake_account = rpc_client.get_account(stake_account_address)?; - if stake_account.owner != stake::id() { + if stake_account.owner != stake::program::id() { return Err(CliError::RpcRequestError(format!( "{:?} is not a stake account", stake_account_address, diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 57b22212100af4..98348cd9acb8c0 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -140,7 +140,7 @@ fn test_seed_stake_delegation_and_deactivation() { let stake_address = Pubkey::create_with_seed( &config_validator.signers[0].pubkey(), "hi there", - &stake::id(), + &stake::program::id(), ) .expect("bad seed"); @@ -1557,6 +1557,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { from: 0, }; process_command(&config).unwrap(); - let seed_address = Pubkey::create_with_seed(&stake_pubkey, seed, &stake::id()).unwrap(); + let seed_address = Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap(); check_recent_balance(50_000, &rpc_client, &seed_address); } diff --git a/cli/tests/transfer.rs b/cli/tests/transfer.rs index aeeb958df5e431..86897c1894d408 100644 --- a/cli/tests/transfer.rs +++ b/cli/tests/transfer.rs @@ -514,7 +514,7 @@ fn test_transfer_with_seed() { let sender_pubkey = config.signers[0].pubkey(); let recipient_pubkey = Pubkey::new(&[1u8; 32]); let derived_address_seed = "seed".to_string(); - let derived_address_program_id = stake::id(); + let derived_address_program_id = stake::program::id(); let derived_address = Pubkey::create_with_seed( &sender_pubkey, &derived_address_seed, diff --git a/genesis/src/stakes.rs b/genesis/src/stakes.rs index 898e8e507ead45..ca2b8da4d9791b 100644 --- a/genesis/src/stakes.rs +++ b/genesis/src/stakes.rs @@ -105,7 +105,7 @@ pub fn create_and_add_stakes( genesis_config.ticks_per_slot, ); - let mut address_generator = AddressGenerator::new(&authorized.staker, &stake::id()); + let mut address_generator = AddressGenerator::new(&authorized.staker, &stake::program::id()); let stake_rent_reserve = StakeState::get_rent_exempt_reserve(&genesis_config.rent); diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index 875d93ed864669..e86c25e3b30834 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -2040,7 +2040,7 @@ fn main() { if remove_stake_accounts { for (address, mut account) in - bank.get_program_accounts(&stake::id()).into_iter() + bank.get_program_accounts(&stake::program::id()).into_iter() { account.set_lamports(0); bank.store_account(&address, &account); diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index d8c5a581293019..0b22475ac4540a 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -1402,7 +1402,7 @@ fn test_mainnet_beta_cluster_type() { for program_id in [ &solana_config_program::id(), &solana_sdk::system_program::id(), - &solana_sdk::stake::id(), + &solana_sdk::stake::program::id(), &solana_vote_program::id(), &solana_sdk::bpf_loader_deprecated::id(), &solana_sdk::bpf_loader::id(), diff --git a/perf/src/test_tx.rs b/perf/src/test_tx.rs index fa23f009a45455..a6845317183e1d 100644 --- a/perf/src/test_tx.rs +++ b/perf/src/test_tx.rs @@ -24,7 +24,7 @@ pub fn test_multisig_tx() -> Transaction { let transfer_instruction = SystemInstruction::Transfer { lamports }; - let program_ids = vec![system_program::id(), stake::id()]; + let program_ids = vec![system_program::id(), stake::program::id()]; let instructions = vec![CompiledInstruction::new( 0, diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 29ddf10960b410..8bf2acc915a0d2 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -8,7 +8,7 @@ use { process_instruction::{get_sysvar, InvokeContext}, program_utils::limited_deserialize, pubkey::Pubkey, - stake::{id, instruction::StakeInstruction}, + stake::{program::id, instruction::StakeInstruction}, sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory}, }, }; diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index fd72d7d282b844..e59d279f72997e 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -16,7 +16,7 @@ use { rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, stake::{ config::Config, - id, + program::id, instruction::{LockupArgs, StakeError}, state::{Authorized, Delegation, Lockup, Meta, Stake, StakeAuthorize, StakeState}, }, diff --git a/rpc/src/rpc_pubsub.rs b/rpc/src/rpc_pubsub.rs index 341afaf226815e..1e897835f34053 100644 --- a/rpc/src/rpc_pubsub.rs +++ b/rpc/src/rpc_pubsub.rs @@ -792,7 +792,7 @@ mod tests { let stake_authority = Keypair::new(); let from = Keypair::new(); let stake_account = Keypair::new(); - let stake_program_id = stake::id(); + let stake_program_id = stake::program::id(); let bank = Bank::new(&genesis_config); let blockhash = bank.last_blockhash(); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); diff --git a/rpc/src/rpc_subscriptions.rs b/rpc/src/rpc_subscriptions.rs index 25f04f71c7bc98..6ee7146c8e6b28 100644 --- a/rpc/src/rpc_subscriptions.rs +++ b/rpc/src/rpc_subscriptions.rs @@ -1544,7 +1544,7 @@ pub(crate) mod tests { blockhash, 1, 16, - &stake::id(), + &stake::program::id(), ); bank_forks .write() @@ -1567,7 +1567,7 @@ pub(crate) mod tests { optimistically_confirmed_bank, ); subscriptions.add_program_subscription( - stake::id(), + stake::program::id(), Some(RpcProgramAccountsConfig { account_config: RpcAccountInfoConfig { commitment: Some(CommitmentConfig::processed()), @@ -1584,7 +1584,7 @@ pub(crate) mod tests { .program_subscriptions .read() .unwrap() - .contains_key(&stake::id())); + .contains_key(&stake::program::id())); subscriptions.notify_subscribers(CommitmentSlots::default()); let (response, _) = robust_poll_or_panic(transport_receiver); @@ -1616,7 +1616,7 @@ pub(crate) mod tests { .program_subscriptions .read() .unwrap() - .contains_key(&stake::id())); + .contains_key(&stake::program::id())); } #[test] @@ -2044,7 +2044,7 @@ pub(crate) mod tests { blockhash, 1, 16, - &stake::id(), + &stake::program::id(), ); // Add the transaction to the 1st bank and then freeze the bank diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 4e6052e1fa3f93..4b33dc34e760e9 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -1907,7 +1907,7 @@ impl Bank { if self .feature_set .is_active(&feature_set::filter_stake_delegation_accounts::id()) - && (stake_account.owner() != &stake::id() + && (stake_account.owner() != &stake::program::id() || vote_account.owner() != &solana_vote_program::id()) { datapoint_warn!( diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index 7b5b7b1d43c93d..a160b590ef568f 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -56,7 +56,7 @@ fn genesis_builtins() -> Vec { ), Builtin::new( "stake_program", - stake::id(), + stake::program::id(), with_program_logging!(solana_stake_program::stake_instruction::process_instruction), ), Builtin::new( diff --git a/runtime/src/non_circulating_supply.rs b/runtime/src/non_circulating_supply.rs index 16187f83afeb53..531d5327e85637 100644 --- a/runtime/src/non_circulating_supply.rs +++ b/runtime/src/non_circulating_supply.rs @@ -36,15 +36,15 @@ pub fn calculate_non_circulating_supply(bank: &Arc) -> NonCirculatingSuppl .contains(&AccountIndex::ProgramId) { bank.get_filtered_indexed_accounts( - &IndexKey::ProgramId(stake::id()), + &IndexKey::ProgramId(stake::program::id()), // The program-id account index checks for Account owner on inclusion. However, due to // the current AccountsDb implementation, an account may remain in storage as a // zero-lamport Account::Default() after being wiped and reinitialized in later // updates. We include the redundant filter here to avoid returning these accounts. - |account| account.owner() == &stake::id(), + |account| account.owner() == &stake::program::id(), ) } else { - bank.get_program_accounts(&stake::id()) + bank.get_program_accounts(&stake::program::id()) }; for (pubkey, account) in stake_accounts.iter() { let stake_account = stake_state::from(account).unwrap_or_default(); @@ -239,7 +239,7 @@ mod tests { balance, &StakeState::Initialized(meta), std::mem::size_of::(), - &stake::id(), + &stake::program::id(), ) .unwrap(); accounts.insert(pubkey, stake_account); diff --git a/runtime/src/stakes.rs b/runtime/src/stakes.rs index 583ab569208cf4..7148094b316ac9 100644 --- a/runtime/src/stakes.rs +++ b/runtime/src/stakes.rs @@ -115,7 +115,7 @@ impl Stakes { pub fn is_stake(account: &AccountSharedData) -> bool { solana_vote_program::check_id(account.owner()) - || stake::check_id(account.owner()) + || stake::program::check_id(account.owner()) && account.data().len() >= std::mem::size_of::() } @@ -152,7 +152,7 @@ impl Stakes { .insert(*pubkey, (stake, ArcVoteAccount::from(account.clone()))); } old.map(|(_, account)| account) - } else if stake::check_id(account.owner()) { + } else if stake::program::check_id(account.owner()) { // old_stake is stake lamports and voter_pubkey from the pre-store() version let old_stake = self.stake_delegations.get(pubkey).map(|delegation| { ( @@ -568,7 +568,7 @@ pub mod tests { // not a stake account, and whacks above entry stakes.store( &stake_pubkey, - &AccountSharedData::new(1, 0, &stake::id()), + &AccountSharedData::new(1, 0, &stake::program::id()), true, true, ); diff --git a/runtime/tests/stake.rs b/runtime/tests/stake.rs index f2ddfdea9cfb4b..c53599fe0fc57c 100644 --- a/runtime/tests/stake.rs +++ b/runtime/tests/stake.rs @@ -118,7 +118,7 @@ fn test_stake_create_and_split_single_signature() { let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); - let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::id()).unwrap(); + let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); let authorized = Authorized::auto(&staker_pubkey); @@ -145,7 +145,7 @@ fn test_stake_create_and_split_single_signature() { // split the stake let split_stake_address = - Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::id()).unwrap(); + Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::program::id()).unwrap(); // Test split let message = Message::new( &stake_instruction::split_with_seed( @@ -187,7 +187,7 @@ fn test_stake_create_and_split_to_existing_system_account() { let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); - let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::id()).unwrap(); + let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); let authorized = Authorized::auto(&staker_pubkey); @@ -212,7 +212,7 @@ fn test_stake_create_and_split_to_existing_system_account() { .expect("failed to create and delegate stake account"); let split_stake_address = - Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::id()).unwrap(); + Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::program::id()).unwrap(); // First, put a system account where we want the new stake account let existing_lamports = 42; @@ -513,7 +513,7 @@ fn test_create_stake_account_from_seed() { let bank_client = BankClient::new_shared(&bank); let seed = "test-string"; - let stake_pubkey = Pubkey::create_with_seed(&mint_pubkey, seed, &stake::id()).unwrap(); + let stake_pubkey = Pubkey::create_with_seed(&mint_pubkey, seed, &stake::program::id()).unwrap(); // Create Vote Account let message = Message::new( diff --git a/sdk/program/src/stake/instruction.rs b/sdk/program/src/stake/instruction.rs index cbb4e82bb413cb..ab01f66d8a8ab4 100644 --- a/sdk/program/src/stake/instruction.rs +++ b/sdk/program/src/stake/instruction.rs @@ -1,6 +1,6 @@ use { crate::stake::{ - config, id, + config, program::id, state::{Authorized, Lockup, StakeAuthorize, StakeState}, }, crate::{ diff --git a/sdk/program/src/stake/mod.rs b/sdk/program/src/stake/mod.rs index 29fa8eb874d162..e2c39b59e163c4 100644 --- a/sdk/program/src/stake/mod.rs +++ b/sdk/program/src/stake/mod.rs @@ -1,5 +1,4 @@ pub mod config; pub mod instruction; +pub mod program; pub mod state; - -crate::declare_id!("Stake11111111111111111111111111111111111111"); diff --git a/sdk/program/src/stake/program.rs b/sdk/program/src/stake/program.rs new file mode 100644 index 00000000000000..e48ae8dca64861 --- /dev/null +++ b/sdk/program/src/stake/program.rs @@ -0,0 +1 @@ +crate::declare_id!("Stake11111111111111111111111111111111111111"); diff --git a/stake-accounts/src/stake_accounts.rs b/stake-accounts/src/stake_accounts.rs index d52ddbdcdbfae8..37b4837408fa4c 100644 --- a/stake-accounts/src/stake_accounts.rs +++ b/stake-accounts/src/stake_accounts.rs @@ -14,7 +14,7 @@ const DAYS_PER_YEAR: f64 = 365.25; const SECONDS_PER_YEAR: i64 = (SECONDS_PER_DAY as f64 * DAYS_PER_YEAR) as i64; pub(crate) fn derive_stake_account_address(base_pubkey: &Pubkey, i: usize) -> Pubkey { - Pubkey::create_with_seed(base_pubkey, &i.to_string(), &stake::id()).unwrap() + Pubkey::create_with_seed(base_pubkey, &i.to_string(), &stake::program::id()).unwrap() } // Return derived addresses diff --git a/stake-monitor/src/lib.rs b/stake-monitor/src/lib.rs index 6dff4a1721f10c..a16168a731f92d 100644 --- a/stake-monitor/src/lib.rs +++ b/stake-monitor/src/lib.rs @@ -82,7 +82,7 @@ fn process_transaction( // Look for stake operations for instruction in message.instructions.iter().rev() { let program_pubkey = message.account_keys[instruction.program_id_index as usize]; - if program_pubkey != stake::id() { + if program_pubkey != stake::program::id() { continue; } diff --git a/transaction-status/src/parse_instruction.rs b/transaction-status/src/parse_instruction.rs index 82a06d5c03accf..15b5b7bf07fce5 100644 --- a/transaction-status/src/parse_instruction.rs +++ b/transaction-status/src/parse_instruction.rs @@ -19,7 +19,7 @@ lazy_static! { static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id(); static ref MEMO_V1_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::v1::id().to_bytes()); static ref MEMO_V3_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::id().to_bytes()); - static ref STAKE_PROGRAM_ID: Pubkey = stake::id(); + static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id(); From 463166482afab8fa436212855bcd69a96940a502 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 14 Jun 2021 22:48:23 +0200 Subject: [PATCH 12/14] Re-export from solana_sdk and mark deprecated --- cli/src/cluster_query.rs | 4 ++-- cli/tests/stake.rs | 3 ++- programs/stake/src/config.rs | 6 ++++++ programs/stake/src/lib.rs | 6 ++++++ programs/stake/src/stake_instruction.rs | 8 +++++++- programs/stake/src/stake_state.rs | 9 +++++++-- runtime/tests/stake.rs | 6 ++++-- sdk/program/src/stake/instruction.rs | 3 ++- 8 files changed, 36 insertions(+), 9 deletions(-) diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 282440b923848e..236ce9c2b396ff 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -1704,8 +1704,8 @@ pub fn process_show_stakes( ]); } } - let all_stake_accounts = - rpc_client.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?; + let all_stake_accounts = rpc_client + .get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?; let stake_history_account = rpc_client.get_account(&stake_history::id())?; let clock_account = rpc_client.get_account(&sysvar::clock::id())?; let clock: Clock = from_account(&clock_account).ok_or_else(|| { diff --git a/cli/tests/stake.rs b/cli/tests/stake.rs index 98348cd9acb8c0..162aa45134d5ee 100644 --- a/cli/tests/stake.rs +++ b/cli/tests/stake.rs @@ -1557,6 +1557,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() { from: 0, }; process_command(&config).unwrap(); - let seed_address = Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap(); + let seed_address = + Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap(); check_recent_balance(50_000, &rpc_client, &seed_address); } diff --git a/programs/stake/src/config.rs b/programs/stake/src/config.rs index 7564fde4bf3e1a..acd7416c2c0873 100644 --- a/programs/stake/src/config.rs +++ b/programs/stake/src/config.rs @@ -10,6 +10,12 @@ use solana_sdk::{ stake::config::{self, Config}, }; +#[deprecated( + since = "1.8.0", + note = "Please use `solana_sdk::stake::config` or `solana_program::stake::config` instead" +)] +pub use solana_sdk::stake::config::*; + pub fn from(account: &T) -> Option { get_config_data(&account.data()) .ok() diff --git a/programs/stake/src/lib.rs b/programs/stake/src/lib.rs index 8a03e59ee737a7..1de5e41071f634 100644 --- a/programs/stake/src/lib.rs +++ b/programs/stake/src/lib.rs @@ -2,6 +2,12 @@ #![allow(clippy::integer_arithmetic)] use solana_sdk::genesis_config::GenesisConfig; +#[deprecated( + since = "1.8.0", + note = "Please use `solana_sdk::stake::program::id` or `solana_program::stake::program::id` instead" +)] +pub use solana_sdk::stake::program::{check_id, id}; + pub mod config; pub mod stake_instruction; pub mod stake_state; diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 8bf2acc915a0d2..b80db4e5e2b824 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -8,11 +8,17 @@ use { process_instruction::{get_sysvar, InvokeContext}, program_utils::limited_deserialize, pubkey::Pubkey, - stake::{program::id, instruction::StakeInstruction}, + stake::{instruction::StakeInstruction, program::id}, sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory}, }, }; +#[deprecated( + since = "1.8.0", + note = "Please use `solana_sdk::stake::instruction` or `solana_program::stake::instruction` instead" +)] +pub use solana_sdk::stake::instruction::*; + pub fn process_instruction( _program_id: &Pubkey, data: &[u8], diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index e59d279f72997e..d342a19904c71e 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -16,8 +16,8 @@ use { rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, stake::{ config::Config, - program::id, instruction::{LockupArgs, StakeError}, + program::id, state::{Authorized, Delegation, Lockup, Meta, Stake, StakeAuthorize, StakeState}, }, stake_history::{StakeHistory, StakeHistoryEntry}, @@ -26,6 +26,12 @@ use { std::{collections::HashSet, convert::TryFrom}, }; +#[deprecated( + since = "1.8.0", + note = "Please use `solana_sdk::stake::state` or `solana_program::stake::state` instead" +)] +pub use solana_sdk::stake::state::*; + #[derive(Debug)] pub enum SkippedReason { ZeroPoints, @@ -1283,7 +1289,6 @@ mod tests { native_token, process_instruction::MockInvokeContext, pubkey::Pubkey, - stake::id, system_program, }; use solana_vote_program::vote_state; diff --git a/runtime/tests/stake.rs b/runtime/tests/stake.rs index c53599fe0fc57c..7c3d812641c1d4 100644 --- a/runtime/tests/stake.rs +++ b/runtime/tests/stake.rs @@ -118,7 +118,8 @@ fn test_stake_create_and_split_single_signature() { let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); - let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); + let stake_address = + Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); let authorized = Authorized::auto(&staker_pubkey); @@ -187,7 +188,8 @@ fn test_stake_create_and_split_to_existing_system_account() { let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); - let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); + let stake_address = + Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); let authorized = Authorized::auto(&staker_pubkey); diff --git a/sdk/program/src/stake/instruction.rs b/sdk/program/src/stake/instruction.rs index ab01f66d8a8ab4..3b4782144d0e1b 100644 --- a/sdk/program/src/stake/instruction.rs +++ b/sdk/program/src/stake/instruction.rs @@ -1,6 +1,7 @@ use { crate::stake::{ - config, program::id, + config, + program::id, state::{Authorized, Lockup, StakeAuthorize, StakeState}, }, crate::{ From 6a19e8914ee308e97ea85d61d2b59817580bc94e Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 15 Jun 2021 00:44:10 +0200 Subject: [PATCH 13/14] Address feedback --- programs/stake/src/stake_state.rs | 10 +++++----- sdk/program/src/stake/mod.rs | 5 ++++- sdk/program/src/stake/program.rs | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 sdk/program/src/stake/program.rs diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index d342a19904c71e..cf14e15504039a 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -197,7 +197,7 @@ fn calculate_stake_points( inflation_point_calc_tracer: &mut Option, fix_stake_deactivate: bool, ) -> u128 { - calculate_points_and_credits( + calculate_stake_points_and_credits( stake, vote_state, stake_history, @@ -210,7 +210,7 @@ fn calculate_stake_points( /// for a given stake and vote_state, calculate how many /// points were earned (credits * stake) and new value /// for credits_observed were the points paid -fn calculate_points_and_credits( +fn calculate_stake_points_and_credits( stake: &Stake, new_vote_state: &VoteState, stake_history: Option<&StakeHistory>, @@ -293,7 +293,7 @@ pub fn calculate_stake_rewards( inflation_point_calc_tracer: &mut Option, fix_stake_deactivate: bool, ) -> Option<(u64, u64, u64)> { - let (points, credits_observed) = calculate_points_and_credits( + let (points, credits_observed) = calculate_stake_points_and_credits( stake, vote_state, stake_history, @@ -3682,11 +3682,11 @@ mod tests { // assert the previous behavior is preserved where fix_stake_deactivate=false assert_eq!( (0, 0), - calculate_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), false) + calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), false) ); assert_eq!( (0, 4), - calculate_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), true) + calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), true) ); } diff --git a/sdk/program/src/stake/mod.rs b/sdk/program/src/stake/mod.rs index e2c39b59e163c4..bb43a067f6387d 100644 --- a/sdk/program/src/stake/mod.rs +++ b/sdk/program/src/stake/mod.rs @@ -1,4 +1,7 @@ pub mod config; pub mod instruction; -pub mod program; pub mod state; + +pub mod program { + crate::declare_id!("Stake11111111111111111111111111111111111111"); +} diff --git a/sdk/program/src/stake/program.rs b/sdk/program/src/stake/program.rs deleted file mode 100644 index e48ae8dca64861..00000000000000 --- a/sdk/program/src/stake/program.rs +++ /dev/null @@ -1 +0,0 @@ -crate::declare_id!("Stake11111111111111111111111111111111111111"); From e1ecfb69cc5c31c1ca1ad77ad7a2812c78e42b36 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 15 Jun 2021 11:33:25 +0200 Subject: [PATCH 14/14] Run cargo fmt --- programs/stake/src/stake_state.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index cf14e15504039a..55689679f0ae4f 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -3682,7 +3682,13 @@ mod tests { // assert the previous behavior is preserved where fix_stake_deactivate=false assert_eq!( (0, 0), - calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), false) + calculate_stake_points_and_credits( + &stake, + &vote_state, + None, + &mut null_tracer(), + false + ) ); assert_eq!( (0, 4),