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
This commit is contained in:
Jon Cinque 2021-06-15 18:04:00 +02:00 committed by GitHub
parent 36b09db2d1
commit 1b1d34da59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1765 additions and 1711 deletions

9
Cargo.lock generated
View File

@ -4125,7 +4125,6 @@ dependencies = [
"serde_json",
"solana-config-program",
"solana-sdk",
"solana-stake-program",
"solana-vote-program",
"spl-token",
"thiserror",
@ -4405,7 +4404,6 @@ dependencies = [
"solana-net-utils",
"solana-remote-wallet",
"solana-sdk",
"solana-stake-program",
"solana-transaction-status",
"solana-version",
"solana-vote-program",
@ -4446,7 +4444,6 @@ dependencies = [
"solana-clap-utils",
"solana-client",
"solana-sdk",
"solana-stake-program",
"solana-transaction-status",
"solana-vote-program",
"spl-memo",
@ -4907,7 +4904,6 @@ dependencies = [
"solana-rayon-threadlimit",
"solana-runtime",
"solana-sdk",
"solana-stake-program",
"solana-storage-bigtable",
"solana-storage-proto",
"solana-transaction-status",
@ -5144,7 +5140,6 @@ dependencies = [
"solana-metrics",
"solana-rayon-threadlimit",
"solana-sdk",
"solana-stake-program",
]
[[package]]
@ -5274,7 +5269,6 @@ dependencies = [
"solana-logger 1.8.0",
"solana-runtime",
"solana-sdk",
"solana-stake-program",
"solana-vote-program",
"thiserror",
"tokio 1.6.1",
@ -5532,7 +5526,6 @@ dependencies = [
"solana-metrics",
"solana-rpc",
"solana-sdk",
"solana-stake-program",
"solana-transaction-status",
"solana-version",
"tempfile",
@ -5669,7 +5662,6 @@ dependencies = [
"solana-remote-wallet",
"solana-runtime",
"solana-sdk",
"solana-stake-program",
"solana-transaction-status",
"solana-version",
"spl-associated-token-account",
@ -5693,7 +5685,6 @@ dependencies = [
"solana-account-decoder",
"solana-runtime",
"solana-sdk",
"solana-stake-program",
"solana-vote-program",
"spl-associated-token-account",
"spl-memo",

View File

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

View File

@ -9,14 +9,14 @@ use crate::{
};
use inflector::Inflector;
use serde_json::Value;
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar};
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar};
use std::collections::HashMap;
use thiserror::Error;
lazy_static! {
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();

View File

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

View File

@ -4,7 +4,7 @@ use crate::{
};
use bincode::deserialize;
use solana_sdk::clock::{Epoch, UnixTimestamp};
use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
let stake_state: StakeState = deserialize(data)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -41,7 +41,7 @@ Create and manage accounts representing stake and rewards for delegations to
validators.
- Program id: `Stake11111111111111111111111111111111111111`
- Instructions: [StakeInstruction](https://docs.rs/solana-stake-program/VERSION_FOR_DOCS_RS/solana_stake_program/stake_instruction/enum.StakeInstruction.html)
- Instructions: [StakeInstruction](https://docs.rs/solana-sdk/VERSION_FOR_DOCS_RS/solana_sdk/stake/instruction/enum.StakeInstruction.html)
## Vote Program

View File

@ -26,9 +26,10 @@ use solana_sdk::{
pubkey::Pubkey,
rent::Rent,
signature::{Keypair, Signer},
stake::state::StakeState,
system_program, timing,
};
use solana_stake_program::stake_state::{self, StakeState};
use solana_stake_program::stake_state;
use solana_vote_program::vote_state::{self, VoteState};
use std::{
collections::HashMap,

View File

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

View File

@ -44,9 +44,10 @@ use solana_sdk::{
pubkey::Pubkey,
rent::Rent,
shred_version::compute_shred_version,
stake::{self, state::StakeState},
system_program,
};
use solana_stake_program::stake_state::{self, PointValue, StakeState};
use solana_stake_program::stake_state::{self, PointValue};
use solana_vote_program::{
self,
vote_state::{self, VoteState},
@ -2040,7 +2041,7 @@ fn main() {
if remove_stake_accounts {
for (address, mut account) in bank
.get_program_accounts(&solana_stake_program::id())
.get_program_accounts(&stake::program::id())
.unwrap()
.into_iter()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2730,7 +2730,6 @@ dependencies = [
"serde_json",
"solana-config-program",
"solana-sdk",
"solana-stake-program",
"solana-vote-program",
"spl-token",
"thiserror",
@ -3143,7 +3142,6 @@ dependencies = [
"solana-clap-utils",
"solana-client",
"solana-sdk",
"solana-stake-program",
"solana-transaction-status",
"solana-vote-program",
"spl-memo",
@ -3643,7 +3641,6 @@ dependencies = [
"solana-account-decoder",
"solana-runtime",
"solana-sdk",
"solana-stake-program",
"solana-vote-program",
"spl-associated-token-account",
"spl-memo",

View File

@ -1297,7 +1297,7 @@ fn assert_instruction_count() {
("solana_bpf_rust_external_spend", 504),
("solana_bpf_rust_iter", 724),
("solana_bpf_rust_many_args", 233),
("solana_bpf_rust_mem", 3096),
("solana_bpf_rust_mem", 3117),
("solana_bpf_rust_membuiltins", 4065),
("solana_bpf_rust_noop", 478),
("solana_bpf_rust_param_passing", 46),

View File

@ -9,6 +9,7 @@ use solana_sdk::{
account::{Account, AccountSharedData},
pubkey::Pubkey,
short_vec,
stake::config::Config as StakeConfig,
};
solana_sdk::declare_id!("Config1111111111111111111111111111111111111");
@ -18,6 +19,13 @@ pub trait ConfigState: serde::Serialize + Default {
fn max_space() -> u64;
}
// TODO move ConfigState into `solana_program` to implement trait locally
impl ConfigState for StakeConfig {
fn max_space() -> u64 {
serialized_size(&StakeConfig::default()).unwrap()
}
}
/// A collection of keys to be stored in Config account data.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ConfigKeys {

View File

@ -1,52 +1,36 @@
//! config for staking
//! carries variables that the stake program cares about
use bincode::{deserialize, serialized_size};
use serde_derive::{Deserialize, Serialize};
use solana_config_program::{create_config_account, get_config_data, ConfigState};
use bincode::deserialize;
use solana_config_program::{create_config_account, get_config_data};
use solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount},
genesis_config::GenesisConfig,
instruction::InstructionError,
keyed_account::KeyedAccount,
stake::config::{self, Config},
};
// stake config ID
solana_sdk::declare_id!("StakeConfig11111111111111111111111111111111");
#[deprecated(
since = "1.8.0",
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
// 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,
pub fn from<T: ReadableAccount>(account: &T) -> Option<Config> {
get_config_data(&account.data())
.ok()
.and_then(|data| deserialize(data).ok())
}
impl Config {
pub fn from<T: ReadableAccount>(account: &T) -> Option<Self> {
get_config_data(&account.data())
.ok()
.and_then(|data| deserialize(data).ok())
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionError> {
if !config::check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
}
impl Default for Config {
fn default() -> Self {
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 create_account(lamports: u64, config: &Config) -> AccountSharedData {
create_config_account(vec![], config, lamports)
}
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));
genesis_config.add_account(id(), account);
genesis_config.add_account(config::id(), account);
lamports
}
pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData {
create_config_account(vec![], config, lamports)
}
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionError> {
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
Config::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)]
mod tests {
use super::*;
@ -80,7 +53,7 @@ mod tests {
#[test]
fn test() {
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!(
from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)),
Err(InstructionError::InvalidArgument)

View File

@ -2,15 +2,16 @@
#![allow(clippy::integer_arithmetic)]
use solana_sdk::genesis_config::GenesisConfig;
#[deprecated(
since = "1.8.0",
note = "Please use `solana_sdk::stake::program::id` or `solana_program::stake::program::id` instead"
)]
pub use solana_sdk::stake::program::{check_id, id};
pub mod config;
pub mod stake_instruction;
pub mod stake_state;
solana_sdk::declare_id!("Stake11111111111111111111111111111111111111");
pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 {
config::add_genesis_account(genesis_config)
}
#[macro_use]
extern crate solana_frozen_abi_macro;

View File

@ -1,481 +1,23 @@
use crate::{
config, id,
stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState},
use {
crate::{config, stake_state::StakeAccount},
log::*,
solana_sdk::{
feature_set,
instruction::InstructionError,
keyed_account::{from_keyed_account, get_signers, keyed_account_at_index},
process_instruction::{get_sysvar, InvokeContext},
program_utils::limited_deserialize,
pubkey::Pubkey,
stake::{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
#[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(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)
}
#[deprecated(
since = "1.8.0",
note = "Please use `solana_sdk::stake::instruction` or `solana_program::stake::instruction` instead"
)]
pub use solana_sdk::stake::instruction::*;
pub fn process_instruction(
_program_id: &Pubkey,
@ -637,9 +179,15 @@ mod tests {
use bincode::serialize;
use solana_sdk::{
account::{self, Account, AccountSharedData, WritableAccount},
instruction::Instruction,
keyed_account::KeyedAccount,
process_instruction::{mock_set_sysvar, MockInvokeContext},
rent::Rent,
stake::{
config as stake_config,
instruction::{self, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
sysvar::stake_history::StakeHistory,
};
use std::cell::RefCell;
@ -685,8 +233,8 @@ mod tests {
))
} else if sysvar::stake_history::check_id(&meta.pubkey) {
account::create_account_shared_data_for_test(&StakeHistory::default())
} else if config::check_id(&meta.pubkey) {
config::create_account(0, &config::Config::default())
} else if stake_config::check_id(&meta.pubkey) {
config::create_account(0, &stake_config::Config::default())
} else if sysvar::rent::check_id(&meta.pubkey) {
account::create_account_shared_data_for_test(&Rent::default())
} else if meta.pubkey == invalid_stake_state_pubkey() {
@ -735,7 +283,7 @@ mod tests {
#[test]
fn test_stake_process_instruction() {
assert_eq!(
process_instruction(&initialize(
process_instruction(&instruction::initialize(
&Pubkey::default(),
&Authorized::default(),
&Lockup::default()
@ -743,7 +291,7 @@ mod tests {
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&authorize(
process_instruction(&instruction::authorize(
&Pubkey::default(),
&Pubkey::default(),
&Pubkey::default(),
@ -754,7 +302,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&split(
&instruction::split(
&Pubkey::default(),
&Pubkey::default(),
100,
@ -765,7 +313,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&merge(
&instruction::merge(
&Pubkey::default(),
&invalid_stake_state_pubkey(),
&Pubkey::default(),
@ -775,7 +323,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&split_with_seed(
&instruction::split_with_seed(
&Pubkey::default(),
&Pubkey::default(),
100,
@ -787,7 +335,7 @@ mod tests {
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&delegate_stake(
process_instruction(&instruction::delegate_stake(
&Pubkey::default(),
&Pubkey::default(),
&invalid_vote_state_pubkey(),
@ -795,7 +343,7 @@ mod tests {
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&withdraw(
process_instruction(&instruction::withdraw(
&Pubkey::default(),
&Pubkey::default(),
&solana_sdk::pubkey::new_rand(),
@ -805,11 +353,14 @@ mod tests {
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&deactivate_stake(&Pubkey::default(), &Pubkey::default())),
process_instruction(&instruction::deactivate_stake(
&Pubkey::default(),
&Pubkey::default()
)),
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&set_lockup(
process_instruction(&instruction::set_lockup(
&Pubkey::default(),
&LockupArgs::default(),
&Pubkey::default()
@ -821,7 +372,7 @@ mod tests {
#[test]
fn test_spoofed_stake_accounts() {
assert_eq!(
process_instruction(&initialize(
process_instruction(&instruction::initialize(
&spoofed_stake_state_pubkey(),
&Authorized::default(),
&Lockup::default()
@ -829,7 +380,7 @@ mod tests {
Err(InstructionError::InvalidAccountOwner),
);
assert_eq!(
process_instruction(&authorize(
process_instruction(&instruction::authorize(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&Pubkey::default(),
@ -840,7 +391,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&split(
&instruction::split(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
100,
@ -851,7 +402,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&split(
&instruction::split(
&Pubkey::default(),
&Pubkey::default(),
100,
@ -862,7 +413,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&merge(
&instruction::merge(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&Pubkey::default(),
@ -872,7 +423,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&merge(
&instruction::merge(
&Pubkey::default(),
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
@ -882,7 +433,7 @@ mod tests {
);
assert_eq!(
process_instruction(
&split_with_seed(
&instruction::split_with_seed(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
100,
@ -894,7 +445,7 @@ mod tests {
Err(InstructionError::InvalidAccountOwner),
);
assert_eq!(
process_instruction(&delegate_stake(
process_instruction(&instruction::delegate_stake(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&Pubkey::default(),
@ -902,7 +453,7 @@ mod tests {
Err(InstructionError::InvalidAccountOwner),
);
assert_eq!(
process_instruction(&withdraw(
process_instruction(&instruction::withdraw(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&solana_sdk::pubkey::new_rand(),
@ -912,14 +463,14 @@ mod tests {
Err(InstructionError::InvalidAccountOwner),
);
assert_eq!(
process_instruction(&deactivate_stake(
process_instruction(&instruction::deactivate_stake(
&spoofed_stake_state_pubkey(),
&Pubkey::default()
)),
Err(InstructionError::InvalidAccountOwner),
);
assert_eq!(
process_instruction(&set_lockup(
process_instruction(&instruction::set_lockup(
&spoofed_stake_state_pubkey(),
&LockupArgs::default(),
&Pubkey::default()
@ -1051,8 +602,9 @@ mod tests {
let stake_history_account = RefCell::new(account::create_account_shared_data_for_test(
&sysvar::stake_history::StakeHistory::default(),
));
let config_address = config::id();
let config_account = RefCell::new(config::create_account(0, &config::Config::default()));
let config_address = stake_config::id();
let config_account =
RefCell::new(config::create_account(0, &stake_config::Config::default()));
let keyed_accounts = vec![
KeyedAccount::new(&stake_address, true, &stake_account),
KeyedAccount::new(&vote_address, false, &bad_vote_account),
@ -1140,30 +692,4 @@ mod tests {
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.8.0" }
solana-poh = { path = "../poh", version = "=1.8.0" }
solana-runtime = { path = "../runtime", version = "=1.8.0" }
solana-sdk = { path = "../sdk", version = "=1.8.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.8.0" }
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.8.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.8.0" }
solana-version = { path = "../version", version = "=1.8.0" }
@ -52,6 +51,7 @@ tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to sta
serial_test = "0.4.0"
solana-logger = { path = "../logger", version = "=1.8.0" }
solana-net-utils = { path = "../net-utils", version = "=1.8.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.8.0" }
symlink = "0.1.0"
[lib]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,8 +4,12 @@ use {
bank::Bank,
},
log::*,
solana_sdk::{account::ReadableAccount, pubkey::Pubkey},
solana_stake_program::stake_state::StakeState,
solana_sdk::{
account::ReadableAccount,
pubkey::Pubkey,
stake::{self, state::StakeState},
},
solana_stake_program::stake_state,
std::{collections::HashSet, sync::Arc},
};
@ -32,19 +36,19 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> ScanResult<NonCircu
.contains(&AccountIndex::ProgramId)
{
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 current AccountsDb implementation, an account may remain in storage as a
// zero-lamport Account::Default() after being wiped and reinitialized in later
// updates. We include the redundant filter here to avoid returning these accounts.
|account| account.owner() == &solana_stake_program::id(),
|account| account.owner() == &stake::program::id(),
)?
} else {
bank.get_program_accounts(&solana_stake_program::id())?
bank.get_program_accounts(&stake::program::id())?
};
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 {
StakeState::Initialized(meta) => {
if meta.lockup.is_in_force(&clock, None)
@ -196,8 +200,8 @@ mod tests {
account::AccountSharedData,
epoch_schedule::EpochSchedule,
genesis_config::{ClusterType, GenesisConfig},
stake::state::{Authorized, Lockup, Meta},
};
use solana_stake_program::stake_state::{Authorized, Lockup, Meta, StakeState};
use std::{collections::BTreeMap, sync::Arc};
fn new_from_parent(parent: &Arc<Bank>) -> Bank {
@ -236,7 +240,7 @@ mod tests {
balance,
&StakeState::Initialized(meta),
std::mem::size_of::<StakeState>(),
&solana_stake_program::id(),
&stake::program::id(),
)
.unwrap();
accounts.insert(pubkey, stake_account);

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,13 +27,13 @@ use solana_sdk::{
message::Message,
native_token::{lamports_to_sol, sol_to_lamports},
signature::{unique_signers, Signature, Signer},
stake::{
instruction::{self as stake_instruction, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
system_instruction,
transaction::Transaction,
};
use solana_stake_program::{
stake_instruction::{self, LockupArgs},
stake_state::{Authorized, Lockup, StakeAuthorize},
};
use solana_transaction_status::TransactionStatus;
use spl_associated_token_account_v1_0::get_associated_token_address;
use spl_token_v2_0::solana_program::program_error::ProgramError;
@ -1204,8 +1204,10 @@ pub fn test_process_distribute_stake_with_client(client: &RpcClient, sender_keyp
mod tests {
use super::*;
use solana_core::test_validator::TestValidator;
use solana_sdk::signature::{read_keypair_file, write_keypair_file, Signer};
use solana_stake_program::stake_instruction::StakeInstruction;
use solana_sdk::{
signature::{read_keypair_file, write_keypair_file, Signer},
stake::instruction::StakeInstruction,
};
use solana_transaction_status::TransactionConfirmationStatus;
#[test]

View File

@ -21,7 +21,6 @@ serde_json = "1.0.64"
solana-account-decoder = { path = "../account-decoder", version = "=1.8.0" }
solana-sdk = { path = "../sdk", version = "=1.8.0" }
solana-runtime = { path = "../runtime", version = "=1.8.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.8.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.8.0" }
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2", features = ["no-entrypoint"] }
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }

View File

@ -9,7 +9,7 @@ use crate::{
use inflector::Inflector;
use serde_json::Value;
use solana_account_decoder::parse_token::spl_token_id_v2_0;
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, system_program};
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, stake, system_program};
use std::{collections::HashMap, str::from_utf8};
use thiserror::Error;
@ -19,7 +19,7 @@ lazy_static! {
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
static ref MEMO_V1_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::v1::id().to_bytes());
static ref MEMO_V3_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::id().to_bytes());
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();

View File

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