v1.7: Stake refactor (Manual backport of #17906) (#17978)

* Refactor stake program into solana_program (#17906)

* Move stake state / instructions into solana_program

* Update account-decoder

* Update cli and runtime

* Update all other parts

* Commit Cargo.lock changes in programs/bpf

* Update cli stake instruction import

* Allow integer arithmetic

* Update ABI digest

* Bump rust mem instruction count

* Remove useless structs

* Move stake::id() -> stake::program::id()

* Re-export from solana_sdk and mark deprecated

* Address feedback

* Run cargo fmt

* Run cargo fmt post cherry-pick
This commit is contained in:
Jon Cinque
2021-06-15 23:43:22 +02:00
committed by GitHub
parent cdd2a51f1f
commit 0c90307677
58 changed files with 1765 additions and 1712 deletions

9
Cargo.lock generated
View File

@@ -3888,7 +3888,6 @@ dependencies = [
"serde_json", "serde_json",
"solana-config-program", "solana-config-program",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-vote-program", "solana-vote-program",
"spl-token", "spl-token",
"thiserror", "thiserror",
@@ -4167,7 +4166,6 @@ dependencies = [
"solana-net-utils", "solana-net-utils",
"solana-remote-wallet", "solana-remote-wallet",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-transaction-status", "solana-transaction-status",
"solana-version", "solana-version",
"solana-vote-program", "solana-vote-program",
@@ -4208,7 +4206,6 @@ dependencies = [
"solana-clap-utils", "solana-clap-utils",
"solana-client", "solana-client",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-transaction-status", "solana-transaction-status",
"solana-vote-program", "solana-vote-program",
"spl-memo", "spl-memo",
@@ -4669,7 +4666,6 @@ dependencies = [
"solana-rayon-threadlimit", "solana-rayon-threadlimit",
"solana-runtime", "solana-runtime",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-storage-bigtable", "solana-storage-bigtable",
"solana-storage-proto", "solana-storage-proto",
"solana-transaction-status", "solana-transaction-status",
@@ -4905,7 +4901,6 @@ dependencies = [
"solana-metrics", "solana-metrics",
"solana-rayon-threadlimit", "solana-rayon-threadlimit",
"solana-sdk", "solana-sdk",
"solana-stake-program",
] ]
[[package]] [[package]]
@@ -5035,7 +5030,6 @@ dependencies = [
"solana-logger 1.7.2", "solana-logger 1.7.2",
"solana-runtime", "solana-runtime",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-vote-program", "solana-vote-program",
"thiserror", "thiserror",
"tokio 1.1.1", "tokio 1.1.1",
@@ -5293,7 +5287,6 @@ dependencies = [
"solana-metrics", "solana-metrics",
"solana-rpc", "solana-rpc",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-transaction-status", "solana-transaction-status",
"solana-version", "solana-version",
"tempfile", "tempfile",
@@ -5430,7 +5423,6 @@ dependencies = [
"solana-remote-wallet", "solana-remote-wallet",
"solana-runtime", "solana-runtime",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-transaction-status", "solana-transaction-status",
"solana-version", "solana-version",
"spl-associated-token-account", "spl-associated-token-account",
@@ -5454,7 +5446,6 @@ dependencies = [
"solana-account-decoder", "solana-account-decoder",
"solana-runtime", "solana-runtime",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-vote-program", "solana-vote-program",
"spl-associated-token-account", "spl-associated-token-account",
"spl-memo", "spl-memo",

View File

@@ -21,7 +21,6 @@ serde_derive = "1.0.103"
serde_json = "1.0.56" serde_json = "1.0.56"
solana-config-program = { path = "../programs/config", version = "=1.7.2" } solana-config-program = { path = "../programs/config", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" } solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] } spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
thiserror = "1.0" thiserror = "1.0"

View File

@@ -9,14 +9,14 @@ use crate::{
}; };
use inflector::Inflector; use inflector::Inflector;
use serde_json::Value; 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 std::collections::HashMap;
use thiserror::Error; use thiserror::Error;
lazy_static! { lazy_static! {
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id(); 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 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::program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id(); static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();

View File

@@ -6,10 +6,10 @@ use bincode::deserialize;
use serde_json::Value; use serde_json::Value;
use solana_config_program::{get_config_data, ConfigKeys}; use solana_config_program::{get_config_data, ConfigKeys};
use solana_sdk::pubkey::Pubkey; 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<ConfigAccountType, ParseAccountError> { pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
let parsed_account = if pubkey == &solana_stake_program::config::id() { let parsed_account = if pubkey == &stake_config::id() {
get_config_data(data) get_config_data(data)
.ok() .ok()
.and_then(|data| deserialize::<StakeConfig>(data).ok()) .and_then(|data| deserialize::<StakeConfig>(data).ok())
@@ -101,11 +101,7 @@ mod test {
}; };
let stake_config_account = create_config_account(vec![], &stake_config, 10); let stake_config_account = create_config_account(vec![], &stake_config, 10);
assert_eq!( assert_eq!(
parse_config( parse_config(&stake_config_account.data(), &stake_config::id()).unwrap(),
&stake_config_account.data(),
&solana_stake_program::config::id()
)
.unwrap(),
ConfigAccountType::StakeConfig(UiStakeConfig { ConfigAccountType::StakeConfig(UiStakeConfig {
warmup_cooldown_rate: 0.25, warmup_cooldown_rate: 0.25,
slash_penalty: 50, slash_penalty: 50,

View File

@@ -4,7 +4,7 @@ use crate::{
}; };
use bincode::deserialize; use bincode::deserialize;
use solana_sdk::clock::{Epoch, UnixTimestamp}; 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<StakeAccountType, ParseAccountError> { pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
let stake_state: StakeState = deserialize(data) let stake_state: StakeState = deserialize(data)

View File

@@ -23,7 +23,6 @@ solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" } solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
solana-client = { path = "../client", version = "=1.7.2" } solana-client = { path = "../client", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" } solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" } solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] } spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }

View File

@@ -25,10 +25,10 @@ use {
native_token::lamports_to_sol, native_token::lamports_to_sol,
pubkey::Pubkey, pubkey::Pubkey,
signature::Signature, signature::Signature,
stake::state::{Authorized, Lockup},
stake_history::StakeHistoryEntry, stake_history::StakeHistoryEntry,
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
}, },
solana_stake_program::stake_state::{Authorized, Lockup},
solana_transaction_status::{ solana_transaction_status::{
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus, EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
UiTransactionStatusMeta, UiTransactionStatusMeta,

View File

@@ -5,7 +5,7 @@ use {
indicatif::{ProgressBar, ProgressStyle}, indicatif::{ProgressBar, ProgressStyle},
solana_sdk::{ solana_sdk::{
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol, 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, solana_transaction_status::UiTransactionStatusMeta,
spl_memo::id as spl_memo_id, spl_memo::id as spl_memo_id,
@@ -244,10 +244,9 @@ pub fn write_transaction<W: io::Write>(
writeln!(w, "{} {:?}", prefix, vote_instruction)?; writeln!(w, "{} {:?}", prefix, vote_instruction)?;
raw = false; raw = false;
} }
} else if program_pubkey == solana_stake_program::id() { } else if program_pubkey == stake::program::id() {
if let Ok(stake_instruction) = limited_deserialize::< if let Ok(stake_instruction) =
solana_stake_program::stake_instruction::StakeInstruction, limited_deserialize::<stake::instruction::StakeInstruction>(&instruction.data)
>(&instruction.data)
{ {
writeln!(w, "{} {:?}", prefix, stake_instruction)?; writeln!(w, "{} {:?}", prefix, stake_instruction)?;
raw = false; raw = false;

View File

@@ -41,7 +41,6 @@ solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
solana_rbpf = "=0.2.11" solana_rbpf = "=0.2.11"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" } solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" } solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
solana-version = { path = "../version", version = "=1.7.2" } solana-version = { path = "../version", version = "=1.7.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" } solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }

View File

@@ -45,14 +45,15 @@ use solana_sdk::{
message::Message, message::Message,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Signature, Signer, SignerError}, signature::{Signature, Signer, SignerError},
stake::{
self,
instruction::LockupArgs,
state::{Lockup, StakeAuthorize},
},
system_instruction::{self, SystemError}, system_instruction::{self, SystemError},
system_program, system_program,
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
}; };
use solana_stake_program::{
stake_instruction::LockupArgs,
stake_state::{Lockup, StakeAuthorize},
};
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding}; use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
use solana_vote_program::vote_state::VoteAuthorize; use solana_vote_program::vote_state::VoteAuthorize;
use std::{ use std::{
@@ -932,7 +933,7 @@ pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> { fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
matches.value_of(arg_name).and_then(|v| match v { matches.value_of(arg_name).and_then(|v| match v {
"NONCE" => Some(system_program::id()), "NONCE" => Some(system_program::id()),
"STAKE" => Some(solana_stake_program::id()), "STAKE" => Some(stake::program::id()),
"VOTE" => Some(solana_vote_program::id()), "VOTE" => Some(solana_vote_program::id()),
_ => pubkey_of(matches, arg_name), _ => pubkey_of(matches, arg_name),
}) })
@@ -2487,7 +2488,7 @@ mod tests {
let from_pubkey = Some(solana_sdk::pubkey::new_rand()); let from_pubkey = Some(solana_sdk::pubkey::new_rand());
let from_str = from_pubkey.unwrap().to_string(); let from_str = from_pubkey.unwrap().to_string();
for (name, program_id) in &[ for (name, program_id) in &[
("STAKE", solana_stake_program::id()), ("STAKE", stake::program::id()),
("VOTE", solana_vote_program::id()), ("VOTE", solana_vote_program::id()),
("NONCE", system_program::id()), ("NONCE", system_program::id()),
] { ] {
@@ -2523,7 +2524,7 @@ mod tests {
command: CliCommand::CreateAddressWithSeed { command: CliCommand::CreateAddressWithSeed {
from_pubkey: None, from_pubkey: None,
seed: "seed".to_string(), seed: "seed".to_string(),
program_id: solana_stake_program::id(), program_id: stake::program::id(),
}, },
signers: vec![read_keypair_file(&keypair_file).unwrap().into()], signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
} }
@@ -2786,11 +2787,11 @@ mod tests {
config.command = CliCommand::CreateAddressWithSeed { config.command = CliCommand::CreateAddressWithSeed {
from_pubkey: Some(from_pubkey), from_pubkey: Some(from_pubkey),
seed: "seed".to_string(), seed: "seed".to_string(),
program_id: solana_stake_program::id(), program_id: stake::program::id(),
}; };
let address = process_command(&config); let address = process_command(&config);
let expected_address = let expected_address =
Pubkey::create_with_seed(&from_pubkey, "seed", &solana_stake_program::id()).unwrap(); Pubkey::create_with_seed(&from_pubkey, "seed", &stake::program::id()).unwrap();
assert_eq!(address.unwrap(), expected_address.to_string()); assert_eq!(address.unwrap(), expected_address.to_string());
// Need airdrop cases // Need airdrop cases
@@ -3177,7 +3178,7 @@ mod tests {
memo: None, memo: None,
fee_payer: 0, fee_payer: 0,
derived_address_seed: Some(derived_address_seed), derived_address_seed: Some(derived_address_seed),
derived_address_program_id: Some(solana_stake_program::id()), derived_address_program_id: Some(stake::program::id()),
}, },
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),], signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
} }

View File

@@ -46,7 +46,9 @@ use solana_sdk::{
rent::Rent, rent::Rent,
rpc_port::DEFAULT_RPC_PORT_STR, rpc_port::DEFAULT_RPC_PORT_STR,
signature::Signature, signature::Signature,
slot_history, system_instruction, system_program, slot_history,
stake::{self, state::StakeState},
system_instruction, system_program,
sysvar::{ sysvar::{
self, self,
slot_history::SlotHistory, slot_history::SlotHistory,
@@ -55,7 +57,6 @@ use solana_sdk::{
timing, timing,
transaction::Transaction, transaction::Transaction,
}; };
use solana_stake_program::stake_state::StakeState;
use solana_transaction_status::UiTransactionEncoding; use solana_transaction_status::UiTransactionEncoding;
use solana_vote_program::vote_state::VoteState; use solana_vote_program::vote_state::VoteState;
use std::{ use std::{
@@ -1707,7 +1708,7 @@ pub fn process_show_stakes(
} }
} }
let all_stake_accounts = rpc_client let all_stake_accounts = rpc_client
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?; .get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?;
let stake_history_account = rpc_client.get_account(&stake_history::id())?; let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let clock_account = rpc_client.get_account(&sysvar::clock::id())?; let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
let clock: Clock = from_account(&clock_account).ok_or_else(|| { let clock: Clock = from_account(&clock_account).ok_or_else(|| {

View File

@@ -36,6 +36,11 @@ use solana_sdk::{
feature, feature_set, feature, feature_set,
message::Message, message::Message,
pubkey::Pubkey, pubkey::Pubkey,
stake::{
self,
instruction::{self as stake_instruction, LockupArgs, StakeError},
state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
},
system_instruction::SystemError, system_instruction::SystemError,
sysvar::{ sysvar::{
clock, clock,
@@ -43,10 +48,6 @@ use solana_sdk::{
}, },
transaction::Transaction, 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 solana_vote_program::vote_state::VoteState;
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
@@ -971,7 +972,7 @@ pub fn process_create_stake_account(
) -> ProcessResult { ) -> ProcessResult {
let stake_account = config.signers[stake_account]; let stake_account = config.signers[stake_account];
let stake_account_address = if let Some(seed) = seed { 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::program::id())?
} else { } else {
stake_account.pubkey() stake_account.pubkey()
}; };
@@ -1039,7 +1040,7 @@ pub fn process_create_stake_account(
if !sign_only { if !sign_only {
if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) { 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::program::id() {
format!("Stake account {} already exists", stake_account_address) format!("Stake account {} already exists", stake_account_address)
} else { } else {
format!( format!(
@@ -1195,7 +1196,7 @@ pub fn process_deactivate_stake_account(
let stake_authority = config.signers[stake_authority]; let stake_authority = config.signers[stake_authority];
let stake_account_address = if let Some(seed) = seed { 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::program::id())?
} else { } else {
*stake_account_pubkey *stake_account_pubkey
}; };
@@ -1273,7 +1274,7 @@ pub fn process_withdraw_stake(
let custodian = custodian.map(|index| config.signers[index]); let custodian = custodian.map(|index| config.signers[index]);
let stake_account_address = if let Some(seed) = seed { 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::program::id())?
} else { } else {
*stake_account_pubkey *stake_account_pubkey
}; };
@@ -1394,18 +1395,14 @@ pub fn process_split_stake(
let stake_authority = config.signers[stake_authority]; let stake_authority = config.signers[stake_authority];
let split_stake_account_address = if let Some(seed) = split_stake_account_seed { let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
Pubkey::create_with_seed( Pubkey::create_with_seed(&split_stake_account.pubkey(), &seed, &stake::program::id())?
&split_stake_account.pubkey(),
&seed,
&solana_stake_program::id(),
)?
} else { } else {
split_stake_account.pubkey() split_stake_account.pubkey()
}; };
if !sign_only { if !sign_only {
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) { 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::program::id() {
format!( format!(
"Stake account {} already exists", "Stake account {} already exists",
split_stake_account_address split_stake_account_address
@@ -1540,7 +1537,7 @@ pub fn process_merge_stake(
if !sign_only { if !sign_only {
for stake_account_address in &[stake_account_pubkey, source_stake_account_pubkey] { 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 let Ok(stake_account) = rpc_client.get_account(stake_account_address) {
if stake_account.owner != solana_stake_program::id() { if stake_account.owner != stake::program::id() {
return Err(CliError::BadParameter(format!( return Err(CliError::BadParameter(format!(
"Account {} is not a stake account", "Account {} is not a stake account",
stake_account_address stake_account_address
@@ -1876,7 +1873,7 @@ pub fn process_show_stake_account(
with_rewards: Option<usize>, with_rewards: Option<usize>,
) -> ProcessResult { ) -> ProcessResult {
let stake_account = rpc_client.get_account(stake_account_address)?; let stake_account = rpc_client.get_account(stake_account_address)?;
if stake_account.owner != solana_stake_program::id() { if stake_account.owner != stake::program::id() {
return Err(CliError::RpcRequestError(format!( return Err(CliError::RpcRequestError(format!(
"{:?} is not a stake account", "{:?} is not a stake account",
stake_account_address, stake_account_address,

View File

@@ -17,10 +17,11 @@ use solana_sdk::{
nonce::State as NonceState, nonce::State as NonceState,
pubkey::Pubkey, pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, Signer}, signature::{keypair_from_seed, Keypair, Signer},
}; stake::{
use solana_stake_program::{ self,
stake_instruction::LockupArgs, instruction::LockupArgs,
stake_state::{Lockup, StakeAuthorize, StakeState}, state::{Lockup, StakeAuthorize, StakeState},
},
}; };
#[test] #[test]
@@ -139,7 +140,7 @@ fn test_seed_stake_delegation_and_deactivation() {
let stake_address = Pubkey::create_with_seed( let stake_address = Pubkey::create_with_seed(
&config_validator.signers[0].pubkey(), &config_validator.signers[0].pubkey(),
"hi there", "hi there",
&solana_stake_program::id(), &stake::program::id(),
) )
.expect("bad seed"); .expect("bad seed");
@@ -1557,6 +1558,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
}; };
process_command(&config).unwrap(); process_command(&config).unwrap();
let seed_address = let seed_address =
Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap(); Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
check_recent_balance(50_000, &rpc_client, &seed_address); check_recent_balance(50_000, &rpc_client, &seed_address);
} }

View File

@@ -16,6 +16,7 @@ use solana_sdk::{
nonce::State as NonceState, nonce::State as NonceState,
pubkey::Pubkey, pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, NullSigner, Signer}, signature::{keypair_from_seed, Keypair, NullSigner, Signer},
stake,
}; };
#[test] #[test]
@@ -513,7 +514,7 @@ fn test_transfer_with_seed() {
let sender_pubkey = config.signers[0].pubkey(); let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]); let recipient_pubkey = Pubkey::new(&[1u8; 32]);
let derived_address_seed = "seed".to_string(); let derived_address_seed = "seed".to_string();
let derived_address_program_id = solana_stake_program::id(); let derived_address_program_id = stake::program::id();
let derived_address = Pubkey::create_with_seed( let derived_address = Pubkey::create_with_seed(
&sender_pubkey, &sender_pubkey,
&derived_address_seed, &derived_address_seed,

View File

@@ -62,7 +62,6 @@ solana-runtime = { path = "../runtime", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-frozen-abi = { path = "../frozen-abi", version = "=1.7.2" } solana-frozen-abi = { path = "../frozen-abi", version = "=1.7.2" }
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.7.2" } solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-streamer = { path = "../streamer", version = "=1.7.2" } solana-streamer = { path = "../streamer", version = "=1.7.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" } solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
solana-version = { path = "../version", version = "=1.7.2" } solana-version = { path = "../version", version = "=1.7.2" }
@@ -81,6 +80,7 @@ num_cpus = "1.13.0"
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] } reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde_json = "1.0.56" serde_json = "1.0.56"
serial_test = "0.4.0" serial_test = "0.4.0"
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-version = { path = "../version", version = "=1.7.2" } solana-version = { path = "../version", version = "=1.7.2" }
symlink = "0.1.0" symlink = "0.1.0"
systemstat = "0.1.5" systemstat = "0.1.5"

View File

@@ -41,7 +41,7 @@ Create and manage accounts representing stake and rewards for delegations to
validators. validators.
- Program id: `Stake11111111111111111111111111111111111111` - 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 ## Vote Program

View File

@@ -26,9 +26,10 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::state::StakeState,
system_program, timing, 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 solana_vote_program::vote_state::{self, VoteState};
use std::{ use std::{
collections::HashMap, collections::HashMap,

View File

@@ -1,15 +1,22 @@
//! stakes generator //! stakes generator
use crate::{ use {
address_generator::AddressGenerator, crate::{
unlocks::{UnlockInfo, Unlocks}, address_generator::AddressGenerator,
}; unlocks::{UnlockInfo, Unlocks},
use solana_sdk::{ },
account::Account, clock::Slot, genesis_config::GenesisConfig, pubkey::Pubkey, system_program, solana_sdk::{
timing::years_as_slots, account::Account,
}; clock::Slot,
use solana_stake_program::{ genesis_config::GenesisConfig,
self, pubkey::Pubkey,
stake_state::{create_lockup_stake_account, Authorized, Lockup, StakeState}, stake::{
self,
state::{Authorized, Lockup, StakeState},
},
system_program,
timing::years_as_slots,
},
solana_stake_program::stake_state::create_lockup_stake_account,
}; };
#[derive(Debug)] #[derive(Debug)]
@@ -98,8 +105,7 @@ pub fn create_and_add_stakes(
genesis_config.ticks_per_slot, genesis_config.ticks_per_slot,
); );
let mut address_generator = let mut address_generator = AddressGenerator::new(&authorized.staker, &stake::program::id());
AddressGenerator::new(&authorized.staker, &solana_stake_program::id());
let stake_rent_reserve = StakeState::get_rent_exempt_reserve(&genesis_config.rent); let stake_rent_reserve = StakeState::get_rent_exempt_reserve(&genesis_config.rent);

View File

@@ -42,9 +42,10 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
shred_version::compute_shred_version, shred_version::compute_shred_version,
stake::{self, state::StakeState},
system_program, system_program,
}; };
use solana_stake_program::stake_state::{self, PointValue, StakeState}; use solana_stake_program::stake_state::{self, PointValue};
use solana_vote_program::{ use solana_vote_program::{
self, self,
vote_state::{self, VoteState}, vote_state::{self, VoteState},
@@ -1971,9 +1972,8 @@ fn main() {
} }
if remove_stake_accounts { if remove_stake_accounts {
for (address, mut account) in bank for (address, mut account) in
.get_program_accounts(&solana_stake_program::id()) bank.get_program_accounts(&stake::program::id()).into_iter()
.into_iter()
{ {
account.set_lamports(0); account.set_lamports(0);
bank.store_account(&address, &account); bank.store_account(&address, &account);

View File

@@ -46,7 +46,6 @@ solana-perf = { path = "../perf", version = "=1.7.2" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
solana-runtime = { path = "../runtime", version = "=1.7.2" } solana-runtime = { path = "../runtime", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" } solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" }
solana-storage-proto = { path = "../storage-proto", version = "=1.7.2" } solana-storage-proto = { path = "../storage-proto", version = "=1.7.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" } solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
@@ -67,7 +66,6 @@ features = ["lz4"]
assert_matches = "1.3.0" assert_matches = "1.3.0"
matches = "0.1.6" matches = "0.1.6"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" } solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
[build-dependencies] [build-dependencies]
rustc_version = "0.2" rustc_version = "0.2"

View File

@@ -74,13 +74,13 @@ pub(crate) mod tests {
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
signers::Signers, signers::Signers,
stake::{
instruction as stake_instruction,
state::{Authorized, Delegation, Lockup, Stake},
},
sysvar::stake_history::{self, StakeHistory}, sysvar::stake_history::{self, StakeHistory},
transaction::Transaction, transaction::Transaction,
}; };
use solana_stake_program::{
stake_instruction,
stake_state::{Authorized, Delegation, Lockup, Stake},
};
use solana_vote_program::{ use solana_vote_program::{
vote_instruction, vote_instruction,
vote_state::{VoteInit, VoteState, VoteStateVersions}, vote_state::{VoteInit, VoteState, VoteStateVersions},

View File

@@ -29,13 +29,14 @@ use solana_sdk::{
poh_config::PohConfig, poh_config::PohConfig,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::{
config as stake_config, instruction as stake_instruction,
state::{Authorized, Lockup},
},
system_transaction, system_transaction,
transaction::Transaction, transaction::Transaction,
}; };
use solana_stake_program::{ use solana_stake_program::{config::create_account as create_stake_config_account, stake_state};
config as stake_config, stake_instruction,
stake_state::{Authorized, Lockup, StakeState},
};
use solana_vote_program::{ use solana_vote_program::{
vote_instruction, vote_instruction,
vote_state::{VoteInit, VoteState}, vote_state::{VoteInit, VoteState},
@@ -190,7 +191,7 @@ impl LocalCluster {
// Replace staking config // Replace staking config
genesis_config.add_account( genesis_config.add_account(
stake_config::id(), stake_config::id(),
stake_config::create_account( create_stake_config_account(
1, 1,
&stake_config::Config { &stake_config::Config {
warmup_cooldown_rate: 1_000_000_000.0f64, warmup_cooldown_rate: 1_000_000_000.0f64,
@@ -568,7 +569,7 @@ impl LocalCluster {
) { ) {
(Ok(Some(stake_account)), Ok(Some(vote_account))) => { (Ok(Some(stake_account)), Ok(Some(vote_account))) => {
match ( match (
StakeState::stake_from(&stake_account), stake_state::stake_from(&stake_account),
VoteState::from(&vote_account), VoteState::from(&vote_account),
) { ) {
(Some(stake_state), Some(vote_state)) => { (Some(stake_state), Some(vote_state)) => {

View File

@@ -1402,7 +1402,7 @@ fn test_mainnet_beta_cluster_type() {
for program_id in [ for program_id in [
&solana_config_program::id(), &solana_config_program::id(),
&solana_sdk::system_program::id(), &solana_sdk::system_program::id(),
&solana_stake_program::id(), &solana_sdk::stake::program::id(),
&solana_vote_program::id(), &solana_vote_program::id(),
&solana_sdk::bpf_loader_deprecated::id(), &solana_sdk::bpf_loader_deprecated::id(),
&solana_sdk::bpf_loader::id(), &solana_sdk::bpf_loader::id(),

View File

@@ -23,7 +23,6 @@ solana-logger = { path = "../logger", version = "=1.7.2" }
solana-metrics = { path = "../metrics", version = "=1.7.2" } solana-metrics = { path = "../metrics", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
[lib] [lib]
name = "solana_perf" name = "solana_perf"

View File

@@ -1,10 +1,12 @@
use solana_sdk::hash::Hash; use solana_sdk::{
use solana_sdk::instruction::CompiledInstruction; hash::Hash,
use solana_sdk::signature::{Keypair, Signer}; instruction::CompiledInstruction,
use solana_sdk::system_instruction::SystemInstruction; signature::{Keypair, Signer},
use solana_sdk::system_program; stake,
use solana_sdk::system_transaction; system_instruction::SystemInstruction,
use solana_sdk::transaction::Transaction; system_program, system_transaction,
transaction::Transaction,
};
pub fn test_tx() -> Transaction { pub fn test_tx() -> Transaction {
let keypair1 = Keypair::new(); let keypair1 = Keypair::new();
@@ -22,7 +24,7 @@ pub fn test_multisig_tx() -> Transaction {
let transfer_instruction = SystemInstruction::Transfer { lamports }; 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::program::id()];
let instructions = vec![CompiledInstruction::new( let instructions = vec![CompiledInstruction::new(
0, 0,

View File

@@ -29,4 +29,3 @@ tokio = { version = "1", features = ["full"] }
[dev-dependencies] [dev-dependencies]
assert_matches = "1.3.0" assert_matches = "1.3.0"
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }

View File

@@ -12,6 +12,10 @@ use {
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::{
instruction as stake_instruction,
state::{Authorized, Lockup, StakeState},
},
system_instruction, system_program, system_instruction, system_program,
sysvar::{ sysvar::{
clock, clock,
@@ -20,10 +24,6 @@ use {
}, },
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
}, },
solana_stake_program::{
stake_instruction,
stake_state::{Authorized, Lockup, StakeState},
},
solana_vote_program::{ solana_vote_program::{
vote_instruction, vote_instruction,
vote_state::{VoteInit, VoteState}, vote_state::{VoteInit, VoteState},

View File

@@ -2715,7 +2715,6 @@ dependencies = [
"serde_json", "serde_json",
"solana-config-program", "solana-config-program",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-vote-program", "solana-vote-program",
"spl-token", "spl-token",
"thiserror", "thiserror",
@@ -3126,7 +3125,6 @@ dependencies = [
"solana-clap-utils", "solana-clap-utils",
"solana-client", "solana-client",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-transaction-status", "solana-transaction-status",
"solana-vote-program", "solana-vote-program",
"spl-memo", "spl-memo",
@@ -3626,7 +3624,6 @@ dependencies = [
"solana-account-decoder", "solana-account-decoder",
"solana-runtime", "solana-runtime",
"solana-sdk", "solana-sdk",
"solana-stake-program",
"solana-vote-program", "solana-vote-program",
"spl-associated-token-account", "spl-associated-token-account",
"spl-memo", "spl-memo",

View File

@@ -9,6 +9,7 @@ use solana_sdk::{
account::{Account, AccountSharedData}, account::{Account, AccountSharedData},
pubkey::Pubkey, pubkey::Pubkey,
short_vec, short_vec,
stake::config::Config as StakeConfig,
}; };
solana_sdk::declare_id!("Config1111111111111111111111111111111111111"); solana_sdk::declare_id!("Config1111111111111111111111111111111111111");
@@ -18,6 +19,13 @@ pub trait ConfigState: serde::Serialize + Default {
fn max_space() -> u64; 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. /// A collection of keys to be stored in Config account data.
#[derive(Debug, Default, Deserialize, Serialize)] #[derive(Debug, Default, Deserialize, Serialize)]
pub struct ConfigKeys { pub struct ConfigKeys {

View File

@@ -1,52 +1,36 @@
//! config for staking //! config for staking
//! carries variables that the stake program cares about //! carries variables that the stake program cares about
use bincode::{deserialize, serialized_size}; use bincode::deserialize;
use serde_derive::{Deserialize, Serialize}; use solana_config_program::{create_config_account, get_config_data};
use solana_config_program::{create_config_account, get_config_data, ConfigState};
use solana_sdk::{ use solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount}, account::{AccountSharedData, ReadableAccount, WritableAccount},
genesis_config::GenesisConfig, genesis_config::GenesisConfig,
instruction::InstructionError, instruction::InstructionError,
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
stake::config::{self, Config},
}; };
// stake config ID #[deprecated(
solana_sdk::declare_id!("StakeConfig11111111111111111111111111111111"); since = "1.7.2",
note = "Please use `solana_sdk::stake::config` or `solana_program::stake::config` instead"
)]
pub use solana_sdk::stake::config::*;
// means that no more than RATE of current effective stake may be added or subtracted per pub fn from<T: ReadableAccount>(account: &T) -> Option<Config> {
// epoch get_config_data(&account.data())
pub const DEFAULT_WARMUP_COOLDOWN_RATE: f64 = 0.25; .ok()
pub const DEFAULT_SLASH_PENALTY: u8 = ((5 * std::u8::MAX as usize) / 100) as u8; .and_then(|data| deserialize(data).ok())
#[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_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionError> {
pub fn from<T: ReadableAccount>(account: &T) -> Option<Self> { if !config::check_id(account.unsigned_key()) {
get_config_data(&account.data()) return Err(InstructionError::InvalidArgument);
.ok()
.and_then(|data| deserialize(data).ok())
} }
from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
} }
impl Default for Config { pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData {
fn default() -> Self { create_config_account(vec![], config, lamports)
Self {
warmup_cooldown_rate: DEFAULT_WARMUP_COOLDOWN_RATE,
slash_penalty: DEFAULT_SLASH_PENALTY,
}
}
}
impl ConfigState for Config {
fn max_space() -> u64 {
serialized_size(&Config::default()).unwrap()
}
} }
pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 { pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 {
@@ -55,22 +39,11 @@ pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 {
account.set_lamports(lamports.max(1)); account.set_lamports(lamports.max(1));
genesis_config.add_account(id(), account); genesis_config.add_account(config::id(), account);
lamports lamports
} }
pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData {
create_config_account(vec![], config, lamports)
}
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionError> {
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
Config::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -80,7 +53,7 @@ mod tests {
#[test] #[test]
fn test() { fn test() {
let account = RefCell::new(create_account(0, &Config::default())); let account = RefCell::new(create_account(0, &Config::default()));
assert_eq!(Config::from(&account.borrow()), Some(Config::default())); assert_eq!(from(&account.borrow()), Some(Config::default()));
assert_eq!( assert_eq!(
from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)), from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)),
Err(InstructionError::InvalidArgument) Err(InstructionError::InvalidArgument)

View File

@@ -2,15 +2,16 @@
#![allow(clippy::integer_arithmetic)] #![allow(clippy::integer_arithmetic)]
use solana_sdk::genesis_config::GenesisConfig; use solana_sdk::genesis_config::GenesisConfig;
#[deprecated(
since = "1.7.2",
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 config;
pub mod stake_instruction; pub mod stake_instruction;
pub mod stake_state; pub mod stake_state;
solana_sdk::declare_id!("Stake11111111111111111111111111111111111111");
pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 { pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 {
config::add_genesis_account(genesis_config) config::add_genesis_account(genesis_config)
} }
#[macro_use]
extern crate solana_frozen_abi_macro;

View File

@@ -1,481 +1,23 @@
use crate::{ use {
config, id, crate::{config, stake_state::StakeAccount},
stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState}, 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::{instruction::StakeInstruction, program::id},
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 #[deprecated(
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] since = "1.7.2",
pub enum StakeError { note = "Please use `solana_sdk::stake::instruction` or `solana_program::stake::instruction` instead"
#[error("not enough credits to redeem")] )]
NoCreditsToRedeem, pub use solana_sdk::stake::instruction::*;
#[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<E> DecodeError<E> 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<UnixTimestamp>,
pub epoch: Option<Epoch>,
pub custodian: Option<Pubkey>,
}
#[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<Instruction> {
vec![
system_instruction::create_account_with_seed(
from_pubkey,
stake_pubkey,
base,
seed,
lamports,
std::mem::size_of::<StakeState>() as u64,
&id(),
),
initialize(stake_pubkey, authorized, lockup),
]
}
pub fn create_account(
from_pubkey: &Pubkey,
stake_pubkey: &Pubkey,
authorized: &Authorized,
lockup: &Lockup,
lamports: u64,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
from_pubkey,
stake_pubkey,
lamports,
std::mem::size_of::<StakeState>() 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<Instruction> {
vec![
system_instruction::allocate(split_stake_pubkey, std::mem::size_of::<StakeState>() as u64),
system_instruction::assign(split_stake_pubkey, &id()),
_split(
stake_pubkey,
authorized_pubkey,
lamports,
split_stake_pubkey,
),
]
}
pub fn split_with_seed(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
lamports: u64,
split_stake_pubkey: &Pubkey, // derived using create_with_seed()
base: &Pubkey, // base
seed: &str, // seed
) -> Vec<Instruction> {
vec![
system_instruction::allocate_with_seed(
split_stake_pubkey,
base,
seed,
std::mem::size_of::<StakeState>() as u64,
&id(),
),
_split(
stake_pubkey,
authorized_pubkey,
lamports,
split_stake_pubkey,
),
]
}
pub fn merge(
destination_stake_pubkey: &Pubkey,
source_stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
) -> Vec<Instruction> {
let account_metas = vec![
AccountMeta::new(*destination_stake_pubkey, false),
AccountMeta::new(*source_stake_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true),
];
vec![Instruction::new_with_bincode(
id(),
&StakeInstruction::Merge,
account_metas,
)]
}
pub fn create_account_and_delegate_stake(
from_pubkey: &Pubkey,
stake_pubkey: &Pubkey,
vote_pubkey: &Pubkey,
authorized: &Authorized,
lockup: &Lockup,
lamports: u64,
) -> Vec<Instruction> {
let mut instructions = create_account(from_pubkey, stake_pubkey, authorized, lockup, lamports);
instructions.push(delegate_stake(
stake_pubkey,
&authorized.staker,
vote_pubkey,
));
instructions
}
pub fn create_account_with_seed_and_delegate_stake(
from_pubkey: &Pubkey,
stake_pubkey: &Pubkey,
base: &Pubkey,
seed: &str,
vote_pubkey: &Pubkey,
authorized: &Authorized,
lockup: &Lockup,
lamports: u64,
) -> Vec<Instruction> {
let mut instructions = create_account_with_seed(
from_pubkey,
stake_pubkey,
base,
seed,
authorized,
lockup,
lamports,
);
instructions.push(delegate_stake(
stake_pubkey,
&authorized.staker,
vote_pubkey,
));
instructions
}
pub fn authorize(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
new_authorized_pubkey: &Pubkey,
stake_authorize: StakeAuthorize,
custodian_pubkey: Option<&Pubkey>,
) -> Instruction {
let mut account_metas = vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true),
];
if let Some(custodian_pubkey) = custodian_pubkey {
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
}
Instruction::new_with_bincode(
id(),
&StakeInstruction::Authorize(*new_authorized_pubkey, stake_authorize),
account_metas,
)
}
pub fn authorize_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( pub fn process_instruction(
_program_id: &Pubkey, _program_id: &Pubkey,
@@ -637,9 +179,15 @@ mod tests {
use bincode::serialize; use bincode::serialize;
use solana_sdk::{ use solana_sdk::{
account::{self, Account, AccountSharedData, WritableAccount}, account::{self, Account, AccountSharedData, WritableAccount},
instruction::Instruction,
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
process_instruction::{mock_set_sysvar, MockInvokeContext}, process_instruction::{mock_set_sysvar, MockInvokeContext},
rent::Rent, rent::Rent,
stake::{
config as stake_config,
instruction::{self, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
sysvar::stake_history::StakeHistory, sysvar::stake_history::StakeHistory,
}; };
use std::cell::RefCell; use std::cell::RefCell;
@@ -685,8 +233,8 @@ mod tests {
)) ))
} else if sysvar::stake_history::check_id(&meta.pubkey) { } else if sysvar::stake_history::check_id(&meta.pubkey) {
account::create_account_shared_data_for_test(&StakeHistory::default()) account::create_account_shared_data_for_test(&StakeHistory::default())
} else if config::check_id(&meta.pubkey) { } else if stake_config::check_id(&meta.pubkey) {
config::create_account(0, &config::Config::default()) config::create_account(0, &stake_config::Config::default())
} else if sysvar::rent::check_id(&meta.pubkey) { } else if sysvar::rent::check_id(&meta.pubkey) {
account::create_account_shared_data_for_test(&Rent::default()) account::create_account_shared_data_for_test(&Rent::default())
} else if meta.pubkey == invalid_stake_state_pubkey() { } else if meta.pubkey == invalid_stake_state_pubkey() {
@@ -735,7 +283,7 @@ mod tests {
#[test] #[test]
fn test_stake_process_instruction() { fn test_stake_process_instruction() {
assert_eq!( assert_eq!(
process_instruction(&initialize( process_instruction(&instruction::initialize(
&Pubkey::default(), &Pubkey::default(),
&Authorized::default(), &Authorized::default(),
&Lockup::default() &Lockup::default()
@@ -743,7 +291,7 @@ mod tests {
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
assert_eq!( assert_eq!(
process_instruction(&authorize( process_instruction(&instruction::authorize(
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
@@ -754,7 +302,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&split( &instruction::split(
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
100, 100,
@@ -765,7 +313,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&merge( &instruction::merge(
&Pubkey::default(), &Pubkey::default(),
&invalid_stake_state_pubkey(), &invalid_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
@@ -775,7 +323,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&split_with_seed( &instruction::split_with_seed(
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
100, 100,
@@ -787,7 +335,7 @@ mod tests {
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
assert_eq!( assert_eq!(
process_instruction(&delegate_stake( process_instruction(&instruction::delegate_stake(
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
&invalid_vote_state_pubkey(), &invalid_vote_state_pubkey(),
@@ -795,7 +343,7 @@ mod tests {
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
assert_eq!( assert_eq!(
process_instruction(&withdraw( process_instruction(&instruction::withdraw(
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
&solana_sdk::pubkey::new_rand(), &solana_sdk::pubkey::new_rand(),
@@ -805,11 +353,14 @@ mod tests {
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
assert_eq!( assert_eq!(
process_instruction(&deactivate_stake(&Pubkey::default(), &Pubkey::default())), process_instruction(&instruction::deactivate_stake(
&Pubkey::default(),
&Pubkey::default()
)),
Err(InstructionError::InvalidAccountData), Err(InstructionError::InvalidAccountData),
); );
assert_eq!( assert_eq!(
process_instruction(&set_lockup( process_instruction(&instruction::set_lockup(
&Pubkey::default(), &Pubkey::default(),
&LockupArgs::default(), &LockupArgs::default(),
&Pubkey::default() &Pubkey::default()
@@ -821,7 +372,7 @@ mod tests {
#[test] #[test]
fn test_spoofed_stake_accounts() { fn test_spoofed_stake_accounts() {
assert_eq!( assert_eq!(
process_instruction(&initialize( process_instruction(&instruction::initialize(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Authorized::default(), &Authorized::default(),
&Lockup::default() &Lockup::default()
@@ -829,7 +380,7 @@ mod tests {
Err(InstructionError::InvalidAccountOwner), Err(InstructionError::InvalidAccountOwner),
); );
assert_eq!( assert_eq!(
process_instruction(&authorize( process_instruction(&instruction::authorize(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
@@ -840,7 +391,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&split( &instruction::split(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
100, 100,
@@ -851,7 +402,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&split( &instruction::split(
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
100, 100,
@@ -862,7 +413,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&merge( &instruction::merge(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
@@ -872,7 +423,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&merge( &instruction::merge(
&Pubkey::default(), &Pubkey::default(),
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
@@ -882,7 +433,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
process_instruction( process_instruction(
&split_with_seed( &instruction::split_with_seed(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
100, 100,
@@ -894,7 +445,7 @@ mod tests {
Err(InstructionError::InvalidAccountOwner), Err(InstructionError::InvalidAccountOwner),
); );
assert_eq!( assert_eq!(
process_instruction(&delegate_stake( process_instruction(&instruction::delegate_stake(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
&Pubkey::default(), &Pubkey::default(),
@@ -902,7 +453,7 @@ mod tests {
Err(InstructionError::InvalidAccountOwner), Err(InstructionError::InvalidAccountOwner),
); );
assert_eq!( assert_eq!(
process_instruction(&withdraw( process_instruction(&instruction::withdraw(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default(), &Pubkey::default(),
&solana_sdk::pubkey::new_rand(), &solana_sdk::pubkey::new_rand(),
@@ -912,14 +463,14 @@ mod tests {
Err(InstructionError::InvalidAccountOwner), Err(InstructionError::InvalidAccountOwner),
); );
assert_eq!( assert_eq!(
process_instruction(&deactivate_stake( process_instruction(&instruction::deactivate_stake(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&Pubkey::default() &Pubkey::default()
)), )),
Err(InstructionError::InvalidAccountOwner), Err(InstructionError::InvalidAccountOwner),
); );
assert_eq!( assert_eq!(
process_instruction(&set_lockup( process_instruction(&instruction::set_lockup(
&spoofed_stake_state_pubkey(), &spoofed_stake_state_pubkey(),
&LockupArgs::default(), &LockupArgs::default(),
&Pubkey::default() &Pubkey::default()
@@ -1051,8 +602,9 @@ mod tests {
let stake_history_account = RefCell::new(account::create_account_shared_data_for_test( let stake_history_account = RefCell::new(account::create_account_shared_data_for_test(
&sysvar::stake_history::StakeHistory::default(), &sysvar::stake_history::StakeHistory::default(),
)); ));
let config_address = config::id(); let config_address = stake_config::id();
let config_account = RefCell::new(config::create_account(0, &config::Config::default())); let config_account =
RefCell::new(config::create_account(0, &stake_config::Config::default()));
let keyed_accounts = vec![ let keyed_accounts = vec![
KeyedAccount::new(&stake_address, true, &stake_account), KeyedAccount::new(&stake_address, true, &stake_account),
KeyedAccount::new(&vote_address, false, &bad_vote_account), KeyedAccount::new(&vote_address, false, &bad_vote_account),
@@ -1140,30 +692,4 @@ mod tests {
Err(InstructionError::NotEnoughAccountKeys), Err(InstructionError::NotEnoughAccountKeys),
); );
} }
#[test]
fn test_custom_error_decode() {
use num_traits::FromPrimitive;
fn pretty_err<T>(err: InstructionError) -> String
where
T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
{
if let InstructionError::Custom(code) = err {
let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
format!(
"{:?}: {}::{:?} - {}",
err,
T::type_of(),
specific_error,
specific_error,
)
} else {
"".to_string()
}
}
assert_eq!(
"Custom(0): StakeError::NoCreditsToRedeem - not enough credits to redeem",
pretty_err::<StakeError>(StakeError::NoCreditsToRedeem.into())
)
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,6 @@ solana-perf = { path = "../perf", version = "=1.7.2" }
solana-poh = { path = "../poh", version = "=1.7.2" } solana-poh = { path = "../poh", version = "=1.7.2" }
solana-runtime = { path = "../runtime", version = "=1.7.2" } solana-runtime = { path = "../runtime", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" } solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" } solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
solana-version = { path = "../version", version = "=1.7.2" } solana-version = { path = "../version", version = "=1.7.2" }
@@ -52,6 +51,7 @@ tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to sta
serial_test = "0.4.0" serial_test = "0.4.0"
solana-logger = { path = "../logger", version = "=1.7.2" } solana-logger = { path = "../logger", version = "=1.7.2" }
solana-net-utils = { path = "../net-utils", version = "=1.7.2" } solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
symlink = "0.1.0" symlink = "0.1.0"
[lib] [lib]

View File

@@ -62,12 +62,12 @@ use {
pubkey::Pubkey, pubkey::Pubkey,
sanitize::Sanitize, sanitize::Sanitize,
signature::{Keypair, Signature, Signer}, signature::{Keypair, Signature, Signer},
stake::state::StakeState,
stake_history::StakeHistory, stake_history::StakeHistory,
system_instruction, system_instruction,
sysvar::stake_history, sysvar::stake_history,
transaction::{self, Transaction}, transaction::{self, Transaction},
}, },
solana_stake_program::stake_state::StakeState,
solana_transaction_status::{ solana_transaction_status::{
EncodedConfirmedTransaction, Reward, RewardType, TransactionConfirmationStatus, EncodedConfirmedTransaction, Reward, RewardType, TransactionConfirmationStatus,
TransactionStatus, UiConfirmedBlock, UiTransactionEncoding, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding,

View File

@@ -569,13 +569,14 @@ mod tests {
message::Message, message::Message,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::{
self, instruction as stake_instruction,
state::{Authorized, Lockup, StakeAuthorize},
},
system_instruction, system_program, system_transaction, system_instruction, system_program, system_transaction,
transaction::{self, Transaction}, transaction::{self, Transaction},
}, },
solana_stake_program::{ solana_stake_program::stake_state,
self, stake_instruction,
stake_state::{Authorized, Lockup, StakeAuthorize, StakeState},
},
solana_vote_program::vote_state::Vote, solana_vote_program::vote_state::Vote,
std::{ std::{
sync::{atomic::AtomicBool, RwLock}, sync::{atomic::AtomicBool, RwLock},
@@ -791,7 +792,7 @@ mod tests {
let stake_authority = Keypair::new(); let stake_authority = Keypair::new();
let from = Keypair::new(); let from = Keypair::new();
let stake_account = Keypair::new(); let stake_account = Keypair::new();
let stake_program_id = solana_stake_program::id(); let stake_program_id = stake::program::id();
let bank = Bank::new(&genesis_config); let bank = Bank::new(&genesis_config);
let blockhash = bank.last_blockhash(); let blockhash = bank.last_blockhash();
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); 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 bank = bank_forks.read().unwrap()[1].clone();
let account = bank.get_account(&stake_account.pubkey()).unwrap(); let account = bank.get_account(&stake_account.pubkey()).unwrap();
assert_eq!( assert_eq!(
StakeState::authorized_from(&account).unwrap().staker, stake_state::authorized_from(&account).unwrap().staker,
new_stake_authority new_stake_authority
); );
} }

View File

@@ -1343,7 +1343,7 @@ pub(crate) mod tests {
solana_sdk::{ solana_sdk::{
message::Message, message::Message,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction, system_program, system_transaction, stake, system_instruction, system_program, system_transaction,
transaction::Transaction, transaction::Transaction,
}, },
std::{fmt::Debug, sync::mpsc::channel}, std::{fmt::Debug, sync::mpsc::channel},
@@ -1544,7 +1544,7 @@ pub(crate) mod tests {
blockhash, blockhash,
1, 1,
16, 16,
&solana_stake_program::id(), &stake::program::id(),
); );
bank_forks bank_forks
.write() .write()
@@ -1567,7 +1567,7 @@ pub(crate) mod tests {
optimistically_confirmed_bank, optimistically_confirmed_bank,
); );
subscriptions.add_program_subscription( subscriptions.add_program_subscription(
solana_stake_program::id(), stake::program::id(),
Some(RpcProgramAccountsConfig { Some(RpcProgramAccountsConfig {
account_config: RpcAccountInfoConfig { account_config: RpcAccountInfoConfig {
commitment: Some(CommitmentConfig::processed()), commitment: Some(CommitmentConfig::processed()),
@@ -1584,7 +1584,7 @@ pub(crate) mod tests {
.program_subscriptions .program_subscriptions
.read() .read()
.unwrap() .unwrap()
.contains_key(&solana_stake_program::id())); .contains_key(&stake::program::id()));
subscriptions.notify_subscribers(CommitmentSlots::default()); subscriptions.notify_subscribers(CommitmentSlots::default());
let (response, _) = robust_poll_or_panic(transport_receiver); let (response, _) = robust_poll_or_panic(transport_receiver);
@@ -1616,7 +1616,7 @@ pub(crate) mod tests {
.program_subscriptions .program_subscriptions
.read() .read()
.unwrap() .unwrap()
.contains_key(&solana_stake_program::id())); .contains_key(&stake::program::id()));
} }
#[test] #[test]
@@ -2044,7 +2044,7 @@ pub(crate) mod tests {
blockhash, blockhash,
1, 1,
16, 16,
&solana_stake_program::id(), &stake::program::id(),
); );
// Add the transaction to the 1st bank and then freeze the bank // Add the transaction to the 1st bank and then freeze the bank

View File

@@ -96,6 +96,7 @@ use solana_sdk::{
signature::{Keypair, Signature}, signature::{Keypair, Signature},
slot_hashes::SlotHashes, slot_hashes::SlotHashes,
slot_history::SlotHistory, slot_history::SlotHistory,
stake::{self, state::Delegation},
stake_weighted_timestamp::{ stake_weighted_timestamp::{
calculate_stake_weighted_timestamp, MaxAllowableDrift, MAX_ALLOWABLE_DRIFT_PERCENTAGE, calculate_stake_weighted_timestamp, MaxAllowableDrift, MAX_ALLOWABLE_DRIFT_PERCENTAGE,
MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW, MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW,
@@ -105,9 +106,7 @@ use solana_sdk::{
timing::years_as_slots, timing::years_as_slots,
transaction::{self, Result, Transaction, TransactionError}, transaction::{self, Result, Transaction, TransactionError},
}; };
use solana_stake_program::stake_state::{ use solana_stake_program::stake_state::{self, InflationPointCalculationEvent, PointValue};
self, Delegation, InflationPointCalculationEvent, PointValue,
};
use solana_vote_program::vote_instruction::VoteInstruction; use solana_vote_program::vote_instruction::VoteInstruction;
use std::{ use std::{
borrow::Cow, borrow::Cow,
@@ -1902,7 +1901,7 @@ impl Bank {
if self if self
.feature_set .feature_set
.is_active(&feature_set::filter_stake_delegation_accounts::id()) .is_active(&feature_set::filter_stake_delegation_accounts::id())
&& (stake_account.owner() != &solana_stake_program::id() && (stake_account.owner() != &stake::program::id()
|| vote_account.owner() != &solana_vote_program::id()) || vote_account.owner() != &solana_vote_program::id())
{ {
datapoint_warn!( datapoint_warn!(
@@ -5326,15 +5325,15 @@ pub(crate) mod tests {
process_instruction::InvokeContext, process_instruction::InvokeContext,
rent::Rent, rent::Rent,
signature::{keypair_from_seed, Keypair, Signer}, signature::{keypair_from_seed, Keypair, Signer},
stake::{
instruction as stake_instruction,
state::{Authorized, Delegation, Lockup, Stake},
},
system_instruction::{self, SystemError}, system_instruction::{self, SystemError},
system_program, system_program,
sysvar::{fees::Fees, rewards::Rewards}, sysvar::{fees::Fees, rewards::Rewards},
timing::duration_as_s, timing::duration_as_s,
}; };
use solana_stake_program::{
stake_instruction,
stake_state::{self, Authorized, Delegation, Lockup, Stake},
};
use solana_vote_program::{ use solana_vote_program::{
vote_instruction, vote_instruction,
vote_state::{ vote_state::{
@@ -9521,7 +9520,7 @@ pub(crate) mod tests {
let pubkey = solana_sdk::pubkey::new_rand(); let pubkey = solana_sdk::pubkey::new_rand();
genesis_config.add_account( genesis_config.add_account(
pubkey, pubkey,
solana_stake_program::stake_state::create_lockup_stake_account( stake_state::create_lockup_stake_account(
&Authorized::auto(&pubkey), &Authorized::auto(&pubkey),
&Lockup::default(), &Lockup::default(),
&Rent::default(), &Rent::default(),

View File

@@ -7,7 +7,7 @@ use solana_sdk::{
instruction::InstructionError, instruction::InstructionError,
process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext}, process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext},
pubkey::Pubkey, pubkey::Pubkey,
system_program, stake, system_program,
}; };
fn process_instruction_with_program_logging( fn process_instruction_with_program_logging(
@@ -56,7 +56,7 @@ fn genesis_builtins() -> Vec<Builtin> {
), ),
Builtin::new( Builtin::new(
"stake_program", "stake_program",
solana_stake_program::id(), stake::program::id(),
with_program_logging!(solana_stake_program::stake_instruction::process_instruction), with_program_logging!(solana_stake_program::stake_instruction::process_instruction),
), ),
Builtin::new( Builtin::new(

View File

@@ -8,10 +8,10 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
rent::Rent, rent::Rent,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::state::StakeState,
system_program, system_program,
}; };
use solana_stake_program::stake_state; use solana_stake_program::stake_state;
use solana_stake_program::stake_state::StakeState;
use solana_vote_program::vote_state; use solana_vote_program::vote_state;
use std::borrow::Borrow; use std::borrow::Borrow;

View File

@@ -4,8 +4,12 @@ use {
bank::Bank, bank::Bank,
}, },
log::*, log::*,
solana_sdk::{account::ReadableAccount, pubkey::Pubkey}, solana_sdk::{
solana_stake_program::stake_state::StakeState, account::ReadableAccount,
pubkey::Pubkey,
stake::{self, state::StakeState},
},
solana_stake_program::stake_state,
std::{collections::HashSet, sync::Arc}, std::{collections::HashSet, sync::Arc},
}; };
@@ -32,18 +36,18 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> NonCirculatingSuppl
.contains(&AccountIndex::ProgramId) .contains(&AccountIndex::ProgramId)
{ {
bank.get_filtered_indexed_accounts( bank.get_filtered_indexed_accounts(
&IndexKey::ProgramId(solana_stake_program::id()), &IndexKey::ProgramId(stake::program::id()),
// The program-id account index checks for Account owner on inclusion. However, due to // 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 // the current AccountsDb implementation, an account may remain in storage as a
// zero-lamport Account::Default() after being wiped and reinitialized in later // zero-lamport Account::Default() after being wiped and reinitialized in later
// updates. We include the redundant filter here to avoid returning these accounts. // updates. We include the redundant filter here to avoid returning these accounts.
|account| account.owner() == &solana_stake_program::id(), |account| account.owner() == &stake::program::id(),
) )
} else { } else {
bank.get_program_accounts(&solana_stake_program::id()) bank.get_program_accounts(&stake::program::id())
}; };
for (pubkey, account) in stake_accounts.iter() { for (pubkey, account) in stake_accounts.iter() {
let stake_account = StakeState::from(account).unwrap_or_default(); let stake_account = stake_state::from(account).unwrap_or_default();
match stake_account { match stake_account {
StakeState::Initialized(meta) => { StakeState::Initialized(meta) => {
if meta.lockup.is_in_force(&clock, None) if meta.lockup.is_in_force(&clock, None)
@@ -195,8 +199,8 @@ mod tests {
account::AccountSharedData, account::AccountSharedData,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
genesis_config::{ClusterType, GenesisConfig}, 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}; use std::{collections::BTreeMap, sync::Arc};
fn new_from_parent(parent: &Arc<Bank>) -> Bank { fn new_from_parent(parent: &Arc<Bank>) -> Bank {
@@ -235,7 +239,7 @@ mod tests {
balance, balance,
&StakeState::Initialized(meta), &StakeState::Initialized(meta),
std::mem::size_of::<StakeState>(), std::mem::size_of::<StakeState>(),
&solana_stake_program::id(), &stake::program::id(),
) )
.unwrap(); .unwrap();
accounts.insert(pubkey, stake_account); accounts.insert(pubkey, stake_account);

View File

@@ -290,7 +290,7 @@ mod test_bank_serialize {
// This some what long test harness is required to freeze the ABI of // This some what long test harness is required to freeze the ABI of
// Bank's serialization due to versioned nature // Bank's serialization due to versioned nature
#[frozen_abi(digest = "DuRGntVwLGNAv5KooafUSpxk67BPAx2yC7Z8A9c8wr2G")] #[frozen_abi(digest = "6msodEzE7YzFtorBhiP6ax4PKBaPZTkmYdGAdpoxLCvV")]
#[derive(Serialize, AbiExample)] #[derive(Serialize, AbiExample)]
pub struct BankAbiTestWrapperFuture { pub struct BankAbiTestWrapperFuture {
#[serde(serialize_with = "wrapper_future")] #[serde(serialize_with = "wrapper_future")]

View File

@@ -5,9 +5,13 @@ use solana_sdk::{
account::{AccountSharedData, ReadableAccount}, account::{AccountSharedData, ReadableAccount},
clock::Epoch, clock::Epoch,
pubkey::Pubkey, pubkey::Pubkey,
stake::{
self,
state::{Delegation, StakeState},
},
sysvar::stake_history::StakeHistory, sysvar::stake_history::StakeHistory,
}; };
use solana_stake_program::stake_state::{new_stake_history_entry, Delegation, StakeState}; use solana_stake_program::stake_state;
use solana_vote_program::vote_state::VoteState; use solana_vote_program::vote_state::VoteState;
use std::{borrow::Borrow, collections::HashMap}; use std::{borrow::Borrow, collections::HashMap};
@@ -42,7 +46,7 @@ impl Stakes {
let mut stake_history_upto_prev_epoch = self.stake_history.clone(); let mut stake_history_upto_prev_epoch = self.stake_history.clone();
stake_history_upto_prev_epoch.add( stake_history_upto_prev_epoch.add(
prev_epoch, prev_epoch,
new_stake_history_entry( stake_state::new_stake_history_entry(
prev_epoch, prev_epoch,
self.stake_delegations self.stake_delegations
.iter() .iter()
@@ -111,7 +115,7 @@ impl Stakes {
pub fn is_stake(account: &AccountSharedData) -> bool { pub fn is_stake(account: &AccountSharedData) -> bool {
solana_vote_program::check_id(account.owner()) solana_vote_program::check_id(account.owner())
|| solana_stake_program::check_id(account.owner()) || stake::program::check_id(account.owner())
&& account.data().len() >= std::mem::size_of::<StakeState>() && account.data().len() >= std::mem::size_of::<StakeState>()
} }
@@ -148,7 +152,7 @@ impl Stakes {
.insert(*pubkey, (stake, ArcVoteAccount::from(account.clone()))); .insert(*pubkey, (stake, ArcVoteAccount::from(account.clone())));
} }
old.map(|(_, account)| account) old.map(|(_, account)| account)
} else if solana_stake_program::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 // old_stake is stake lamports and voter_pubkey from the pre-store() version
let old_stake = self.stake_delegations.get(pubkey).map(|delegation| { let old_stake = self.stake_delegations.get(pubkey).map(|delegation| {
( (
@@ -157,7 +161,7 @@ impl Stakes {
) )
}); });
let delegation = StakeState::delegation_from(account); let delegation = stake_state::delegation_from(account);
let stake = delegation.map(|delegation| { let stake = delegation.map(|delegation| {
( (
@@ -308,7 +312,7 @@ pub mod tests {
stakes.store(&vote_pubkey, &vote_account, true, true); stakes.store(&vote_pubkey, &vote_account, true, true);
stakes.store(&stake_pubkey, &stake_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true);
let stake = StakeState::stake_from(&stake_account).unwrap(); let stake = stake_state::stake_from(&stake_account).unwrap();
{ {
let vote_accounts = stakes.vote_accounts(); let vote_accounts = stakes.vote_accounts();
assert!(vote_accounts.get(&vote_pubkey).is_some()); assert!(vote_accounts.get(&vote_pubkey).is_some());
@@ -332,7 +336,7 @@ pub mod tests {
// activate more // activate more
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey); let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
stakes.store(&stake_pubkey, &stake_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true);
let stake = StakeState::stake_from(&stake_account).unwrap(); let stake = stake_state::stake_from(&stake_account).unwrap();
{ {
let vote_accounts = stakes.vote_accounts(); let vote_accounts = stakes.vote_accounts();
assert!(vote_accounts.get(&vote_pubkey).is_some()); assert!(vote_accounts.get(&vote_pubkey).is_some());
@@ -463,7 +467,7 @@ pub mod tests {
// delegates to vote_pubkey // delegates to vote_pubkey
stakes.store(&stake_pubkey, &stake_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true);
let stake = StakeState::stake_from(&stake_account).unwrap(); let stake = stake_state::stake_from(&stake_account).unwrap();
{ {
let vote_accounts = stakes.vote_accounts(); let vote_accounts = stakes.vote_accounts();
@@ -523,7 +527,7 @@ pub mod tests {
stakes.store(&vote_pubkey, &vote_account, true, true); stakes.store(&vote_pubkey, &vote_account, true, true);
stakes.store(&stake_pubkey, &stake_account, true, true); stakes.store(&stake_pubkey, &stake_account, true, true);
let stake = StakeState::stake_from(&stake_account).unwrap(); let stake = stake_state::stake_from(&stake_account).unwrap();
{ {
let vote_accounts = stakes.vote_accounts(); let vote_accounts = stakes.vote_accounts();
@@ -564,7 +568,7 @@ pub mod tests {
// not a stake account, and whacks above entry // not a stake account, and whacks above entry
stakes.store( stakes.store(
&stake_pubkey, &stake_pubkey,
&AccountSharedData::new(1, 0, &solana_stake_program::id()), &AccountSharedData::new(1, 0, &stake::program::id()),
true, true,
true, true,
); );

View File

@@ -11,12 +11,13 @@ use solana_sdk::{
message::Message, message::Message,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::{
self, instruction as stake_instruction,
state::{Authorized, Lockup, StakeState},
},
sysvar::{self, stake_history::StakeHistory}, sysvar::{self, stake_history::StakeHistory},
}; };
use solana_stake_program::{ use solana_stake_program::stake_state;
stake_instruction::{self},
stake_state::{self, StakeState},
};
use solana_vote_program::{ use solana_vote_program::{
vote_instruction, vote_instruction,
vote_state::{Vote, VoteInit, VoteState, VoteStateVersions}, vote_state::{Vote, VoteInit, VoteState, VoteStateVersions},
@@ -69,7 +70,7 @@ fn fill_epoch_with_votes(
} }
fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool { fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool {
let stake = StakeState::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.delegation.stake
== stake.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 { fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 {
StakeState::stake_from(&bank.get_account(stake_pubkey).unwrap()) stake_state::stake_from(&bank.get_account(stake_pubkey).unwrap())
.unwrap() .unwrap()
.stake( .stake(
bank.epoch(), bank.epoch(),
@@ -118,9 +119,9 @@ fn test_stake_create_and_split_single_signature() {
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
let stake_address = let stake_address =
Pubkey::create_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap(); Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap();
let authorized = stake_state::Authorized::auto(&staker_pubkey); let authorized = Authorized::auto(&staker_pubkey);
let lamports = 1_000_000; let lamports = 1_000_000;
@@ -132,7 +133,7 @@ fn test_stake_create_and_split_single_signature() {
&staker_pubkey, // base &staker_pubkey, // base
"stake", // seed "stake", // seed
&authorized, &authorized,
&stake_state::Lockup::default(), &Lockup::default(),
lamports, lamports,
), ),
Some(&staker_pubkey), Some(&staker_pubkey),
@@ -145,8 +146,7 @@ fn test_stake_create_and_split_single_signature() {
// split the stake // split the stake
let split_stake_address = let split_stake_address =
Pubkey::create_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id()) Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::program::id()).unwrap();
.unwrap();
// Test split // Test split
let message = Message::new( let message = Message::new(
&stake_instruction::split_with_seed( &stake_instruction::split_with_seed(
@@ -189,9 +189,9 @@ fn test_stake_create_and_split_to_existing_system_account() {
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config))); let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
let stake_address = let stake_address =
Pubkey::create_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap(); Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap();
let authorized = stake_state::Authorized::auto(&staker_pubkey); let authorized = Authorized::auto(&staker_pubkey);
let lamports = 1_000_000; let lamports = 1_000_000;
@@ -203,7 +203,7 @@ fn test_stake_create_and_split_to_existing_system_account() {
&staker_pubkey, // base &staker_pubkey, // base
"stake", // seed "stake", // seed
&authorized, &authorized,
&stake_state::Lockup::default(), &Lockup::default(),
lamports, lamports,
), ),
Some(&staker_pubkey), Some(&staker_pubkey),
@@ -214,8 +214,7 @@ fn test_stake_create_and_split_to_existing_system_account() {
.expect("failed to create and delegate stake account"); .expect("failed to create and delegate stake account");
let split_stake_address = let split_stake_address =
Pubkey::create_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id()) Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::program::id()).unwrap();
.unwrap();
// First, put a system account where we want the new stake account // First, put a system account where we want the new stake account
let existing_lamports = 42; let existing_lamports = 42;
@@ -290,7 +289,7 @@ fn test_stake_account_lifetime() {
.send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message) .send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message)
.expect("failed to create vote account"); .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 // Create stake account and delegate to vote account
let message = Message::new( let message = Message::new(
&stake_instruction::create_account_and_delegate_stake( &stake_instruction::create_account_and_delegate_stake(
@@ -298,7 +297,7 @@ fn test_stake_account_lifetime() {
&stake_pubkey, &stake_pubkey,
&vote_pubkey, &vote_pubkey,
&authorized, &authorized,
&stake_state::Lockup::default(), &Lockup::default(),
1_000_000, 1_000_000,
), ),
Some(&mint_pubkey), Some(&mint_pubkey),
@@ -516,8 +515,7 @@ fn test_create_stake_account_from_seed() {
let bank_client = BankClient::new_shared(&bank); let bank_client = BankClient::new_shared(&bank);
let seed = "test-string"; let seed = "test-string";
let stake_pubkey = let stake_pubkey = Pubkey::create_with_seed(&mint_pubkey, seed, &stake::program::id()).unwrap();
Pubkey::create_with_seed(&mint_pubkey, seed, &solana_stake_program::id()).unwrap();
// Create Vote Account // Create Vote Account
let message = Message::new( let message = Message::new(
@@ -538,7 +536,7 @@ fn test_create_stake_account_from_seed() {
.send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message) .send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message)
.expect("failed to create vote account"); .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 // Create stake account and delegate to vote account
let message = Message::new( let message = Message::new(
&stake_instruction::create_account_with_seed_and_delegate_stake( &stake_instruction::create_account_with_seed_and_delegate_stake(
@@ -548,7 +546,7 @@ fn test_create_stake_account_from_seed() {
seed, seed,
&vote_pubkey, &vote_pubkey,
&authorized, &authorized,
&stake_state::Lockup::default(), &Lockup::default(),
1_000_000, 1_000_000,
), ),
Some(&mint_pubkey), Some(&mint_pubkey),

View File

@@ -42,6 +42,7 @@ pub mod serialize_utils;
pub mod short_vec; pub mod short_vec;
pub mod slot_hashes; pub mod slot_hashes;
pub mod slot_history; pub mod slot_history;
pub mod stake;
pub mod stake_history; pub mod stake_history;
pub mod system_instruction; pub mod system_instruction;
pub mod system_program; pub mod system_program;

View File

@@ -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,
}
}
}

View File

@@ -0,0 +1,508 @@
use {
crate::stake::{
config,
program::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<E> DecodeError<E> 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<UnixTimestamp>,
pub epoch: Option<Epoch>,
pub custodian: Option<Pubkey>,
}
#[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<Instruction> {
vec![
system_instruction::create_account_with_seed(
from_pubkey,
stake_pubkey,
base,
seed,
lamports,
std::mem::size_of::<StakeState>() as u64,
&id(),
),
initialize(stake_pubkey, authorized, lockup),
]
}
pub fn create_account(
from_pubkey: &Pubkey,
stake_pubkey: &Pubkey,
authorized: &Authorized,
lockup: &Lockup,
lamports: u64,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
from_pubkey,
stake_pubkey,
lamports,
std::mem::size_of::<StakeState>() 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<Instruction> {
vec![
system_instruction::allocate(split_stake_pubkey, std::mem::size_of::<StakeState>() as u64),
system_instruction::assign(split_stake_pubkey, &id()),
_split(
stake_pubkey,
authorized_pubkey,
lamports,
split_stake_pubkey,
),
]
}
pub fn split_with_seed(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
lamports: u64,
split_stake_pubkey: &Pubkey, // derived using create_with_seed()
base: &Pubkey, // base
seed: &str, // seed
) -> Vec<Instruction> {
vec![
system_instruction::allocate_with_seed(
split_stake_pubkey,
base,
seed,
std::mem::size_of::<StakeState>() as u64,
&id(),
),
_split(
stake_pubkey,
authorized_pubkey,
lamports,
split_stake_pubkey,
),
]
}
pub fn merge(
destination_stake_pubkey: &Pubkey,
source_stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
) -> Vec<Instruction> {
let account_metas = vec![
AccountMeta::new(*destination_stake_pubkey, false),
AccountMeta::new(*source_stake_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true),
];
vec![Instruction::new_with_bincode(
id(),
&StakeInstruction::Merge,
account_metas,
)]
}
pub fn create_account_and_delegate_stake(
from_pubkey: &Pubkey,
stake_pubkey: &Pubkey,
vote_pubkey: &Pubkey,
authorized: &Authorized,
lockup: &Lockup,
lamports: u64,
) -> Vec<Instruction> {
let mut instructions = create_account(from_pubkey, stake_pubkey, authorized, lockup, lamports);
instructions.push(delegate_stake(
stake_pubkey,
&authorized.staker,
vote_pubkey,
));
instructions
}
pub fn create_account_with_seed_and_delegate_stake(
from_pubkey: &Pubkey,
stake_pubkey: &Pubkey,
base: &Pubkey,
seed: &str,
vote_pubkey: &Pubkey,
authorized: &Authorized,
lockup: &Lockup,
lamports: u64,
) -> Vec<Instruction> {
let mut instructions = create_account_with_seed(
from_pubkey,
stake_pubkey,
base,
seed,
authorized,
lockup,
lamports,
);
instructions.push(delegate_stake(
stake_pubkey,
&authorized.staker,
vote_pubkey,
));
instructions
}
pub fn authorize(
stake_pubkey: &Pubkey,
authorized_pubkey: &Pubkey,
new_authorized_pubkey: &Pubkey,
stake_authorize: StakeAuthorize,
custodian_pubkey: Option<&Pubkey>,
) -> Instruction {
let mut account_metas = vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(*authorized_pubkey, true),
];
if let Some(custodian_pubkey) = custodian_pubkey {
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
}
Instruction::new_with_bincode(
id(),
&StakeInstruction::Authorize(*new_authorized_pubkey, stake_authorize),
account_metas,
)
}
pub fn authorize_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<T>(err: InstructionError) -> String
where
T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
{
if let InstructionError::Custom(code) = err {
let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
format!(
"{:?}: {}::{:?} - {}",
err,
T::type_of(),
specific_error,
specific_error,
)
} else {
"".to_string()
}
}
assert_eq!(
"Custom(0): StakeError::NoCreditsToRedeem - not enough credits to redeem",
pretty_err::<StakeError>(StakeError::NoCreditsToRedeem.into())
)
}
}

View File

@@ -0,0 +1,7 @@
pub mod config;
pub mod instruction;
pub mod state;
pub mod program {
crate::declare_id!("Stake11111111111111111111111111111111111111");
}

View File

@@ -0,0 +1,533 @@
#![allow(clippy::integer_arithmetic)]
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::<StakeState>())
}
pub fn stake(&self) -> Option<Stake> {
match self {
StakeState::Stake(_meta, stake) => Some(*stake),
_ => None,
}
}
pub fn delegation(&self) -> Option<Delegation> {
match self {
StakeState::Stake(_meta, stake) => Some(stake.delegation),
_ => None,
}
}
pub fn authorized(&self) -> Option<Authorized> {
match self {
StakeState::Stake(meta, _stake) => Some(meta.authorized),
StakeState::Initialized(meta) => Some(meta.authorized),
_ => None,
}
}
pub fn lockup(&self) -> Option<Lockup> {
self.meta().map(|meta| meta.lockup)
}
pub fn meta(&self) -> Option<Meta> {
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<Pubkey>,
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<Pubkey>,
new_authorized: &Pubkey,
stake_authorize: StakeAuthorize,
lockup_custodian_args: Option<(&Lockup, &Clock, Option<&Pubkey>)>,
) -> Result<(), InstructionError> {
match stake_authorize {
StakeAuthorize::Staker => {
// Allow either the staker or the withdrawer to change the staker key
if !signers.contains(&self.staker) && !signers.contains(&self.withdrawer) {
return Err(InstructionError::MissingRequiredSignature);
}
self.staker = *new_authorized
}
StakeAuthorize::Withdrawer => {
if let Some((lockup, clock, custodian)) = lockup_custodian_args {
if lockup.is_in_force(&clock, None) {
match custodian {
None => {
return Err(StakeError::CustodianMissing.into());
}
Some(custodian) => {
if !signers.contains(custodian) {
return Err(StakeError::CustodianSignatureMissing.into());
}
if lockup.is_in_force(&clock, Some(custodian)) {
return Err(StakeError::LockupInForce.into());
}
}
}
}
}
self.check(signers, stake_authorize)?;
self.withdrawer = *new_authorized
}
}
Ok(())
}
}
#[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<Pubkey>,
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(&current_epoch) {
prev_epoch = current_epoch;
prev_cluster_stake = current_cluster_stake;
} else {
break;
}
}
// deactivating stake should equal to all of currently remaining effective stake
(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(&current_epoch) {
prev_epoch = current_epoch;
prev_cluster_stake = current_cluster_stake;
} else {
break;
}
}
(
current_effective_stake,
delegated_stake - current_effective_stake,
)
} else {
// no history or I've dropped out of history, so assume fully effective
(delegated_stake, 0)
}
}
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<Self, StakeError> {
if remaining_stake_delta > self.delegation.stake {
return Err(StakeError::InsufficientStake);
}
self.delegation.stake -= remaining_stake_delta;
let new = Self {
delegation: Delegation {
stake: split_stake_amount,
..self.delegation
},
..*self
};
Ok(new)
}
pub fn deactivate(&mut self, epoch: Epoch) -> Result<(), StakeError> {
if self.delegation.deactivation_epoch != std::u64::MAX {
Err(StakeError::AlreadyDeactivated)
} else {
self.delegation.deactivation_epoch = epoch;
Ok(())
}
}
}

View File

@@ -16,12 +16,10 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
signature::{unique_signers, Signature, Signer}, signature::{unique_signers, Signature, Signer},
signers::Signers, signers::Signers,
stake::{instruction::LockupArgs, state::Lockup},
transaction::Transaction, transaction::Transaction,
}; };
use solana_stake_program::{ use solana_stake_program::stake_state;
stake_instruction::LockupArgs,
stake_state::{Lockup, StakeState},
};
use std::env; use std::env;
use std::error::Error; use std::error::Error;
@@ -52,7 +50,7 @@ fn get_balances(
fn get_lockup(client: &RpcClient, address: &Pubkey) -> Result<Lockup, ClientError> { fn get_lockup(client: &RpcClient, address: &Pubkey) -> Result<Lockup, ClientError> {
client client
.get_account(address) .get_account(address)
.map(|account| StakeState::lockup_from(&account).unwrap()) .map(|account| stake_state::lockup_from(&account).unwrap())
} }
fn get_lockups( fn get_lockups(

View File

@@ -1,16 +1,20 @@
use solana_sdk::{ use solana_sdk::{
clock::SECONDS_PER_DAY, instruction::Instruction, message::Message, pubkey::Pubkey, clock::SECONDS_PER_DAY,
}; instruction::Instruction,
use solana_stake_program::{ message::Message,
stake_instruction::{self, LockupArgs}, pubkey::Pubkey,
stake_state::{Authorized, Lockup, StakeAuthorize}, stake::{
self,
instruction::{self as stake_instruction, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
}; };
const DAYS_PER_YEAR: f64 = 365.25; const DAYS_PER_YEAR: f64 = 365.25;
const SECONDS_PER_YEAR: i64 = (SECONDS_PER_DAY as f64 * DAYS_PER_YEAR) as i64; 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 { 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::program::id()).unwrap()
} }
// Return derived addresses // Return derived addresses
@@ -284,8 +288,9 @@ mod tests {
client::SyncClient, client::SyncClient,
genesis_config::create_genesis_config, genesis_config::create_genesis_config,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::state::StakeState,
}; };
use solana_stake_program::stake_state::StakeState; use solana_stake_program::stake_state;
fn create_bank(lamports: u64) -> (Bank, Keypair, u64) { fn create_bank(lamports: u64) -> (Bank, Keypair, u64) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports); 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 address = derive_stake_account_address(&base_pubkey, i);
let account = let account =
AccountSharedData::from(client.get_account(&address).unwrap().unwrap()); AccountSharedData::from(client.get_account(&address).unwrap().unwrap());
(address, StakeState::lockup_from(&account).unwrap()) (address, stake_state::lockup_from(&account).unwrap())
}) })
.collect() .collect()
} }
@@ -375,7 +380,7 @@ mod tests {
let account = get_account_at(&bank_client, &base_pubkey, 0); let account = get_account_at(&bank_client, &base_pubkey, 0);
assert_eq!(account.lamports(), lamports); assert_eq!(account.lamports(), lamports);
let authorized = StakeState::authorized_from(&account).unwrap(); let authorized = stake_state::authorized_from(&account).unwrap();
assert_eq!(authorized.staker, stake_authority_pubkey); assert_eq!(authorized.staker, stake_authority_pubkey);
assert_eq!(authorized.withdrawer, withdraw_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 account = get_account_at(&bank_client, &base_pubkey, 0);
let authorized = StakeState::authorized_from(&account).unwrap(); let authorized = stake_state::authorized_from(&account).unwrap();
assert_eq!(authorized.staker, new_stake_authority_pubkey); assert_eq!(authorized.staker, new_stake_authority_pubkey);
assert_eq!(authorized.withdrawer, new_withdraw_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 account = get_account_at(&bank_client, &base_pubkey, 0);
let lockup = StakeState::lockup_from(&account).unwrap(); let lockup = stake_state::lockup_from(&account).unwrap();
assert_eq!(lockup.unix_timestamp, 1); assert_eq!(lockup.unix_timestamp, 1);
assert_eq!(lockup.epoch, 0); assert_eq!(lockup.epoch, 0);
@@ -586,7 +591,7 @@ mod tests {
// Ensure the new accounts are duplicates of the previous ones. // Ensure the new accounts are duplicates of the previous ones.
let account = get_account_at(&bank_client, &new_base_pubkey, 0); let account = get_account_at(&bank_client, &new_base_pubkey, 0);
let authorized = StakeState::authorized_from(&account).unwrap(); let authorized = stake_state::authorized_from(&account).unwrap();
assert_eq!(authorized.staker, stake_authority_pubkey); assert_eq!(authorized.staker, stake_authority_pubkey);
assert_eq!(authorized.withdrawer, withdraw_authority_pubkey); assert_eq!(authorized.withdrawer, withdraw_authority_pubkey);
} }
@@ -655,7 +660,7 @@ mod tests {
// Ensure the new accounts have the new authorities. // Ensure the new accounts have the new authorities.
let account = get_account_at(&bank_client, &new_base_pubkey, 0); let account = get_account_at(&bank_client, &new_base_pubkey, 0);
let authorized = StakeState::authorized_from(&account).unwrap(); let authorized = stake_state::authorized_from(&account).unwrap();
assert_eq!(authorized.staker, new_stake_authority_pubkey); assert_eq!(authorized.staker, new_stake_authority_pubkey);
assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey); assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey);
} }

View File

@@ -22,7 +22,6 @@ solana-logger = { path = "../logger", version = "=1.7.2" }
solana-metrics = { path = "../metrics", version = "=1.7.2" } solana-metrics = { path = "../metrics", version = "=1.7.2" }
solana-rpc = { path = "../rpc", version = "=1.7.2" } solana-rpc = { path = "../rpc", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" } solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
solana-version = { path = "../version", version = "=1.7.2" } solana-version = { path = "../version", version = "=1.7.2" }

View File

@@ -4,10 +4,14 @@ use serde::{Deserialize, Serialize};
use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient}; use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient};
use solana_metrics::{datapoint_error, datapoint_info}; use solana_metrics::{datapoint_error, datapoint_info};
use solana_sdk::{ use solana_sdk::{
clock::Slot, native_token::LAMPORTS_PER_SOL, program_utils::limited_deserialize, clock::Slot,
pubkey::Pubkey, signature::Signature, transaction::Transaction, 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::{ use solana_transaction_status::{
EncodedConfirmedBlock, UiTransactionEncoding, UiTransactionStatusMeta, EncodedConfirmedBlock, UiTransactionEncoding, UiTransactionStatusMeta,
}; };
@@ -78,7 +82,7 @@ fn process_transaction(
// Look for stake operations // Look for stake operations
for instruction in message.instructions.iter().rev() { for instruction in message.instructions.iter().rev() {
let program_pubkey = message.account_keys[instruction.program_id_index as usize]; let program_pubkey = message.account_keys[instruction.program_id_index as usize];
if program_pubkey != solana_stake_program::id() { if program_pubkey != stake::program::id() {
continue; continue;
} }
@@ -368,10 +372,10 @@ mod test {
message::Message, message::Message,
native_token::sol_to_lamports, native_token::sol_to_lamports,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
stake::{instruction as stake_instruction, state::Authorized},
system_transaction, system_transaction,
transaction::Transaction, transaction::Transaction,
}; };
use solana_stake_program::{stake_instruction, stake_state::Authorized};
#[test] #[test]
#[serial] #[serial]

View File

@@ -27,7 +27,6 @@ solana-client = { path = "../client", version = "=1.7.2" }
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" } solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
solana-runtime = { path = "../runtime", version = "=1.7.2" } solana-runtime = { path = "../runtime", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" } solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
solana-version = { path = "../version", version = "=1.7.2" } solana-version = { path = "../version", version = "=1.7.2" }
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2" } spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2" }

View File

@@ -27,13 +27,13 @@ use solana_sdk::{
message::Message, message::Message,
native_token::{lamports_to_sol, sol_to_lamports}, native_token::{lamports_to_sol, sol_to_lamports},
signature::{unique_signers, Signature, Signer}, signature::{unique_signers, Signature, Signer},
stake::{
instruction::{self as stake_instruction, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
system_instruction, system_instruction,
transaction::Transaction, transaction::Transaction,
}; };
use solana_stake_program::{
stake_instruction::{self, LockupArgs},
stake_state::{Authorized, Lockup, StakeAuthorize},
};
use solana_transaction_status::TransactionStatus; use solana_transaction_status::TransactionStatus;
use spl_associated_token_account_v1_0::get_associated_token_address; use spl_associated_token_account_v1_0::get_associated_token_address;
use spl_token_v2_0::solana_program::program_error::ProgramError; 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 { mod tests {
use super::*; use super::*;
use solana_core::test_validator::TestValidator; use solana_core::test_validator::TestValidator;
use solana_sdk::signature::{read_keypair_file, write_keypair_file, Signer}; use solana_sdk::{
use solana_stake_program::stake_instruction::StakeInstruction; signature::{read_keypair_file, write_keypair_file, Signer},
stake::instruction::StakeInstruction,
};
use solana_transaction_status::TransactionConfirmationStatus; use solana_transaction_status::TransactionConfirmationStatus;
#[test] #[test]

View File

@@ -21,7 +21,6 @@ serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" } solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
solana-sdk = { path = "../sdk", version = "=1.7.2" } solana-sdk = { path = "../sdk", version = "=1.7.2" }
solana-runtime = { path = "../runtime", version = "=1.7.2" } solana-runtime = { path = "../runtime", version = "=1.7.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" } solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2", features = ["no-entrypoint"] } 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"] } spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }

View File

@@ -9,7 +9,7 @@ use crate::{
use inflector::Inflector; use inflector::Inflector;
use serde_json::Value; use serde_json::Value;
use solana_account_decoder::parse_token::spl_token_id_v2_0; 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 std::{collections::HashMap, str::from_utf8};
use thiserror::Error; 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 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_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 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::program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id(); static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0(); static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id(); static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();

View File

@@ -3,8 +3,9 @@ use crate::parse_instruction::{
}; };
use bincode::deserialize; use bincode::deserialize;
use serde_json::{json, Map}; use serde_json::{json, Map};
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey}; use solana_sdk::{
use solana_stake_program::stake_instruction::StakeInstruction; instruction::CompiledInstruction, pubkey::Pubkey, stake::instruction::StakeInstruction,
};
pub fn parse_stake( pub fn parse_stake(
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
@@ -195,10 +196,13 @@ fn check_num_stake_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInst
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use solana_sdk::{message::Message, pubkey::Pubkey}; use solana_sdk::{
use solana_stake_program::{ message::Message,
stake_instruction::{self, LockupArgs}, pubkey::Pubkey,
stake_state::{Authorized, Lockup, StakeAuthorize}, stake::{
instruction::{self, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
}; };
#[test] #[test]
@@ -221,7 +225,7 @@ mod test {
let lamports = 55; let lamports = 55;
let instructions = 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); let message = Message::new(&instructions, None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[1], &keys[0..3]).unwrap(), 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()); assert!(parse_stake(&message.instructions[1], &keys[0..2]).is_err());
let instruction = stake_instruction::authorize( let instruction =
&keys[1], instruction::authorize(&keys[1], &keys[0], &keys[3], StakeAuthorize::Staker, None);
&keys[0],
&keys[3],
StakeAuthorize::Staker,
None,
);
let message = Message::new(&[instruction], None); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(), 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()); assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
let instruction = stake_instruction::authorize( let instruction = instruction::authorize(
&keys[1], &keys[1],
&keys[0], &keys[0],
&keys[3], &keys[3],
@@ -291,7 +290,7 @@ mod test {
); );
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err()); 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(), parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
@@ -313,7 +312,7 @@ mod test {
// * split account (signer, allocate + assign first) // * split account (signer, allocate + assign first)
// * stake authority (signer) // * stake authority (signer)
// * stake account // * 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); let message = Message::new(&instructions, None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[2], &keys[0..3]).unwrap(), 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()); 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(), parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
@@ -346,7 +345,7 @@ mod test {
} }
); );
let instruction = 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(), 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()); 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(), 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()); 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); let message = Message::new(&instructions, None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(), 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()); assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
let seed = "test_seed"; let seed = "test_seed";
let instruction = stake_instruction::authorize_with_seed( let instruction = instruction::authorize_with_seed(
&keys[1], &keys[1],
&keys[0], &keys[0],
seed.to_string(), seed.to_string(),
@@ -425,7 +424,7 @@ mod test {
); );
assert!(parse_stake(&message.instructions[0], &keys[0..1]).is_err()); 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[1],
&keys[0], &keys[0],
seed.to_string(), seed.to_string(),
@@ -470,7 +469,7 @@ mod test {
epoch: None, epoch: None,
custodian: 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(), parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
@@ -491,7 +490,7 @@ mod test {
epoch: Some(epoch), epoch: Some(epoch),
custodian: 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(), parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
@@ -513,7 +512,7 @@ mod test {
epoch: Some(epoch), epoch: Some(epoch),
custodian: Some(custodian), 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); let message = Message::new(&[instruction], None);
assert_eq!( assert_eq!(
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(), parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),