* Refactor stake program into solana_program (#17906) * Move stake state / instructions into solana_program * Update account-decoder * Update cli and runtime * Update all other parts * Commit Cargo.lock changes in programs/bpf * Update cli stake instruction import * Allow integer arithmetic * Update ABI digest * Bump rust mem instruction count * Remove useless structs * Move stake::id() -> stake::program::id() * Re-export from solana_sdk and mark deprecated * Address feedback * Run cargo fmt * Run cargo fmt post cherry-pick
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -3888,7 +3888,6 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-config-program",
|
"solana-config-program",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-token",
|
"spl-token",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -4167,7 +4166,6 @@ dependencies = [
|
|||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
@@ -4208,7 +4206,6 @@ dependencies = [
|
|||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-memo",
|
"spl-memo",
|
||||||
@@ -4669,7 +4666,6 @@ dependencies = [
|
|||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-storage-bigtable",
|
"solana-storage-bigtable",
|
||||||
"solana-storage-proto",
|
"solana-storage-proto",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
@@ -4905,7 +4901,6 @@ dependencies = [
|
|||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-rayon-threadlimit",
|
"solana-rayon-threadlimit",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5035,7 +5030,6 @@ dependencies = [
|
|||||||
"solana-logger 1.7.2",
|
"solana-logger 1.7.2",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio 1.1.1",
|
"tokio 1.1.1",
|
||||||
@@ -5293,7 +5287,6 @@ dependencies = [
|
|||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
"solana-rpc",
|
"solana-rpc",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@@ -5430,7 +5423,6 @@ dependencies = [
|
|||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-version",
|
"solana-version",
|
||||||
"spl-associated-token-account",
|
"spl-associated-token-account",
|
||||||
@@ -5454,7 +5446,6 @@ dependencies = [
|
|||||||
"solana-account-decoder",
|
"solana-account-decoder",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-associated-token-account",
|
"spl-associated-token-account",
|
||||||
"spl-memo",
|
"spl-memo",
|
||||||
|
@@ -21,7 +21,6 @@ serde_derive = "1.0.103"
|
|||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-config-program = { path = "../programs/config", version = "=1.7.2" }
|
solana-config-program = { path = "../programs/config", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
@@ -9,14 +9,14 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar};
|
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
||||||
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
|
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
|
||||||
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
|
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
|
||||||
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
||||||
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
|
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
|
||||||
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
|
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
|
||||||
|
@@ -6,10 +6,10 @@ use bincode::deserialize;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use solana_config_program::{get_config_data, ConfigKeys};
|
use solana_config_program::{get_config_data, ConfigKeys};
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_stake_program::config::Config as StakeConfig;
|
use solana_sdk::stake::config::{self as stake_config, Config as StakeConfig};
|
||||||
|
|
||||||
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
|
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
|
||||||
let parsed_account = if pubkey == &solana_stake_program::config::id() {
|
let parsed_account = if pubkey == &stake_config::id() {
|
||||||
get_config_data(data)
|
get_config_data(data)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|data| deserialize::<StakeConfig>(data).ok())
|
.and_then(|data| deserialize::<StakeConfig>(data).ok())
|
||||||
@@ -101,11 +101,7 @@ mod test {
|
|||||||
};
|
};
|
||||||
let stake_config_account = create_config_account(vec![], &stake_config, 10);
|
let stake_config_account = create_config_account(vec![], &stake_config, 10);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_config(
|
parse_config(&stake_config_account.data(), &stake_config::id()).unwrap(),
|
||||||
&stake_config_account.data(),
|
|
||||||
&solana_stake_program::config::id()
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
ConfigAccountType::StakeConfig(UiStakeConfig {
|
ConfigAccountType::StakeConfig(UiStakeConfig {
|
||||||
warmup_cooldown_rate: 0.25,
|
warmup_cooldown_rate: 0.25,
|
||||||
slash_penalty: 50,
|
slash_penalty: 50,
|
||||||
|
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use solana_sdk::clock::{Epoch, UnixTimestamp};
|
use solana_sdk::clock::{Epoch, UnixTimestamp};
|
||||||
use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
|
use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
|
||||||
|
|
||||||
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
|
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
|
||||||
let stake_state: StakeState = deserialize(data)
|
let stake_state: StakeState = deserialize(data)
|
||||||
|
@@ -23,7 +23,6 @@ solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
|||||||
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
solana-clap-utils = { path = "../clap-utils", version = "=1.7.2" }
|
||||||
solana-client = { path = "../client", version = "=1.7.2" }
|
solana-client = { path = "../client", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||||
|
@@ -25,10 +25,10 @@ use {
|
|||||||
native_token::lamports_to_sol,
|
native_token::lamports_to_sol,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
|
stake::state::{Authorized, Lockup},
|
||||||
stake_history::StakeHistoryEntry,
|
stake_history::StakeHistoryEntry,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
},
|
},
|
||||||
solana_stake_program::stake_state::{Authorized, Lockup},
|
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
|
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
|
||||||
UiTransactionStatusMeta,
|
UiTransactionStatusMeta,
|
||||||
|
@@ -5,7 +5,7 @@ use {
|
|||||||
indicatif::{ProgressBar, ProgressStyle},
|
indicatif::{ProgressBar, ProgressStyle},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
|
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
|
||||||
program_utils::limited_deserialize, pubkey::Pubkey, transaction::Transaction,
|
program_utils::limited_deserialize, pubkey::Pubkey, stake, transaction::Transaction,
|
||||||
},
|
},
|
||||||
solana_transaction_status::UiTransactionStatusMeta,
|
solana_transaction_status::UiTransactionStatusMeta,
|
||||||
spl_memo::id as spl_memo_id,
|
spl_memo::id as spl_memo_id,
|
||||||
@@ -244,10 +244,9 @@ pub fn write_transaction<W: io::Write>(
|
|||||||
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
|
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
|
||||||
raw = false;
|
raw = false;
|
||||||
}
|
}
|
||||||
} else if program_pubkey == solana_stake_program::id() {
|
} else if program_pubkey == stake::program::id() {
|
||||||
if let Ok(stake_instruction) = limited_deserialize::<
|
if let Ok(stake_instruction) =
|
||||||
solana_stake_program::stake_instruction::StakeInstruction,
|
limited_deserialize::<stake::instruction::StakeInstruction>(&instruction.data)
|
||||||
>(&instruction.data)
|
|
||||||
{
|
{
|
||||||
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
|
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
|
||||||
raw = false;
|
raw = false;
|
||||||
|
@@ -41,7 +41,6 @@ solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
|||||||
solana_rbpf = "=0.2.11"
|
solana_rbpf = "=0.2.11"
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||||
solana-version = { path = "../version", version = "=1.7.2" }
|
solana-version = { path = "../version", version = "=1.7.2" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||||
|
@@ -45,14 +45,15 @@ use solana_sdk::{
|
|||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Signature, Signer, SignerError},
|
signature::{Signature, Signer, SignerError},
|
||||||
|
stake::{
|
||||||
|
self,
|
||||||
|
instruction::LockupArgs,
|
||||||
|
state::{Lockup, StakeAuthorize},
|
||||||
|
},
|
||||||
system_instruction::{self, SystemError},
|
system_instruction::{self, SystemError},
|
||||||
system_program,
|
system_program,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
|
||||||
stake_instruction::LockupArgs,
|
|
||||||
stake_state::{Lockup, StakeAuthorize},
|
|
||||||
};
|
|
||||||
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
|
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
|
||||||
use solana_vote_program::vote_state::VoteAuthorize;
|
use solana_vote_program::vote_state::VoteAuthorize;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -932,7 +933,7 @@ pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
|
|||||||
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
|
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
|
||||||
matches.value_of(arg_name).and_then(|v| match v {
|
matches.value_of(arg_name).and_then(|v| match v {
|
||||||
"NONCE" => Some(system_program::id()),
|
"NONCE" => Some(system_program::id()),
|
||||||
"STAKE" => Some(solana_stake_program::id()),
|
"STAKE" => Some(stake::program::id()),
|
||||||
"VOTE" => Some(solana_vote_program::id()),
|
"VOTE" => Some(solana_vote_program::id()),
|
||||||
_ => pubkey_of(matches, arg_name),
|
_ => pubkey_of(matches, arg_name),
|
||||||
})
|
})
|
||||||
@@ -2487,7 +2488,7 @@ mod tests {
|
|||||||
let from_pubkey = Some(solana_sdk::pubkey::new_rand());
|
let from_pubkey = Some(solana_sdk::pubkey::new_rand());
|
||||||
let from_str = from_pubkey.unwrap().to_string();
|
let from_str = from_pubkey.unwrap().to_string();
|
||||||
for (name, program_id) in &[
|
for (name, program_id) in &[
|
||||||
("STAKE", solana_stake_program::id()),
|
("STAKE", stake::program::id()),
|
||||||
("VOTE", solana_vote_program::id()),
|
("VOTE", solana_vote_program::id()),
|
||||||
("NONCE", system_program::id()),
|
("NONCE", system_program::id()),
|
||||||
] {
|
] {
|
||||||
@@ -2523,7 +2524,7 @@ mod tests {
|
|||||||
command: CliCommand::CreateAddressWithSeed {
|
command: CliCommand::CreateAddressWithSeed {
|
||||||
from_pubkey: None,
|
from_pubkey: None,
|
||||||
seed: "seed".to_string(),
|
seed: "seed".to_string(),
|
||||||
program_id: solana_stake_program::id(),
|
program_id: stake::program::id(),
|
||||||
},
|
},
|
||||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||||
}
|
}
|
||||||
@@ -2786,11 +2787,11 @@ mod tests {
|
|||||||
config.command = CliCommand::CreateAddressWithSeed {
|
config.command = CliCommand::CreateAddressWithSeed {
|
||||||
from_pubkey: Some(from_pubkey),
|
from_pubkey: Some(from_pubkey),
|
||||||
seed: "seed".to_string(),
|
seed: "seed".to_string(),
|
||||||
program_id: solana_stake_program::id(),
|
program_id: stake::program::id(),
|
||||||
};
|
};
|
||||||
let address = process_command(&config);
|
let address = process_command(&config);
|
||||||
let expected_address =
|
let expected_address =
|
||||||
Pubkey::create_with_seed(&from_pubkey, "seed", &solana_stake_program::id()).unwrap();
|
Pubkey::create_with_seed(&from_pubkey, "seed", &stake::program::id()).unwrap();
|
||||||
assert_eq!(address.unwrap(), expected_address.to_string());
|
assert_eq!(address.unwrap(), expected_address.to_string());
|
||||||
|
|
||||||
// Need airdrop cases
|
// Need airdrop cases
|
||||||
@@ -3177,7 +3178,7 @@ mod tests {
|
|||||||
memo: None,
|
memo: None,
|
||||||
fee_payer: 0,
|
fee_payer: 0,
|
||||||
derived_address_seed: Some(derived_address_seed),
|
derived_address_seed: Some(derived_address_seed),
|
||||||
derived_address_program_id: Some(solana_stake_program::id()),
|
derived_address_program_id: Some(stake::program::id()),
|
||||||
},
|
},
|
||||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,9 @@ use solana_sdk::{
|
|||||||
rent::Rent,
|
rent::Rent,
|
||||||
rpc_port::DEFAULT_RPC_PORT_STR,
|
rpc_port::DEFAULT_RPC_PORT_STR,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
slot_history, system_instruction, system_program,
|
slot_history,
|
||||||
|
stake::{self, state::StakeState},
|
||||||
|
system_instruction, system_program,
|
||||||
sysvar::{
|
sysvar::{
|
||||||
self,
|
self,
|
||||||
slot_history::SlotHistory,
|
slot_history::SlotHistory,
|
||||||
@@ -55,7 +57,6 @@ use solana_sdk::{
|
|||||||
timing,
|
timing,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::StakeState;
|
|
||||||
use solana_transaction_status::UiTransactionEncoding;
|
use solana_transaction_status::UiTransactionEncoding;
|
||||||
use solana_vote_program::vote_state::VoteState;
|
use solana_vote_program::vote_state::VoteState;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -1707,7 +1708,7 @@ pub fn process_show_stakes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let all_stake_accounts = rpc_client
|
let all_stake_accounts = rpc_client
|
||||||
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?;
|
.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?;
|
||||||
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
||||||
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
|
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
|
||||||
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
|
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
|
||||||
|
@@ -36,6 +36,11 @@ use solana_sdk::{
|
|||||||
feature, feature_set,
|
feature, feature_set,
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
stake::{
|
||||||
|
self,
|
||||||
|
instruction::{self as stake_instruction, LockupArgs, StakeError},
|
||||||
|
state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
|
||||||
|
},
|
||||||
system_instruction::SystemError,
|
system_instruction::SystemError,
|
||||||
sysvar::{
|
sysvar::{
|
||||||
clock,
|
clock,
|
||||||
@@ -43,10 +48,6 @@ use solana_sdk::{
|
|||||||
},
|
},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
|
||||||
stake_instruction::{self, LockupArgs, StakeError},
|
|
||||||
stake_state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
|
|
||||||
};
|
|
||||||
use solana_vote_program::vote_state::VoteState;
|
use solana_vote_program::vote_state::VoteState;
|
||||||
use std::{ops::Deref, sync::Arc};
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
@@ -971,7 +972,7 @@ pub fn process_create_stake_account(
|
|||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let stake_account = config.signers[stake_account];
|
let stake_account = config.signers[stake_account];
|
||||||
let stake_account_address = if let Some(seed) = seed {
|
let stake_account_address = if let Some(seed) = seed {
|
||||||
Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &solana_stake_program::id())?
|
Pubkey::create_with_seed(&stake_account.pubkey(), &seed, &stake::program::id())?
|
||||||
} else {
|
} else {
|
||||||
stake_account.pubkey()
|
stake_account.pubkey()
|
||||||
};
|
};
|
||||||
@@ -1039,7 +1040,7 @@ pub fn process_create_stake_account(
|
|||||||
|
|
||||||
if !sign_only {
|
if !sign_only {
|
||||||
if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) {
|
if let Ok(stake_account) = rpc_client.get_account(&stake_account_address) {
|
||||||
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
let err_msg = if stake_account.owner == stake::program::id() {
|
||||||
format!("Stake account {} already exists", stake_account_address)
|
format!("Stake account {} already exists", stake_account_address)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
@@ -1195,7 +1196,7 @@ pub fn process_deactivate_stake_account(
|
|||||||
let stake_authority = config.signers[stake_authority];
|
let stake_authority = config.signers[stake_authority];
|
||||||
|
|
||||||
let stake_account_address = if let Some(seed) = seed {
|
let stake_account_address = if let Some(seed) = seed {
|
||||||
Pubkey::create_with_seed(&stake_account_pubkey, seed, &solana_stake_program::id())?
|
Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::program::id())?
|
||||||
} else {
|
} else {
|
||||||
*stake_account_pubkey
|
*stake_account_pubkey
|
||||||
};
|
};
|
||||||
@@ -1273,7 +1274,7 @@ pub fn process_withdraw_stake(
|
|||||||
let custodian = custodian.map(|index| config.signers[index]);
|
let custodian = custodian.map(|index| config.signers[index]);
|
||||||
|
|
||||||
let stake_account_address = if let Some(seed) = seed {
|
let stake_account_address = if let Some(seed) = seed {
|
||||||
Pubkey::create_with_seed(&stake_account_pubkey, seed, &solana_stake_program::id())?
|
Pubkey::create_with_seed(&stake_account_pubkey, seed, &stake::program::id())?
|
||||||
} else {
|
} else {
|
||||||
*stake_account_pubkey
|
*stake_account_pubkey
|
||||||
};
|
};
|
||||||
@@ -1394,18 +1395,14 @@ pub fn process_split_stake(
|
|||||||
let stake_authority = config.signers[stake_authority];
|
let stake_authority = config.signers[stake_authority];
|
||||||
|
|
||||||
let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
|
let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
|
||||||
Pubkey::create_with_seed(
|
Pubkey::create_with_seed(&split_stake_account.pubkey(), &seed, &stake::program::id())?
|
||||||
&split_stake_account.pubkey(),
|
|
||||||
&seed,
|
|
||||||
&solana_stake_program::id(),
|
|
||||||
)?
|
|
||||||
} else {
|
} else {
|
||||||
split_stake_account.pubkey()
|
split_stake_account.pubkey()
|
||||||
};
|
};
|
||||||
|
|
||||||
if !sign_only {
|
if !sign_only {
|
||||||
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
|
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
|
||||||
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
let err_msg = if stake_account.owner == stake::program::id() {
|
||||||
format!(
|
format!(
|
||||||
"Stake account {} already exists",
|
"Stake account {} already exists",
|
||||||
split_stake_account_address
|
split_stake_account_address
|
||||||
@@ -1540,7 +1537,7 @@ pub fn process_merge_stake(
|
|||||||
if !sign_only {
|
if !sign_only {
|
||||||
for stake_account_address in &[stake_account_pubkey, source_stake_account_pubkey] {
|
for stake_account_address in &[stake_account_pubkey, source_stake_account_pubkey] {
|
||||||
if let Ok(stake_account) = rpc_client.get_account(stake_account_address) {
|
if let Ok(stake_account) = rpc_client.get_account(stake_account_address) {
|
||||||
if stake_account.owner != solana_stake_program::id() {
|
if stake_account.owner != stake::program::id() {
|
||||||
return Err(CliError::BadParameter(format!(
|
return Err(CliError::BadParameter(format!(
|
||||||
"Account {} is not a stake account",
|
"Account {} is not a stake account",
|
||||||
stake_account_address
|
stake_account_address
|
||||||
@@ -1876,7 +1873,7 @@ pub fn process_show_stake_account(
|
|||||||
with_rewards: Option<usize>,
|
with_rewards: Option<usize>,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let stake_account = rpc_client.get_account(stake_account_address)?;
|
let stake_account = rpc_client.get_account(stake_account_address)?;
|
||||||
if stake_account.owner != solana_stake_program::id() {
|
if stake_account.owner != stake::program::id() {
|
||||||
return Err(CliError::RpcRequestError(format!(
|
return Err(CliError::RpcRequestError(format!(
|
||||||
"{:?} is not a stake account",
|
"{:?} is not a stake account",
|
||||||
stake_account_address,
|
stake_account_address,
|
||||||
|
@@ -17,10 +17,11 @@ use solana_sdk::{
|
|||||||
nonce::State as NonceState,
|
nonce::State as NonceState,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{keypair_from_seed, Keypair, Signer},
|
signature::{keypair_from_seed, Keypair, Signer},
|
||||||
};
|
stake::{
|
||||||
use solana_stake_program::{
|
self,
|
||||||
stake_instruction::LockupArgs,
|
instruction::LockupArgs,
|
||||||
stake_state::{Lockup, StakeAuthorize, StakeState},
|
state::{Lockup, StakeAuthorize, StakeState},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -139,7 +140,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
|||||||
let stake_address = Pubkey::create_with_seed(
|
let stake_address = Pubkey::create_with_seed(
|
||||||
&config_validator.signers[0].pubkey(),
|
&config_validator.signers[0].pubkey(),
|
||||||
"hi there",
|
"hi there",
|
||||||
&solana_stake_program::id(),
|
&stake::program::id(),
|
||||||
)
|
)
|
||||||
.expect("bad seed");
|
.expect("bad seed");
|
||||||
|
|
||||||
@@ -1557,6 +1558,6 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
};
|
};
|
||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
let seed_address =
|
let seed_address =
|
||||||
Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap();
|
Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
|
||||||
check_recent_balance(50_000, &rpc_client, &seed_address);
|
check_recent_balance(50_000, &rpc_client, &seed_address);
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ use solana_sdk::{
|
|||||||
nonce::State as NonceState,
|
nonce::State as NonceState,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
|
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
|
||||||
|
stake,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -513,7 +514,7 @@ fn test_transfer_with_seed() {
|
|||||||
let sender_pubkey = config.signers[0].pubkey();
|
let sender_pubkey = config.signers[0].pubkey();
|
||||||
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
|
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
|
||||||
let derived_address_seed = "seed".to_string();
|
let derived_address_seed = "seed".to_string();
|
||||||
let derived_address_program_id = solana_stake_program::id();
|
let derived_address_program_id = stake::program::id();
|
||||||
let derived_address = Pubkey::create_with_seed(
|
let derived_address = Pubkey::create_with_seed(
|
||||||
&sender_pubkey,
|
&sender_pubkey,
|
||||||
&derived_address_seed,
|
&derived_address_seed,
|
||||||
|
@@ -62,7 +62,6 @@ solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
|||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.7.2" }
|
solana-frozen-abi = { path = "../frozen-abi", version = "=1.7.2" }
|
||||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.7.2" }
|
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-streamer = { path = "../streamer", version = "=1.7.2" }
|
solana-streamer = { path = "../streamer", version = "=1.7.2" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||||
solana-version = { path = "../version", version = "=1.7.2" }
|
solana-version = { path = "../version", version = "=1.7.2" }
|
||||||
@@ -81,6 +80,7 @@ num_cpus = "1.13.0"
|
|||||||
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
serial_test = "0.4.0"
|
serial_test = "0.4.0"
|
||||||
|
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
||||||
solana-version = { path = "../version", version = "=1.7.2" }
|
solana-version = { path = "../version", version = "=1.7.2" }
|
||||||
symlink = "0.1.0"
|
symlink = "0.1.0"
|
||||||
systemstat = "0.1.5"
|
systemstat = "0.1.5"
|
||||||
|
@@ -41,7 +41,7 @@ Create and manage accounts representing stake and rewards for delegations to
|
|||||||
validators.
|
validators.
|
||||||
|
|
||||||
- Program id: `Stake11111111111111111111111111111111111111`
|
- Program id: `Stake11111111111111111111111111111111111111`
|
||||||
- Instructions: [StakeInstruction](https://docs.rs/solana-stake-program/VERSION_FOR_DOCS_RS/solana_stake_program/stake_instruction/enum.StakeInstruction.html)
|
- Instructions: [StakeInstruction](https://docs.rs/solana-sdk/VERSION_FOR_DOCS_RS/solana_sdk/stake/instruction/enum.StakeInstruction.html)
|
||||||
|
|
||||||
## Vote Program
|
## Vote Program
|
||||||
|
|
||||||
|
@@ -26,9 +26,10 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::state::StakeState,
|
||||||
system_program, timing,
|
system_program, timing,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::{self, StakeState};
|
use solana_stake_program::stake_state;
|
||||||
use solana_vote_program::vote_state::{self, VoteState};
|
use solana_vote_program::vote_state::{self, VoteState};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
@@ -1,15 +1,22 @@
|
|||||||
//! stakes generator
|
//! stakes generator
|
||||||
use crate::{
|
use {
|
||||||
address_generator::AddressGenerator,
|
crate::{
|
||||||
unlocks::{UnlockInfo, Unlocks},
|
address_generator::AddressGenerator,
|
||||||
};
|
unlocks::{UnlockInfo, Unlocks},
|
||||||
use solana_sdk::{
|
},
|
||||||
account::Account, clock::Slot, genesis_config::GenesisConfig, pubkey::Pubkey, system_program,
|
solana_sdk::{
|
||||||
timing::years_as_slots,
|
account::Account,
|
||||||
};
|
clock::Slot,
|
||||||
use solana_stake_program::{
|
genesis_config::GenesisConfig,
|
||||||
self,
|
pubkey::Pubkey,
|
||||||
stake_state::{create_lockup_stake_account, Authorized, Lockup, StakeState},
|
stake::{
|
||||||
|
self,
|
||||||
|
state::{Authorized, Lockup, StakeState},
|
||||||
|
},
|
||||||
|
system_program,
|
||||||
|
timing::years_as_slots,
|
||||||
|
},
|
||||||
|
solana_stake_program::stake_state::create_lockup_stake_account,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -98,8 +105,7 @@ pub fn create_and_add_stakes(
|
|||||||
genesis_config.ticks_per_slot,
|
genesis_config.ticks_per_slot,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut address_generator =
|
let mut address_generator = AddressGenerator::new(&authorized.staker, &stake::program::id());
|
||||||
AddressGenerator::new(&authorized.staker, &solana_stake_program::id());
|
|
||||||
|
|
||||||
let stake_rent_reserve = StakeState::get_rent_exempt_reserve(&genesis_config.rent);
|
let stake_rent_reserve = StakeState::get_rent_exempt_reserve(&genesis_config.rent);
|
||||||
|
|
||||||
|
@@ -42,9 +42,10 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
shred_version::compute_shred_version,
|
shred_version::compute_shred_version,
|
||||||
|
stake::{self, state::StakeState},
|
||||||
system_program,
|
system_program,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::{self, PointValue, StakeState};
|
use solana_stake_program::stake_state::{self, PointValue};
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
self,
|
self,
|
||||||
vote_state::{self, VoteState},
|
vote_state::{self, VoteState},
|
||||||
@@ -1971,9 +1972,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if remove_stake_accounts {
|
if remove_stake_accounts {
|
||||||
for (address, mut account) in bank
|
for (address, mut account) in
|
||||||
.get_program_accounts(&solana_stake_program::id())
|
bank.get_program_accounts(&stake::program::id()).into_iter()
|
||||||
.into_iter()
|
|
||||||
{
|
{
|
||||||
account.set_lamports(0);
|
account.set_lamports(0);
|
||||||
bank.store_account(&address, &account);
|
bank.store_account(&address, &account);
|
||||||
|
@@ -46,7 +46,6 @@ solana-perf = { path = "../perf", version = "=1.7.2" }
|
|||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
|
||||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" }
|
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" }
|
||||||
solana-storage-proto = { path = "../storage-proto", version = "=1.7.2" }
|
solana-storage-proto = { path = "../storage-proto", version = "=1.7.2" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||||
@@ -67,7 +66,6 @@ features = ["lz4"]
|
|||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
matches = "0.1.6"
|
matches = "0.1.6"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
rustc_version = "0.2"
|
rustc_version = "0.2"
|
||||||
|
@@ -74,13 +74,13 @@ pub(crate) mod tests {
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
signers::Signers,
|
signers::Signers,
|
||||||
|
stake::{
|
||||||
|
instruction as stake_instruction,
|
||||||
|
state::{Authorized, Delegation, Lockup, Stake},
|
||||||
|
},
|
||||||
sysvar::stake_history::{self, StakeHistory},
|
sysvar::stake_history::{self, StakeHistory},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
|
||||||
stake_instruction,
|
|
||||||
stake_state::{Authorized, Delegation, Lockup, Stake},
|
|
||||||
};
|
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{VoteInit, VoteState, VoteStateVersions},
|
vote_state::{VoteInit, VoteState, VoteStateVersions},
|
||||||
|
@@ -29,13 +29,14 @@ use solana_sdk::{
|
|||||||
poh_config::PohConfig,
|
poh_config::PohConfig,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::{
|
||||||
|
config as stake_config, instruction as stake_instruction,
|
||||||
|
state::{Authorized, Lockup},
|
||||||
|
},
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
use solana_stake_program::{config::create_account as create_stake_config_account, stake_state};
|
||||||
config as stake_config, stake_instruction,
|
|
||||||
stake_state::{Authorized, Lockup, StakeState},
|
|
||||||
};
|
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{VoteInit, VoteState},
|
vote_state::{VoteInit, VoteState},
|
||||||
@@ -190,7 +191,7 @@ impl LocalCluster {
|
|||||||
// Replace staking config
|
// Replace staking config
|
||||||
genesis_config.add_account(
|
genesis_config.add_account(
|
||||||
stake_config::id(),
|
stake_config::id(),
|
||||||
stake_config::create_account(
|
create_stake_config_account(
|
||||||
1,
|
1,
|
||||||
&stake_config::Config {
|
&stake_config::Config {
|
||||||
warmup_cooldown_rate: 1_000_000_000.0f64,
|
warmup_cooldown_rate: 1_000_000_000.0f64,
|
||||||
@@ -568,7 +569,7 @@ impl LocalCluster {
|
|||||||
) {
|
) {
|
||||||
(Ok(Some(stake_account)), Ok(Some(vote_account))) => {
|
(Ok(Some(stake_account)), Ok(Some(vote_account))) => {
|
||||||
match (
|
match (
|
||||||
StakeState::stake_from(&stake_account),
|
stake_state::stake_from(&stake_account),
|
||||||
VoteState::from(&vote_account),
|
VoteState::from(&vote_account),
|
||||||
) {
|
) {
|
||||||
(Some(stake_state), Some(vote_state)) => {
|
(Some(stake_state), Some(vote_state)) => {
|
||||||
|
@@ -1402,7 +1402,7 @@ fn test_mainnet_beta_cluster_type() {
|
|||||||
for program_id in [
|
for program_id in [
|
||||||
&solana_config_program::id(),
|
&solana_config_program::id(),
|
||||||
&solana_sdk::system_program::id(),
|
&solana_sdk::system_program::id(),
|
||||||
&solana_stake_program::id(),
|
&solana_sdk::stake::program::id(),
|
||||||
&solana_vote_program::id(),
|
&solana_vote_program::id(),
|
||||||
&solana_sdk::bpf_loader_deprecated::id(),
|
&solana_sdk::bpf_loader_deprecated::id(),
|
||||||
&solana_sdk::bpf_loader::id(),
|
&solana_sdk::bpf_loader::id(),
|
||||||
|
@@ -23,7 +23,6 @@ solana-logger = { path = "../logger", version = "=1.7.2" }
|
|||||||
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "solana_perf"
|
name = "solana_perf"
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
use solana_sdk::hash::Hash;
|
use solana_sdk::{
|
||||||
use solana_sdk::instruction::CompiledInstruction;
|
hash::Hash,
|
||||||
use solana_sdk::signature::{Keypair, Signer};
|
instruction::CompiledInstruction,
|
||||||
use solana_sdk::system_instruction::SystemInstruction;
|
signature::{Keypair, Signer},
|
||||||
use solana_sdk::system_program;
|
stake,
|
||||||
use solana_sdk::system_transaction;
|
system_instruction::SystemInstruction,
|
||||||
use solana_sdk::transaction::Transaction;
|
system_program, system_transaction,
|
||||||
|
transaction::Transaction,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn test_tx() -> Transaction {
|
pub fn test_tx() -> Transaction {
|
||||||
let keypair1 = Keypair::new();
|
let keypair1 = Keypair::new();
|
||||||
@@ -22,7 +24,7 @@ pub fn test_multisig_tx() -> Transaction {
|
|||||||
|
|
||||||
let transfer_instruction = SystemInstruction::Transfer { lamports };
|
let transfer_instruction = SystemInstruction::Transfer { lamports };
|
||||||
|
|
||||||
let program_ids = vec![system_program::id(), solana_stake_program::id()];
|
let program_ids = vec![system_program::id(), stake::program::id()];
|
||||||
|
|
||||||
let instructions = vec![CompiledInstruction::new(
|
let instructions = vec![CompiledInstruction::new(
|
||||||
0,
|
0,
|
||||||
|
@@ -29,4 +29,3 @@ tokio = { version = "1", features = ["full"] }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
|
@@ -12,6 +12,10 @@ use {
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::{
|
||||||
|
instruction as stake_instruction,
|
||||||
|
state::{Authorized, Lockup, StakeState},
|
||||||
|
},
|
||||||
system_instruction, system_program,
|
system_instruction, system_program,
|
||||||
sysvar::{
|
sysvar::{
|
||||||
clock,
|
clock,
|
||||||
@@ -20,10 +24,6 @@ use {
|
|||||||
},
|
},
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
},
|
},
|
||||||
solana_stake_program::{
|
|
||||||
stake_instruction,
|
|
||||||
stake_state::{Authorized, Lockup, StakeState},
|
|
||||||
},
|
|
||||||
solana_vote_program::{
|
solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{VoteInit, VoteState},
|
vote_state::{VoteInit, VoteState},
|
||||||
|
3
programs/bpf/Cargo.lock
generated
3
programs/bpf/Cargo.lock
generated
@@ -2715,7 +2715,6 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-config-program",
|
"solana-config-program",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-token",
|
"spl-token",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -3126,7 +3125,6 @@ dependencies = [
|
|||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-memo",
|
"spl-memo",
|
||||||
@@ -3626,7 +3624,6 @@ dependencies = [
|
|||||||
"solana-account-decoder",
|
"solana-account-decoder",
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana-stake-program",
|
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
"spl-associated-token-account",
|
"spl-associated-token-account",
|
||||||
"spl-memo",
|
"spl-memo",
|
||||||
|
@@ -9,6 +9,7 @@ use solana_sdk::{
|
|||||||
account::{Account, AccountSharedData},
|
account::{Account, AccountSharedData},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
short_vec,
|
short_vec,
|
||||||
|
stake::config::Config as StakeConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
solana_sdk::declare_id!("Config1111111111111111111111111111111111111");
|
solana_sdk::declare_id!("Config1111111111111111111111111111111111111");
|
||||||
@@ -18,6 +19,13 @@ pub trait ConfigState: serde::Serialize + Default {
|
|||||||
fn max_space() -> u64;
|
fn max_space() -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move ConfigState into `solana_program` to implement trait locally
|
||||||
|
impl ConfigState for StakeConfig {
|
||||||
|
fn max_space() -> u64 {
|
||||||
|
serialized_size(&StakeConfig::default()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A collection of keys to be stored in Config account data.
|
/// A collection of keys to be stored in Config account data.
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct ConfigKeys {
|
pub struct ConfigKeys {
|
||||||
|
@@ -1,52 +1,36 @@
|
|||||||
//! config for staking
|
//! config for staking
|
||||||
//! carries variables that the stake program cares about
|
//! carries variables that the stake program cares about
|
||||||
use bincode::{deserialize, serialized_size};
|
use bincode::deserialize;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use solana_config_program::{create_config_account, get_config_data};
|
||||||
use solana_config_program::{create_config_account, get_config_data, ConfigState};
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
||||||
genesis_config::GenesisConfig,
|
genesis_config::GenesisConfig,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
|
stake::config::{self, Config},
|
||||||
};
|
};
|
||||||
|
|
||||||
// stake config ID
|
#[deprecated(
|
||||||
solana_sdk::declare_id!("StakeConfig11111111111111111111111111111111");
|
since = "1.7.2",
|
||||||
|
note = "Please use `solana_sdk::stake::config` or `solana_program::stake::config` instead"
|
||||||
|
)]
|
||||||
|
pub use solana_sdk::stake::config::*;
|
||||||
|
|
||||||
// means that no more than RATE of current effective stake may be added or subtracted per
|
pub fn from<T: ReadableAccount>(account: &T) -> Option<Config> {
|
||||||
// epoch
|
get_config_data(&account.data())
|
||||||
pub const DEFAULT_WARMUP_COOLDOWN_RATE: f64 = 0.25;
|
.ok()
|
||||||
pub const DEFAULT_SLASH_PENALTY: u8 = ((5 * std::u8::MAX as usize) / 100) as u8;
|
.and_then(|data| deserialize(data).ok())
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
|
|
||||||
pub struct Config {
|
|
||||||
/// how much stake we can activate/deactivate per-epoch as a fraction of currently effective stake
|
|
||||||
pub warmup_cooldown_rate: f64,
|
|
||||||
/// percentage of stake lost when slash, expressed as a portion of std::u8::MAX
|
|
||||||
pub slash_penalty: u8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionError> {
|
||||||
pub fn from<T: ReadableAccount>(account: &T) -> Option<Self> {
|
if !config::check_id(account.unsigned_key()) {
|
||||||
get_config_data(&account.data())
|
return Err(InstructionError::InvalidArgument);
|
||||||
.ok()
|
|
||||||
.and_then(|data| deserialize(data).ok())
|
|
||||||
}
|
}
|
||||||
|
from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData {
|
||||||
fn default() -> Self {
|
create_config_account(vec![], config, lamports)
|
||||||
Self {
|
|
||||||
warmup_cooldown_rate: DEFAULT_WARMUP_COOLDOWN_RATE,
|
|
||||||
slash_penalty: DEFAULT_SLASH_PENALTY,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConfigState for Config {
|
|
||||||
fn max_space() -> u64 {
|
|
||||||
serialized_size(&Config::default()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 {
|
pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 {
|
||||||
@@ -55,22 +39,11 @@ pub fn add_genesis_account(genesis_config: &mut GenesisConfig) -> u64 {
|
|||||||
|
|
||||||
account.set_lamports(lamports.max(1));
|
account.set_lamports(lamports.max(1));
|
||||||
|
|
||||||
genesis_config.add_account(id(), account);
|
genesis_config.add_account(config::id(), account);
|
||||||
|
|
||||||
lamports
|
lamports
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_account(lamports: u64, config: &Config) -> AccountSharedData {
|
|
||||||
create_config_account(vec![], config, lamports)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Config, InstructionError> {
|
|
||||||
if !check_id(account.unsigned_key()) {
|
|
||||||
return Err(InstructionError::InvalidArgument);
|
|
||||||
}
|
|
||||||
Config::from(&*account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -80,7 +53,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
let account = RefCell::new(create_account(0, &Config::default()));
|
let account = RefCell::new(create_account(0, &Config::default()));
|
||||||
assert_eq!(Config::from(&account.borrow()), Some(Config::default()));
|
assert_eq!(from(&account.borrow()), Some(Config::default()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)),
|
from_keyed_account(&KeyedAccount::new(&Pubkey::default(), false, &account)),
|
||||||
Err(InstructionError::InvalidArgument)
|
Err(InstructionError::InvalidArgument)
|
||||||
|
@@ -2,15 +2,16 @@
|
|||||||
#![allow(clippy::integer_arithmetic)]
|
#![allow(clippy::integer_arithmetic)]
|
||||||
use solana_sdk::genesis_config::GenesisConfig;
|
use solana_sdk::genesis_config::GenesisConfig;
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "1.7.2",
|
||||||
|
note = "Please use `solana_sdk::stake::program::id` or `solana_program::stake::program::id` instead"
|
||||||
|
)]
|
||||||
|
pub use solana_sdk::stake::program::{check_id, id};
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod stake_instruction;
|
pub mod stake_instruction;
|
||||||
pub mod stake_state;
|
pub mod stake_state;
|
||||||
|
|
||||||
solana_sdk::declare_id!("Stake11111111111111111111111111111111111111");
|
|
||||||
|
|
||||||
pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 {
|
pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig) -> u64 {
|
||||||
config::add_genesis_account(genesis_config)
|
config::add_genesis_account(genesis_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate solana_frozen_abi_macro;
|
|
||||||
|
@@ -1,481 +1,23 @@
|
|||||||
use crate::{
|
use {
|
||||||
config, id,
|
crate::{config, stake_state::StakeAccount},
|
||||||
stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState},
|
log::*,
|
||||||
|
solana_sdk::{
|
||||||
|
feature_set,
|
||||||
|
instruction::InstructionError,
|
||||||
|
keyed_account::{from_keyed_account, get_signers, keyed_account_at_index},
|
||||||
|
process_instruction::{get_sysvar, InvokeContext},
|
||||||
|
program_utils::limited_deserialize,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
stake::{instruction::StakeInstruction, program::id},
|
||||||
|
sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use log::*;
|
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
use solana_sdk::{
|
|
||||||
clock::{Epoch, UnixTimestamp},
|
|
||||||
decode_error::DecodeError,
|
|
||||||
feature_set,
|
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
|
||||||
keyed_account::{from_keyed_account, get_signers, keyed_account_at_index},
|
|
||||||
process_instruction::{get_sysvar, InvokeContext},
|
|
||||||
program_utils::limited_deserialize,
|
|
||||||
pubkey::Pubkey,
|
|
||||||
system_instruction,
|
|
||||||
sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory},
|
|
||||||
};
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
/// Reasons the stake might have had an error
|
#[deprecated(
|
||||||
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
|
since = "1.7.2",
|
||||||
pub enum StakeError {
|
note = "Please use `solana_sdk::stake::instruction` or `solana_program::stake::instruction` instead"
|
||||||
#[error("not enough credits to redeem")]
|
)]
|
||||||
NoCreditsToRedeem,
|
pub use solana_sdk::stake::instruction::*;
|
||||||
|
|
||||||
#[error("lockup has not yet expired")]
|
|
||||||
LockupInForce,
|
|
||||||
|
|
||||||
#[error("stake already deactivated")]
|
|
||||||
AlreadyDeactivated,
|
|
||||||
|
|
||||||
#[error("one re-delegation permitted per epoch")]
|
|
||||||
TooSoonToRedelegate,
|
|
||||||
|
|
||||||
#[error("split amount is more than is staked")]
|
|
||||||
InsufficientStake,
|
|
||||||
|
|
||||||
#[error("stake account with transient stake cannot be merged")]
|
|
||||||
MergeTransientStake,
|
|
||||||
|
|
||||||
#[error("stake account merge failed due to different authority, lockups or state")]
|
|
||||||
MergeMismatch,
|
|
||||||
|
|
||||||
#[error("custodian address not present")]
|
|
||||||
CustodianMissing,
|
|
||||||
|
|
||||||
#[error("custodian signature not present")]
|
|
||||||
CustodianSignatureMissing,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E> DecodeError<E> for StakeError {
|
|
||||||
fn type_of() -> &'static str {
|
|
||||||
"StakeError"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
|
||||||
pub enum StakeInstruction {
|
|
||||||
/// Initialize a stake with lockup and authorization information
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Uninitialized stake account
|
|
||||||
/// 1. [] Rent sysvar
|
|
||||||
///
|
|
||||||
/// Authorized carries pubkeys that must sign staker transactions
|
|
||||||
/// and withdrawer transactions.
|
|
||||||
/// Lockup carries information about withdrawal restrictions
|
|
||||||
Initialize(Authorized, Lockup),
|
|
||||||
|
|
||||||
/// Authorize a key to manage stake or withdrawal
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Stake account to be updated
|
|
||||||
/// 1. [] Clock sysvar
|
|
||||||
/// 2. [SIGNER] The stake or withdraw authority
|
|
||||||
/// 3. Optional: [SIGNER] Lockup authority, if updating StakeAuthorize::Withdrawer before
|
|
||||||
/// lockup expiration
|
|
||||||
Authorize(Pubkey, StakeAuthorize),
|
|
||||||
|
|
||||||
/// Delegate a stake to a particular vote account
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Initialized stake account to be delegated
|
|
||||||
/// 1. [] Vote account to which this stake will be delegated
|
|
||||||
/// 2. [] Clock sysvar
|
|
||||||
/// 3. [] Stake history sysvar that carries stake warmup/cooldown history
|
|
||||||
/// 4. [] Address of config account that carries stake config
|
|
||||||
/// 5. [SIGNER] Stake authority
|
|
||||||
///
|
|
||||||
/// The entire balance of the staking account is staked. DelegateStake
|
|
||||||
/// can be called multiple times, but re-delegation is delayed
|
|
||||||
/// by one epoch
|
|
||||||
DelegateStake,
|
|
||||||
|
|
||||||
/// Split u64 tokens and stake off a stake account into another stake account.
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Stake account to be split; must be in the Initialized or Stake state
|
|
||||||
/// 1. [WRITE] Uninitialized stake account that will take the split-off amount
|
|
||||||
/// 2. [SIGNER] Stake authority
|
|
||||||
Split(u64),
|
|
||||||
|
|
||||||
/// Withdraw unstaked lamports from the stake account
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Stake account from which to withdraw
|
|
||||||
/// 1. [WRITE] Recipient account
|
|
||||||
/// 2. [] Clock sysvar
|
|
||||||
/// 3. [] Stake history sysvar that carries stake warmup/cooldown history
|
|
||||||
/// 4. [SIGNER] Withdraw authority
|
|
||||||
/// 5. Optional: [SIGNER] Lockup authority, if before lockup expiration
|
|
||||||
///
|
|
||||||
/// The u64 is the portion of the stake account balance to be withdrawn,
|
|
||||||
/// must be `<= StakeAccount.lamports - staked_lamports`.
|
|
||||||
Withdraw(u64),
|
|
||||||
|
|
||||||
/// Deactivates the stake in the account
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Delegated stake account
|
|
||||||
/// 1. [] Clock sysvar
|
|
||||||
/// 2. [SIGNER] Stake authority
|
|
||||||
Deactivate,
|
|
||||||
|
|
||||||
/// Set stake lockup
|
|
||||||
///
|
|
||||||
/// If a lockup is not active, the withdraw authority may set a new lockup
|
|
||||||
/// If a lockup is active, the lockup custodian may update the lockup parameters
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Initialized stake account
|
|
||||||
/// 1. [SIGNER] Lockup authority or withdraw authority
|
|
||||||
SetLockup(LockupArgs),
|
|
||||||
|
|
||||||
/// Merge two stake accounts.
|
|
||||||
///
|
|
||||||
/// Both accounts must have identical lockup and authority keys. A merge
|
|
||||||
/// is possible between two stakes in the following states with no additional
|
|
||||||
/// conditions:
|
|
||||||
///
|
|
||||||
/// * two deactivated stakes
|
|
||||||
/// * an inactive stake into an activating stake during its activation epoch
|
|
||||||
///
|
|
||||||
/// For the following cases, the voter pubkey and vote credits observed must match:
|
|
||||||
///
|
|
||||||
/// * two activated stakes
|
|
||||||
/// * two activating accounts that share an activation epoch, during the activation epoch
|
|
||||||
///
|
|
||||||
/// All other combinations of stake states will fail to merge, including all
|
|
||||||
/// "transient" states, where a stake is activating or deactivating with a
|
|
||||||
/// non-zero effective stake.
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Destination stake account for the merge
|
|
||||||
/// 1. [WRITE] Source stake account for to merge. This account will be drained
|
|
||||||
/// 2. [] Clock sysvar
|
|
||||||
/// 3. [] Stake history sysvar that carries stake warmup/cooldown history
|
|
||||||
/// 4. [SIGNER] Stake authority
|
|
||||||
Merge,
|
|
||||||
|
|
||||||
/// Authorize a key to manage stake or withdrawal with a derived key
|
|
||||||
///
|
|
||||||
/// # Account references
|
|
||||||
/// 0. [WRITE] Stake account to be updated
|
|
||||||
/// 1. [SIGNER] Base key of stake or withdraw authority
|
|
||||||
/// 2. [] Clock sysvar
|
|
||||||
/// 3. Optional: [SIGNER] Lockup authority, if updating StakeAuthorize::Withdrawer before
|
|
||||||
/// lockup expiration
|
|
||||||
AuthorizeWithSeed(AuthorizeWithSeedArgs),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
|
|
||||||
pub struct LockupArgs {
|
|
||||||
pub unix_timestamp: Option<UnixTimestamp>,
|
|
||||||
pub epoch: Option<Epoch>,
|
|
||||||
pub custodian: Option<Pubkey>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
|
||||||
pub struct AuthorizeWithSeedArgs {
|
|
||||||
pub new_authorized_pubkey: Pubkey,
|
|
||||||
pub stake_authorize: StakeAuthorize,
|
|
||||||
pub authority_seed: String,
|
|
||||||
pub authority_owner: Pubkey,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
|
|
||||||
Instruction::new_with_bincode(
|
|
||||||
id(),
|
|
||||||
&StakeInstruction::Initialize(*authorized, *lockup),
|
|
||||||
vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_account_with_seed(
|
|
||||||
from_pubkey: &Pubkey,
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
base: &Pubkey,
|
|
||||||
seed: &str,
|
|
||||||
authorized: &Authorized,
|
|
||||||
lockup: &Lockup,
|
|
||||||
lamports: u64,
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
vec![
|
|
||||||
system_instruction::create_account_with_seed(
|
|
||||||
from_pubkey,
|
|
||||||
stake_pubkey,
|
|
||||||
base,
|
|
||||||
seed,
|
|
||||||
lamports,
|
|
||||||
std::mem::size_of::<StakeState>() as u64,
|
|
||||||
&id(),
|
|
||||||
),
|
|
||||||
initialize(stake_pubkey, authorized, lockup),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_account(
|
|
||||||
from_pubkey: &Pubkey,
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authorized: &Authorized,
|
|
||||||
lockup: &Lockup,
|
|
||||||
lamports: u64,
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
vec![
|
|
||||||
system_instruction::create_account(
|
|
||||||
from_pubkey,
|
|
||||||
stake_pubkey,
|
|
||||||
lamports,
|
|
||||||
std::mem::size_of::<StakeState>() as u64,
|
|
||||||
&id(),
|
|
||||||
),
|
|
||||||
initialize(stake_pubkey, authorized, lockup),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _split(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authorized_pubkey: &Pubkey,
|
|
||||||
lamports: u64,
|
|
||||||
split_stake_pubkey: &Pubkey,
|
|
||||||
) -> Instruction {
|
|
||||||
let account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new(*split_stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
|
||||||
];
|
|
||||||
|
|
||||||
Instruction::new_with_bincode(id(), &StakeInstruction::Split(lamports), account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authorized_pubkey: &Pubkey,
|
|
||||||
lamports: u64,
|
|
||||||
split_stake_pubkey: &Pubkey,
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
vec![
|
|
||||||
system_instruction::allocate(split_stake_pubkey, std::mem::size_of::<StakeState>() as u64),
|
|
||||||
system_instruction::assign(split_stake_pubkey, &id()),
|
|
||||||
_split(
|
|
||||||
stake_pubkey,
|
|
||||||
authorized_pubkey,
|
|
||||||
lamports,
|
|
||||||
split_stake_pubkey,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split_with_seed(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authorized_pubkey: &Pubkey,
|
|
||||||
lamports: u64,
|
|
||||||
split_stake_pubkey: &Pubkey, // derived using create_with_seed()
|
|
||||||
base: &Pubkey, // base
|
|
||||||
seed: &str, // seed
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
vec![
|
|
||||||
system_instruction::allocate_with_seed(
|
|
||||||
split_stake_pubkey,
|
|
||||||
base,
|
|
||||||
seed,
|
|
||||||
std::mem::size_of::<StakeState>() as u64,
|
|
||||||
&id(),
|
|
||||||
),
|
|
||||||
_split(
|
|
||||||
stake_pubkey,
|
|
||||||
authorized_pubkey,
|
|
||||||
lamports,
|
|
||||||
split_stake_pubkey,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn merge(
|
|
||||||
destination_stake_pubkey: &Pubkey,
|
|
||||||
source_stake_pubkey: &Pubkey,
|
|
||||||
authorized_pubkey: &Pubkey,
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
let account_metas = vec![
|
|
||||||
AccountMeta::new(*destination_stake_pubkey, false),
|
|
||||||
AccountMeta::new(*source_stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
|
||||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
|
||||||
];
|
|
||||||
|
|
||||||
vec![Instruction::new_with_bincode(
|
|
||||||
id(),
|
|
||||||
&StakeInstruction::Merge,
|
|
||||||
account_metas,
|
|
||||||
)]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_account_and_delegate_stake(
|
|
||||||
from_pubkey: &Pubkey,
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
vote_pubkey: &Pubkey,
|
|
||||||
authorized: &Authorized,
|
|
||||||
lockup: &Lockup,
|
|
||||||
lamports: u64,
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
let mut instructions = create_account(from_pubkey, stake_pubkey, authorized, lockup, lamports);
|
|
||||||
instructions.push(delegate_stake(
|
|
||||||
stake_pubkey,
|
|
||||||
&authorized.staker,
|
|
||||||
vote_pubkey,
|
|
||||||
));
|
|
||||||
instructions
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_account_with_seed_and_delegate_stake(
|
|
||||||
from_pubkey: &Pubkey,
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
base: &Pubkey,
|
|
||||||
seed: &str,
|
|
||||||
vote_pubkey: &Pubkey,
|
|
||||||
authorized: &Authorized,
|
|
||||||
lockup: &Lockup,
|
|
||||||
lamports: u64,
|
|
||||||
) -> Vec<Instruction> {
|
|
||||||
let mut instructions = create_account_with_seed(
|
|
||||||
from_pubkey,
|
|
||||||
stake_pubkey,
|
|
||||||
base,
|
|
||||||
seed,
|
|
||||||
authorized,
|
|
||||||
lockup,
|
|
||||||
lamports,
|
|
||||||
);
|
|
||||||
instructions.push(delegate_stake(
|
|
||||||
stake_pubkey,
|
|
||||||
&authorized.staker,
|
|
||||||
vote_pubkey,
|
|
||||||
));
|
|
||||||
instructions
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn authorize(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authorized_pubkey: &Pubkey,
|
|
||||||
new_authorized_pubkey: &Pubkey,
|
|
||||||
stake_authorize: StakeAuthorize,
|
|
||||||
custodian_pubkey: Option<&Pubkey>,
|
|
||||||
) -> Instruction {
|
|
||||||
let mut account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
|
||||||
];
|
|
||||||
|
|
||||||
if let Some(custodian_pubkey) = custodian_pubkey {
|
|
||||||
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
Instruction::new_with_bincode(
|
|
||||||
id(),
|
|
||||||
&StakeInstruction::Authorize(*new_authorized_pubkey, stake_authorize),
|
|
||||||
account_metas,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn authorize_with_seed(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authority_base: &Pubkey,
|
|
||||||
authority_seed: String,
|
|
||||||
authority_owner: &Pubkey,
|
|
||||||
new_authorized_pubkey: &Pubkey,
|
|
||||||
stake_authorize: StakeAuthorize,
|
|
||||||
custodian_pubkey: Option<&Pubkey>,
|
|
||||||
) -> Instruction {
|
|
||||||
let mut account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(*authority_base, true),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
];
|
|
||||||
|
|
||||||
if let Some(custodian_pubkey) = custodian_pubkey {
|
|
||||||
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let args = AuthorizeWithSeedArgs {
|
|
||||||
new_authorized_pubkey: *new_authorized_pubkey,
|
|
||||||
stake_authorize,
|
|
||||||
authority_seed,
|
|
||||||
authority_owner: *authority_owner,
|
|
||||||
};
|
|
||||||
|
|
||||||
Instruction::new_with_bincode(
|
|
||||||
id(),
|
|
||||||
&StakeInstruction::AuthorizeWithSeed(args),
|
|
||||||
account_metas,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delegate_stake(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
authorized_pubkey: &Pubkey,
|
|
||||||
vote_pubkey: &Pubkey,
|
|
||||||
) -> Instruction {
|
|
||||||
let account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(*vote_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
|
||||||
AccountMeta::new_readonly(crate::config::id(), false),
|
|
||||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
|
||||||
];
|
|
||||||
Instruction::new_with_bincode(id(), &StakeInstruction::DelegateStake, account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn withdraw(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
withdrawer_pubkey: &Pubkey,
|
|
||||||
to_pubkey: &Pubkey,
|
|
||||||
lamports: u64,
|
|
||||||
custodian_pubkey: Option<&Pubkey>,
|
|
||||||
) -> Instruction {
|
|
||||||
let mut account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new(*to_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
|
||||||
AccountMeta::new_readonly(*withdrawer_pubkey, true),
|
|
||||||
];
|
|
||||||
|
|
||||||
if let Some(custodian_pubkey) = custodian_pubkey {
|
|
||||||
account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
Instruction::new_with_bincode(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
|
|
||||||
let account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
AccountMeta::new_readonly(*authorized_pubkey, true),
|
|
||||||
];
|
|
||||||
Instruction::new_with_bincode(id(), &StakeInstruction::Deactivate, account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_lockup(
|
|
||||||
stake_pubkey: &Pubkey,
|
|
||||||
lockup: &LockupArgs,
|
|
||||||
custodian_pubkey: &Pubkey,
|
|
||||||
) -> Instruction {
|
|
||||||
let account_metas = vec![
|
|
||||||
AccountMeta::new(*stake_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(*custodian_pubkey, true),
|
|
||||||
];
|
|
||||||
Instruction::new_with_bincode(id(), &StakeInstruction::SetLockup(*lockup), account_metas)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
@@ -637,9 +179,15 @@ mod tests {
|
|||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{self, Account, AccountSharedData, WritableAccount},
|
account::{self, Account, AccountSharedData, WritableAccount},
|
||||||
|
instruction::Instruction,
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
process_instruction::{mock_set_sysvar, MockInvokeContext},
|
process_instruction::{mock_set_sysvar, MockInvokeContext},
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
|
stake::{
|
||||||
|
config as stake_config,
|
||||||
|
instruction::{self, LockupArgs},
|
||||||
|
state::{Authorized, Lockup, StakeAuthorize},
|
||||||
|
},
|
||||||
sysvar::stake_history::StakeHistory,
|
sysvar::stake_history::StakeHistory,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -685,8 +233,8 @@ mod tests {
|
|||||||
))
|
))
|
||||||
} else if sysvar::stake_history::check_id(&meta.pubkey) {
|
} else if sysvar::stake_history::check_id(&meta.pubkey) {
|
||||||
account::create_account_shared_data_for_test(&StakeHistory::default())
|
account::create_account_shared_data_for_test(&StakeHistory::default())
|
||||||
} else if config::check_id(&meta.pubkey) {
|
} else if stake_config::check_id(&meta.pubkey) {
|
||||||
config::create_account(0, &config::Config::default())
|
config::create_account(0, &stake_config::Config::default())
|
||||||
} else if sysvar::rent::check_id(&meta.pubkey) {
|
} else if sysvar::rent::check_id(&meta.pubkey) {
|
||||||
account::create_account_shared_data_for_test(&Rent::default())
|
account::create_account_shared_data_for_test(&Rent::default())
|
||||||
} else if meta.pubkey == invalid_stake_state_pubkey() {
|
} else if meta.pubkey == invalid_stake_state_pubkey() {
|
||||||
@@ -735,7 +283,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_stake_process_instruction() {
|
fn test_stake_process_instruction() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&initialize(
|
process_instruction(&instruction::initialize(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Authorized::default(),
|
&Authorized::default(),
|
||||||
&Lockup::default()
|
&Lockup::default()
|
||||||
@@ -743,7 +291,7 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&authorize(
|
process_instruction(&instruction::authorize(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@@ -754,7 +302,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&split(
|
&instruction::split(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
100,
|
100,
|
||||||
@@ -765,7 +313,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&merge(
|
&instruction::merge(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&invalid_stake_state_pubkey(),
|
&invalid_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@@ -775,7 +323,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&split_with_seed(
|
&instruction::split_with_seed(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
100,
|
100,
|
||||||
@@ -787,7 +335,7 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&delegate_stake(
|
process_instruction(&instruction::delegate_stake(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&invalid_vote_state_pubkey(),
|
&invalid_vote_state_pubkey(),
|
||||||
@@ -795,7 +343,7 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&withdraw(
|
process_instruction(&instruction::withdraw(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&solana_sdk::pubkey::new_rand(),
|
&solana_sdk::pubkey::new_rand(),
|
||||||
@@ -805,11 +353,14 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&deactivate_stake(&Pubkey::default(), &Pubkey::default())),
|
process_instruction(&instruction::deactivate_stake(
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default()
|
||||||
|
)),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&set_lockup(
|
process_instruction(&instruction::set_lockup(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&LockupArgs::default(),
|
&LockupArgs::default(),
|
||||||
&Pubkey::default()
|
&Pubkey::default()
|
||||||
@@ -821,7 +372,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_spoofed_stake_accounts() {
|
fn test_spoofed_stake_accounts() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&initialize(
|
process_instruction(&instruction::initialize(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Authorized::default(),
|
&Authorized::default(),
|
||||||
&Lockup::default()
|
&Lockup::default()
|
||||||
@@ -829,7 +380,7 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountOwner),
|
Err(InstructionError::InvalidAccountOwner),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&authorize(
|
process_instruction(&instruction::authorize(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@@ -840,7 +391,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&split(
|
&instruction::split(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
100,
|
100,
|
||||||
@@ -851,7 +402,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&split(
|
&instruction::split(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
100,
|
100,
|
||||||
@@ -862,7 +413,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&merge(
|
&instruction::merge(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@@ -872,7 +423,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&merge(
|
&instruction::merge(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@@ -882,7 +433,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(
|
process_instruction(
|
||||||
&split_with_seed(
|
&instruction::split_with_seed(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
100,
|
100,
|
||||||
@@ -894,7 +445,7 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountOwner),
|
Err(InstructionError::InvalidAccountOwner),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&delegate_stake(
|
process_instruction(&instruction::delegate_stake(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@@ -902,7 +453,7 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountOwner),
|
Err(InstructionError::InvalidAccountOwner),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&withdraw(
|
process_instruction(&instruction::withdraw(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&solana_sdk::pubkey::new_rand(),
|
&solana_sdk::pubkey::new_rand(),
|
||||||
@@ -912,14 +463,14 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountOwner),
|
Err(InstructionError::InvalidAccountOwner),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&deactivate_stake(
|
process_instruction(&instruction::deactivate_stake(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&Pubkey::default()
|
&Pubkey::default()
|
||||||
)),
|
)),
|
||||||
Err(InstructionError::InvalidAccountOwner),
|
Err(InstructionError::InvalidAccountOwner),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&set_lockup(
|
process_instruction(&instruction::set_lockup(
|
||||||
&spoofed_stake_state_pubkey(),
|
&spoofed_stake_state_pubkey(),
|
||||||
&LockupArgs::default(),
|
&LockupArgs::default(),
|
||||||
&Pubkey::default()
|
&Pubkey::default()
|
||||||
@@ -1051,8 +602,9 @@ mod tests {
|
|||||||
let stake_history_account = RefCell::new(account::create_account_shared_data_for_test(
|
let stake_history_account = RefCell::new(account::create_account_shared_data_for_test(
|
||||||
&sysvar::stake_history::StakeHistory::default(),
|
&sysvar::stake_history::StakeHistory::default(),
|
||||||
));
|
));
|
||||||
let config_address = config::id();
|
let config_address = stake_config::id();
|
||||||
let config_account = RefCell::new(config::create_account(0, &config::Config::default()));
|
let config_account =
|
||||||
|
RefCell::new(config::create_account(0, &stake_config::Config::default()));
|
||||||
let keyed_accounts = vec![
|
let keyed_accounts = vec![
|
||||||
KeyedAccount::new(&stake_address, true, &stake_account),
|
KeyedAccount::new(&stake_address, true, &stake_account),
|
||||||
KeyedAccount::new(&vote_address, false, &bad_vote_account),
|
KeyedAccount::new(&vote_address, false, &bad_vote_account),
|
||||||
@@ -1140,30 +692,4 @@ mod tests {
|
|||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_custom_error_decode() {
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
fn pretty_err<T>(err: InstructionError) -> String
|
|
||||||
where
|
|
||||||
T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
|
|
||||||
{
|
|
||||||
if let InstructionError::Custom(code) = err {
|
|
||||||
let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
|
|
||||||
format!(
|
|
||||||
"{:?}: {}::{:?} - {}",
|
|
||||||
err,
|
|
||||||
T::type_of(),
|
|
||||||
specific_error,
|
|
||||||
specific_error,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(
|
|
||||||
"Custom(0): StakeError::NoCreditsToRedeem - not enough credits to redeem",
|
|
||||||
pretty_err::<StakeError>(StakeError::NoCreditsToRedeem.into())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,6 @@ solana-perf = { path = "../perf", version = "=1.7.2" }
|
|||||||
solana-poh = { path = "../poh", version = "=1.7.2" }
|
solana-poh = { path = "../poh", version = "=1.7.2" }
|
||||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" }
|
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.7.2" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||||
solana-version = { path = "../version", version = "=1.7.2" }
|
solana-version = { path = "../version", version = "=1.7.2" }
|
||||||
@@ -52,6 +51,7 @@ tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to sta
|
|||||||
serial_test = "0.4.0"
|
serial_test = "0.4.0"
|
||||||
solana-logger = { path = "../logger", version = "=1.7.2" }
|
solana-logger = { path = "../logger", version = "=1.7.2" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
solana-net-utils = { path = "../net-utils", version = "=1.7.2" }
|
||||||
|
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
||||||
symlink = "0.1.0"
|
symlink = "0.1.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@@ -62,12 +62,12 @@ use {
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
sanitize::Sanitize,
|
sanitize::Sanitize,
|
||||||
signature::{Keypair, Signature, Signer},
|
signature::{Keypair, Signature, Signer},
|
||||||
|
stake::state::StakeState,
|
||||||
stake_history::StakeHistory,
|
stake_history::StakeHistory,
|
||||||
system_instruction,
|
system_instruction,
|
||||||
sysvar::stake_history,
|
sysvar::stake_history,
|
||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
},
|
},
|
||||||
solana_stake_program::stake_state::StakeState,
|
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
EncodedConfirmedTransaction, Reward, RewardType, TransactionConfirmationStatus,
|
EncodedConfirmedTransaction, Reward, RewardType, TransactionConfirmationStatus,
|
||||||
TransactionStatus, UiConfirmedBlock, UiTransactionEncoding,
|
TransactionStatus, UiConfirmedBlock, UiTransactionEncoding,
|
||||||
|
@@ -569,13 +569,14 @@ mod tests {
|
|||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::{
|
||||||
|
self, instruction as stake_instruction,
|
||||||
|
state::{Authorized, Lockup, StakeAuthorize},
|
||||||
|
},
|
||||||
system_instruction, system_program, system_transaction,
|
system_instruction, system_program, system_transaction,
|
||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
},
|
},
|
||||||
solana_stake_program::{
|
solana_stake_program::stake_state,
|
||||||
self, stake_instruction,
|
|
||||||
stake_state::{Authorized, Lockup, StakeAuthorize, StakeState},
|
|
||||||
},
|
|
||||||
solana_vote_program::vote_state::Vote,
|
solana_vote_program::vote_state::Vote,
|
||||||
std::{
|
std::{
|
||||||
sync::{atomic::AtomicBool, RwLock},
|
sync::{atomic::AtomicBool, RwLock},
|
||||||
@@ -791,7 +792,7 @@ mod tests {
|
|||||||
let stake_authority = Keypair::new();
|
let stake_authority = Keypair::new();
|
||||||
let from = Keypair::new();
|
let from = Keypair::new();
|
||||||
let stake_account = Keypair::new();
|
let stake_account = Keypair::new();
|
||||||
let stake_program_id = solana_stake_program::id();
|
let stake_program_id = stake::program::id();
|
||||||
let bank = Bank::new(&genesis_config);
|
let bank = Bank::new(&genesis_config);
|
||||||
let blockhash = bank.last_blockhash();
|
let blockhash = bank.last_blockhash();
|
||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||||
@@ -887,7 +888,7 @@ mod tests {
|
|||||||
let bank = bank_forks.read().unwrap()[1].clone();
|
let bank = bank_forks.read().unwrap()[1].clone();
|
||||||
let account = bank.get_account(&stake_account.pubkey()).unwrap();
|
let account = bank.get_account(&stake_account.pubkey()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StakeState::authorized_from(&account).unwrap().staker,
|
stake_state::authorized_from(&account).unwrap().staker,
|
||||||
new_stake_authority
|
new_stake_authority
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1343,7 +1343,7 @@ pub(crate) mod tests {
|
|||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
message::Message,
|
message::Message,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
system_instruction, system_program, system_transaction,
|
stake, system_instruction, system_program, system_transaction,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
},
|
},
|
||||||
std::{fmt::Debug, sync::mpsc::channel},
|
std::{fmt::Debug, sync::mpsc::channel},
|
||||||
@@ -1544,7 +1544,7 @@ pub(crate) mod tests {
|
|||||||
blockhash,
|
blockhash,
|
||||||
1,
|
1,
|
||||||
16,
|
16,
|
||||||
&solana_stake_program::id(),
|
&stake::program::id(),
|
||||||
);
|
);
|
||||||
bank_forks
|
bank_forks
|
||||||
.write()
|
.write()
|
||||||
@@ -1567,7 +1567,7 @@ pub(crate) mod tests {
|
|||||||
optimistically_confirmed_bank,
|
optimistically_confirmed_bank,
|
||||||
);
|
);
|
||||||
subscriptions.add_program_subscription(
|
subscriptions.add_program_subscription(
|
||||||
solana_stake_program::id(),
|
stake::program::id(),
|
||||||
Some(RpcProgramAccountsConfig {
|
Some(RpcProgramAccountsConfig {
|
||||||
account_config: RpcAccountInfoConfig {
|
account_config: RpcAccountInfoConfig {
|
||||||
commitment: Some(CommitmentConfig::processed()),
|
commitment: Some(CommitmentConfig::processed()),
|
||||||
@@ -1584,7 +1584,7 @@ pub(crate) mod tests {
|
|||||||
.program_subscriptions
|
.program_subscriptions
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains_key(&solana_stake_program::id()));
|
.contains_key(&stake::program::id()));
|
||||||
|
|
||||||
subscriptions.notify_subscribers(CommitmentSlots::default());
|
subscriptions.notify_subscribers(CommitmentSlots::default());
|
||||||
let (response, _) = robust_poll_or_panic(transport_receiver);
|
let (response, _) = robust_poll_or_panic(transport_receiver);
|
||||||
@@ -1616,7 +1616,7 @@ pub(crate) mod tests {
|
|||||||
.program_subscriptions
|
.program_subscriptions
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains_key(&solana_stake_program::id()));
|
.contains_key(&stake::program::id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2044,7 +2044,7 @@ pub(crate) mod tests {
|
|||||||
blockhash,
|
blockhash,
|
||||||
1,
|
1,
|
||||||
16,
|
16,
|
||||||
&solana_stake_program::id(),
|
&stake::program::id(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add the transaction to the 1st bank and then freeze the bank
|
// Add the transaction to the 1st bank and then freeze the bank
|
||||||
|
@@ -96,6 +96,7 @@ use solana_sdk::{
|
|||||||
signature::{Keypair, Signature},
|
signature::{Keypair, Signature},
|
||||||
slot_hashes::SlotHashes,
|
slot_hashes::SlotHashes,
|
||||||
slot_history::SlotHistory,
|
slot_history::SlotHistory,
|
||||||
|
stake::{self, state::Delegation},
|
||||||
stake_weighted_timestamp::{
|
stake_weighted_timestamp::{
|
||||||
calculate_stake_weighted_timestamp, MaxAllowableDrift, MAX_ALLOWABLE_DRIFT_PERCENTAGE,
|
calculate_stake_weighted_timestamp, MaxAllowableDrift, MAX_ALLOWABLE_DRIFT_PERCENTAGE,
|
||||||
MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW,
|
MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW,
|
||||||
@@ -105,9 +106,7 @@ use solana_sdk::{
|
|||||||
timing::years_as_slots,
|
timing::years_as_slots,
|
||||||
transaction::{self, Result, Transaction, TransactionError},
|
transaction::{self, Result, Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::{
|
use solana_stake_program::stake_state::{self, InflationPointCalculationEvent, PointValue};
|
||||||
self, Delegation, InflationPointCalculationEvent, PointValue,
|
|
||||||
};
|
|
||||||
use solana_vote_program::vote_instruction::VoteInstruction;
|
use solana_vote_program::vote_instruction::VoteInstruction;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
@@ -1902,7 +1901,7 @@ impl Bank {
|
|||||||
if self
|
if self
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&feature_set::filter_stake_delegation_accounts::id())
|
.is_active(&feature_set::filter_stake_delegation_accounts::id())
|
||||||
&& (stake_account.owner() != &solana_stake_program::id()
|
&& (stake_account.owner() != &stake::program::id()
|
||||||
|| vote_account.owner() != &solana_vote_program::id())
|
|| vote_account.owner() != &solana_vote_program::id())
|
||||||
{
|
{
|
||||||
datapoint_warn!(
|
datapoint_warn!(
|
||||||
@@ -5326,15 +5325,15 @@ pub(crate) mod tests {
|
|||||||
process_instruction::InvokeContext,
|
process_instruction::InvokeContext,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
signature::{keypair_from_seed, Keypair, Signer},
|
signature::{keypair_from_seed, Keypair, Signer},
|
||||||
|
stake::{
|
||||||
|
instruction as stake_instruction,
|
||||||
|
state::{Authorized, Delegation, Lockup, Stake},
|
||||||
|
},
|
||||||
system_instruction::{self, SystemError},
|
system_instruction::{self, SystemError},
|
||||||
system_program,
|
system_program,
|
||||||
sysvar::{fees::Fees, rewards::Rewards},
|
sysvar::{fees::Fees, rewards::Rewards},
|
||||||
timing::duration_as_s,
|
timing::duration_as_s,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
|
||||||
stake_instruction,
|
|
||||||
stake_state::{self, Authorized, Delegation, Lockup, Stake},
|
|
||||||
};
|
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{
|
vote_state::{
|
||||||
@@ -9521,7 +9520,7 @@ pub(crate) mod tests {
|
|||||||
let pubkey = solana_sdk::pubkey::new_rand();
|
let pubkey = solana_sdk::pubkey::new_rand();
|
||||||
genesis_config.add_account(
|
genesis_config.add_account(
|
||||||
pubkey,
|
pubkey,
|
||||||
solana_stake_program::stake_state::create_lockup_stake_account(
|
stake_state::create_lockup_stake_account(
|
||||||
&Authorized::auto(&pubkey),
|
&Authorized::auto(&pubkey),
|
||||||
&Lockup::default(),
|
&Lockup::default(),
|
||||||
&Rent::default(),
|
&Rent::default(),
|
||||||
|
@@ -7,7 +7,7 @@ use solana_sdk::{
|
|||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext},
|
process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_program,
|
stake, system_program,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn process_instruction_with_program_logging(
|
fn process_instruction_with_program_logging(
|
||||||
@@ -56,7 +56,7 @@ fn genesis_builtins() -> Vec<Builtin> {
|
|||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"stake_program",
|
"stake_program",
|
||||||
solana_stake_program::id(),
|
stake::program::id(),
|
||||||
with_program_logging!(solana_stake_program::stake_instruction::process_instruction),
|
with_program_logging!(solana_stake_program::stake_instruction::process_instruction),
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
|
@@ -8,10 +8,10 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::state::StakeState,
|
||||||
system_program,
|
system_program,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state;
|
use solana_stake_program::stake_state;
|
||||||
use solana_stake_program::stake_state::StakeState;
|
|
||||||
use solana_vote_program::vote_state;
|
use solana_vote_program::vote_state;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
|
@@ -4,8 +4,12 @@ use {
|
|||||||
bank::Bank,
|
bank::Bank,
|
||||||
},
|
},
|
||||||
log::*,
|
log::*,
|
||||||
solana_sdk::{account::ReadableAccount, pubkey::Pubkey},
|
solana_sdk::{
|
||||||
solana_stake_program::stake_state::StakeState,
|
account::ReadableAccount,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
stake::{self, state::StakeState},
|
||||||
|
},
|
||||||
|
solana_stake_program::stake_state,
|
||||||
std::{collections::HashSet, sync::Arc},
|
std::{collections::HashSet, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,18 +36,18 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> NonCirculatingSuppl
|
|||||||
.contains(&AccountIndex::ProgramId)
|
.contains(&AccountIndex::ProgramId)
|
||||||
{
|
{
|
||||||
bank.get_filtered_indexed_accounts(
|
bank.get_filtered_indexed_accounts(
|
||||||
&IndexKey::ProgramId(solana_stake_program::id()),
|
&IndexKey::ProgramId(stake::program::id()),
|
||||||
// The program-id account index checks for Account owner on inclusion. However, due to
|
// The program-id account index checks for Account owner on inclusion. However, due to
|
||||||
// the current AccountsDb implementation, an account may remain in storage as a
|
// the current AccountsDb implementation, an account may remain in storage as a
|
||||||
// zero-lamport Account::Default() after being wiped and reinitialized in later
|
// zero-lamport Account::Default() after being wiped and reinitialized in later
|
||||||
// updates. We include the redundant filter here to avoid returning these accounts.
|
// updates. We include the redundant filter here to avoid returning these accounts.
|
||||||
|account| account.owner() == &solana_stake_program::id(),
|
|account| account.owner() == &stake::program::id(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
bank.get_program_accounts(&solana_stake_program::id())
|
bank.get_program_accounts(&stake::program::id())
|
||||||
};
|
};
|
||||||
for (pubkey, account) in stake_accounts.iter() {
|
for (pubkey, account) in stake_accounts.iter() {
|
||||||
let stake_account = StakeState::from(account).unwrap_or_default();
|
let stake_account = stake_state::from(account).unwrap_or_default();
|
||||||
match stake_account {
|
match stake_account {
|
||||||
StakeState::Initialized(meta) => {
|
StakeState::Initialized(meta) => {
|
||||||
if meta.lockup.is_in_force(&clock, None)
|
if meta.lockup.is_in_force(&clock, None)
|
||||||
@@ -195,8 +199,8 @@ mod tests {
|
|||||||
account::AccountSharedData,
|
account::AccountSharedData,
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
genesis_config::{ClusterType, GenesisConfig},
|
genesis_config::{ClusterType, GenesisConfig},
|
||||||
|
stake::state::{Authorized, Lockup, Meta},
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::{Authorized, Lockup, Meta, StakeState};
|
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
fn new_from_parent(parent: &Arc<Bank>) -> Bank {
|
fn new_from_parent(parent: &Arc<Bank>) -> Bank {
|
||||||
@@ -235,7 +239,7 @@ mod tests {
|
|||||||
balance,
|
balance,
|
||||||
&StakeState::Initialized(meta),
|
&StakeState::Initialized(meta),
|
||||||
std::mem::size_of::<StakeState>(),
|
std::mem::size_of::<StakeState>(),
|
||||||
&solana_stake_program::id(),
|
&stake::program::id(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
accounts.insert(pubkey, stake_account);
|
accounts.insert(pubkey, stake_account);
|
||||||
|
@@ -290,7 +290,7 @@ mod test_bank_serialize {
|
|||||||
|
|
||||||
// This some what long test harness is required to freeze the ABI of
|
// This some what long test harness is required to freeze the ABI of
|
||||||
// Bank's serialization due to versioned nature
|
// Bank's serialization due to versioned nature
|
||||||
#[frozen_abi(digest = "DuRGntVwLGNAv5KooafUSpxk67BPAx2yC7Z8A9c8wr2G")]
|
#[frozen_abi(digest = "6msodEzE7YzFtorBhiP6ax4PKBaPZTkmYdGAdpoxLCvV")]
|
||||||
#[derive(Serialize, AbiExample)]
|
#[derive(Serialize, AbiExample)]
|
||||||
pub struct BankAbiTestWrapperFuture {
|
pub struct BankAbiTestWrapperFuture {
|
||||||
#[serde(serialize_with = "wrapper_future")]
|
#[serde(serialize_with = "wrapper_future")]
|
||||||
|
@@ -5,9 +5,13 @@ use solana_sdk::{
|
|||||||
account::{AccountSharedData, ReadableAccount},
|
account::{AccountSharedData, ReadableAccount},
|
||||||
clock::Epoch,
|
clock::Epoch,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
stake::{
|
||||||
|
self,
|
||||||
|
state::{Delegation, StakeState},
|
||||||
|
},
|
||||||
sysvar::stake_history::StakeHistory,
|
sysvar::stake_history::StakeHistory,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::{new_stake_history_entry, Delegation, StakeState};
|
use solana_stake_program::stake_state;
|
||||||
use solana_vote_program::vote_state::VoteState;
|
use solana_vote_program::vote_state::VoteState;
|
||||||
use std::{borrow::Borrow, collections::HashMap};
|
use std::{borrow::Borrow, collections::HashMap};
|
||||||
|
|
||||||
@@ -42,7 +46,7 @@ impl Stakes {
|
|||||||
let mut stake_history_upto_prev_epoch = self.stake_history.clone();
|
let mut stake_history_upto_prev_epoch = self.stake_history.clone();
|
||||||
stake_history_upto_prev_epoch.add(
|
stake_history_upto_prev_epoch.add(
|
||||||
prev_epoch,
|
prev_epoch,
|
||||||
new_stake_history_entry(
|
stake_state::new_stake_history_entry(
|
||||||
prev_epoch,
|
prev_epoch,
|
||||||
self.stake_delegations
|
self.stake_delegations
|
||||||
.iter()
|
.iter()
|
||||||
@@ -111,7 +115,7 @@ impl Stakes {
|
|||||||
|
|
||||||
pub fn is_stake(account: &AccountSharedData) -> bool {
|
pub fn is_stake(account: &AccountSharedData) -> bool {
|
||||||
solana_vote_program::check_id(account.owner())
|
solana_vote_program::check_id(account.owner())
|
||||||
|| solana_stake_program::check_id(account.owner())
|
|| stake::program::check_id(account.owner())
|
||||||
&& account.data().len() >= std::mem::size_of::<StakeState>()
|
&& account.data().len() >= std::mem::size_of::<StakeState>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +152,7 @@ impl Stakes {
|
|||||||
.insert(*pubkey, (stake, ArcVoteAccount::from(account.clone())));
|
.insert(*pubkey, (stake, ArcVoteAccount::from(account.clone())));
|
||||||
}
|
}
|
||||||
old.map(|(_, account)| account)
|
old.map(|(_, account)| account)
|
||||||
} else if solana_stake_program::check_id(account.owner()) {
|
} else if stake::program::check_id(account.owner()) {
|
||||||
// old_stake is stake lamports and voter_pubkey from the pre-store() version
|
// old_stake is stake lamports and voter_pubkey from the pre-store() version
|
||||||
let old_stake = self.stake_delegations.get(pubkey).map(|delegation| {
|
let old_stake = self.stake_delegations.get(pubkey).map(|delegation| {
|
||||||
(
|
(
|
||||||
@@ -157,7 +161,7 @@ impl Stakes {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let delegation = StakeState::delegation_from(account);
|
let delegation = stake_state::delegation_from(account);
|
||||||
|
|
||||||
let stake = delegation.map(|delegation| {
|
let stake = delegation.map(|delegation| {
|
||||||
(
|
(
|
||||||
@@ -308,7 +312,7 @@ pub mod tests {
|
|||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true, true);
|
||||||
let stake = StakeState::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
@@ -332,7 +336,7 @@ pub mod tests {
|
|||||||
// activate more
|
// activate more
|
||||||
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
|
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true, true);
|
||||||
let stake = StakeState::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
@@ -463,7 +467,7 @@ pub mod tests {
|
|||||||
// delegates to vote_pubkey
|
// delegates to vote_pubkey
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true, true);
|
||||||
|
|
||||||
let stake = StakeState::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@@ -523,7 +527,7 @@ pub mod tests {
|
|||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true, true);
|
||||||
let stake = StakeState::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@@ -564,7 +568,7 @@ pub mod tests {
|
|||||||
// not a stake account, and whacks above entry
|
// not a stake account, and whacks above entry
|
||||||
stakes.store(
|
stakes.store(
|
||||||
&stake_pubkey,
|
&stake_pubkey,
|
||||||
&AccountSharedData::new(1, 0, &solana_stake_program::id()),
|
&AccountSharedData::new(1, 0, &stake::program::id()),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
@@ -11,12 +11,13 @@ use solana_sdk::{
|
|||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::{
|
||||||
|
self, instruction as stake_instruction,
|
||||||
|
state::{Authorized, Lockup, StakeState},
|
||||||
|
},
|
||||||
sysvar::{self, stake_history::StakeHistory},
|
sysvar::{self, stake_history::StakeHistory},
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
use solana_stake_program::stake_state;
|
||||||
stake_instruction::{self},
|
|
||||||
stake_state::{self, StakeState},
|
|
||||||
};
|
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{Vote, VoteInit, VoteState, VoteStateVersions},
|
vote_state::{Vote, VoteInit, VoteState, VoteStateVersions},
|
||||||
@@ -69,7 +70,7 @@ fn fill_epoch_with_votes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool {
|
fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool {
|
||||||
let stake = StakeState::stake_from(&bank.get_account(stake_pubkey).unwrap()).unwrap();
|
let stake = stake_state::stake_from(&bank.get_account(stake_pubkey).unwrap()).unwrap();
|
||||||
|
|
||||||
stake.delegation.stake
|
stake.delegation.stake
|
||||||
== stake.stake(
|
== stake.stake(
|
||||||
@@ -85,7 +86,7 @@ fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 {
|
fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 {
|
||||||
StakeState::stake_from(&bank.get_account(stake_pubkey).unwrap())
|
stake_state::stake_from(&bank.get_account(stake_pubkey).unwrap())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.stake(
|
.stake(
|
||||||
bank.epoch(),
|
bank.epoch(),
|
||||||
@@ -118,9 +119,9 @@ fn test_stake_create_and_split_single_signature() {
|
|||||||
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
|
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
|
||||||
|
|
||||||
let stake_address =
|
let stake_address =
|
||||||
Pubkey::create_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap();
|
Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap();
|
||||||
|
|
||||||
let authorized = stake_state::Authorized::auto(&staker_pubkey);
|
let authorized = Authorized::auto(&staker_pubkey);
|
||||||
|
|
||||||
let lamports = 1_000_000;
|
let lamports = 1_000_000;
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ fn test_stake_create_and_split_single_signature() {
|
|||||||
&staker_pubkey, // base
|
&staker_pubkey, // base
|
||||||
"stake", // seed
|
"stake", // seed
|
||||||
&authorized,
|
&authorized,
|
||||||
&stake_state::Lockup::default(),
|
&Lockup::default(),
|
||||||
lamports,
|
lamports,
|
||||||
),
|
),
|
||||||
Some(&staker_pubkey),
|
Some(&staker_pubkey),
|
||||||
@@ -145,8 +146,7 @@ fn test_stake_create_and_split_single_signature() {
|
|||||||
|
|
||||||
// split the stake
|
// split the stake
|
||||||
let split_stake_address =
|
let split_stake_address =
|
||||||
Pubkey::create_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id())
|
Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::program::id()).unwrap();
|
||||||
.unwrap();
|
|
||||||
// Test split
|
// Test split
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&stake_instruction::split_with_seed(
|
&stake_instruction::split_with_seed(
|
||||||
@@ -189,9 +189,9 @@ fn test_stake_create_and_split_to_existing_system_account() {
|
|||||||
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
|
let bank_client = BankClient::new_shared(&Arc::new(Bank::new(&genesis_config)));
|
||||||
|
|
||||||
let stake_address =
|
let stake_address =
|
||||||
Pubkey::create_with_seed(&staker_pubkey, "stake", &solana_stake_program::id()).unwrap();
|
Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap();
|
||||||
|
|
||||||
let authorized = stake_state::Authorized::auto(&staker_pubkey);
|
let authorized = Authorized::auto(&staker_pubkey);
|
||||||
|
|
||||||
let lamports = 1_000_000;
|
let lamports = 1_000_000;
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ fn test_stake_create_and_split_to_existing_system_account() {
|
|||||||
&staker_pubkey, // base
|
&staker_pubkey, // base
|
||||||
"stake", // seed
|
"stake", // seed
|
||||||
&authorized,
|
&authorized,
|
||||||
&stake_state::Lockup::default(),
|
&Lockup::default(),
|
||||||
lamports,
|
lamports,
|
||||||
),
|
),
|
||||||
Some(&staker_pubkey),
|
Some(&staker_pubkey),
|
||||||
@@ -214,8 +214,7 @@ fn test_stake_create_and_split_to_existing_system_account() {
|
|||||||
.expect("failed to create and delegate stake account");
|
.expect("failed to create and delegate stake account");
|
||||||
|
|
||||||
let split_stake_address =
|
let split_stake_address =
|
||||||
Pubkey::create_with_seed(&staker_pubkey, "split_stake", &solana_stake_program::id())
|
Pubkey::create_with_seed(&staker_pubkey, "split_stake", &stake::program::id()).unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// First, put a system account where we want the new stake account
|
// First, put a system account where we want the new stake account
|
||||||
let existing_lamports = 42;
|
let existing_lamports = 42;
|
||||||
@@ -290,7 +289,7 @@ fn test_stake_account_lifetime() {
|
|||||||
.send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message)
|
.send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message)
|
||||||
.expect("failed to create vote account");
|
.expect("failed to create vote account");
|
||||||
|
|
||||||
let authorized = stake_state::Authorized::auto(&stake_pubkey);
|
let authorized = Authorized::auto(&stake_pubkey);
|
||||||
// Create stake account and delegate to vote account
|
// Create stake account and delegate to vote account
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&stake_instruction::create_account_and_delegate_stake(
|
&stake_instruction::create_account_and_delegate_stake(
|
||||||
@@ -298,7 +297,7 @@ fn test_stake_account_lifetime() {
|
|||||||
&stake_pubkey,
|
&stake_pubkey,
|
||||||
&vote_pubkey,
|
&vote_pubkey,
|
||||||
&authorized,
|
&authorized,
|
||||||
&stake_state::Lockup::default(),
|
&Lockup::default(),
|
||||||
1_000_000,
|
1_000_000,
|
||||||
),
|
),
|
||||||
Some(&mint_pubkey),
|
Some(&mint_pubkey),
|
||||||
@@ -516,8 +515,7 @@ fn test_create_stake_account_from_seed() {
|
|||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
let seed = "test-string";
|
let seed = "test-string";
|
||||||
let stake_pubkey =
|
let stake_pubkey = Pubkey::create_with_seed(&mint_pubkey, seed, &stake::program::id()).unwrap();
|
||||||
Pubkey::create_with_seed(&mint_pubkey, seed, &solana_stake_program::id()).unwrap();
|
|
||||||
|
|
||||||
// Create Vote Account
|
// Create Vote Account
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
@@ -538,7 +536,7 @@ fn test_create_stake_account_from_seed() {
|
|||||||
.send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message)
|
.send_and_confirm_message(&[&mint_keypair, &vote_keypair, &identity_keypair], message)
|
||||||
.expect("failed to create vote account");
|
.expect("failed to create vote account");
|
||||||
|
|
||||||
let authorized = stake_state::Authorized::auto(&mint_pubkey);
|
let authorized = Authorized::auto(&mint_pubkey);
|
||||||
// Create stake account and delegate to vote account
|
// Create stake account and delegate to vote account
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&stake_instruction::create_account_with_seed_and_delegate_stake(
|
&stake_instruction::create_account_with_seed_and_delegate_stake(
|
||||||
@@ -548,7 +546,7 @@ fn test_create_stake_account_from_seed() {
|
|||||||
seed,
|
seed,
|
||||||
&vote_pubkey,
|
&vote_pubkey,
|
||||||
&authorized,
|
&authorized,
|
||||||
&stake_state::Lockup::default(),
|
&Lockup::default(),
|
||||||
1_000_000,
|
1_000_000,
|
||||||
),
|
),
|
||||||
Some(&mint_pubkey),
|
Some(&mint_pubkey),
|
||||||
|
@@ -42,6 +42,7 @@ pub mod serialize_utils;
|
|||||||
pub mod short_vec;
|
pub mod short_vec;
|
||||||
pub mod slot_hashes;
|
pub mod slot_hashes;
|
||||||
pub mod slot_history;
|
pub mod slot_history;
|
||||||
|
pub mod stake;
|
||||||
pub mod stake_history;
|
pub mod stake_history;
|
||||||
pub mod system_instruction;
|
pub mod system_instruction;
|
||||||
pub mod system_program;
|
pub mod system_program;
|
||||||
|
28
sdk/program/src/stake/config.rs
Normal file
28
sdk/program/src/stake/config.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
508
sdk/program/src/stake/instruction.rs
Normal file
508
sdk/program/src/stake/instruction.rs
Normal 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())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
7
sdk/program/src/stake/mod.rs
Normal file
7
sdk/program/src/stake/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub mod config;
|
||||||
|
pub mod instruction;
|
||||||
|
pub mod state;
|
||||||
|
|
||||||
|
pub mod program {
|
||||||
|
crate::declare_id!("Stake11111111111111111111111111111111111111");
|
||||||
|
}
|
533
sdk/program/src/stake/state.rs
Normal file
533
sdk/program/src/stake/state.rs
Normal 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(¤t_epoch) {
|
||||||
|
prev_epoch = current_epoch;
|
||||||
|
prev_cluster_stake = current_cluster_stake;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// deactivating stake should equal to all of currently remaining effective stake
|
||||||
|
(current_effective_stake, 0, current_effective_stake)
|
||||||
|
} else {
|
||||||
|
// no history or I've dropped out of history, so assume fully deactivated
|
||||||
|
(0, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returned tuple is (effective, activating) stake
|
||||||
|
fn stake_and_activating(
|
||||||
|
&self,
|
||||||
|
target_epoch: Epoch,
|
||||||
|
history: Option<&StakeHistory>,
|
||||||
|
fix_stake_deactivate: bool,
|
||||||
|
) -> (u64, u64) {
|
||||||
|
let delegated_stake = self.stake;
|
||||||
|
|
||||||
|
if self.is_bootstrap() {
|
||||||
|
// fully effective immediately
|
||||||
|
(delegated_stake, 0)
|
||||||
|
} else if fix_stake_deactivate && self.activation_epoch == self.deactivation_epoch {
|
||||||
|
// activated but instantly deactivated; no stake at all regardless of target_epoch
|
||||||
|
// this must be after the bootstrap check and before all-is-activating check
|
||||||
|
(0, 0)
|
||||||
|
} else if target_epoch == self.activation_epoch {
|
||||||
|
// all is activating
|
||||||
|
(0, delegated_stake)
|
||||||
|
} else if target_epoch < self.activation_epoch {
|
||||||
|
// not yet enabled
|
||||||
|
(0, 0)
|
||||||
|
} else if let Some((history, mut prev_epoch, mut prev_cluster_stake)) =
|
||||||
|
history.and_then(|history| {
|
||||||
|
history
|
||||||
|
.get(&self.activation_epoch)
|
||||||
|
.map(|cluster_stake_at_activation_epoch| {
|
||||||
|
(
|
||||||
|
history,
|
||||||
|
self.activation_epoch,
|
||||||
|
cluster_stake_at_activation_epoch,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
{
|
||||||
|
// target_epoch > self.activation_epoch
|
||||||
|
|
||||||
|
// loop from my activation epoch until the target epoch summing up my entitlement
|
||||||
|
// current effective stake is updated using its previous epoch's cluster stake
|
||||||
|
let mut current_epoch;
|
||||||
|
let mut current_effective_stake = 0;
|
||||||
|
loop {
|
||||||
|
current_epoch = prev_epoch + 1;
|
||||||
|
// if there is no activating stake at prev epoch, we should have been
|
||||||
|
// fully effective at this moment
|
||||||
|
if prev_cluster_stake.activating == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// how much of the growth in stake this account is
|
||||||
|
// entitled to take
|
||||||
|
let remaining_activating_stake = delegated_stake - current_effective_stake;
|
||||||
|
let weight =
|
||||||
|
remaining_activating_stake as f64 / prev_cluster_stake.activating as f64;
|
||||||
|
|
||||||
|
// portion of newly effective cluster stake I'm entitled to at current epoch
|
||||||
|
let newly_effective_cluster_stake =
|
||||||
|
prev_cluster_stake.effective as f64 * self.warmup_cooldown_rate;
|
||||||
|
let newly_effective_stake =
|
||||||
|
((weight * newly_effective_cluster_stake) as u64).max(1);
|
||||||
|
|
||||||
|
current_effective_stake += newly_effective_stake;
|
||||||
|
if current_effective_stake >= delegated_stake {
|
||||||
|
current_effective_stake = delegated_stake;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if current_epoch >= target_epoch || current_epoch >= self.deactivation_epoch {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(current_cluster_stake) = history.get(¤t_epoch) {
|
||||||
|
prev_epoch = current_epoch;
|
||||||
|
prev_cluster_stake = current_cluster_stake;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
current_effective_stake,
|
||||||
|
delegated_stake - current_effective_stake,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// no history or I've dropped out of history, so assume fully effective
|
||||||
|
(delegated_stake, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rewrite_stake(
|
||||||
|
&mut self,
|
||||||
|
account_balance: u64,
|
||||||
|
rent_exempt_balance: u64,
|
||||||
|
) -> Option<(u64, u64)> {
|
||||||
|
// note that this will intentionally overwrite innocent
|
||||||
|
// deactivated-then-immeditealy-withdrawn stake accounts as well
|
||||||
|
// this is chosen to minimize the risks from complicated logic,
|
||||||
|
// over some unneeded rewrites
|
||||||
|
let corrected_stake = account_balance.saturating_sub(rent_exempt_balance);
|
||||||
|
if self.stake != corrected_stake {
|
||||||
|
// this could result in creating a 0-staked account;
|
||||||
|
// rewards and staking calc can handle it.
|
||||||
|
let (old, new) = (self.stake, corrected_stake);
|
||||||
|
self.stake = corrected_stake;
|
||||||
|
Some((old, new))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)]
|
||||||
|
pub struct Stake {
|
||||||
|
pub delegation: Delegation,
|
||||||
|
/// credits observed is credits from vote account state when delegated or redeemed
|
||||||
|
pub credits_observed: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stake {
|
||||||
|
pub fn stake(
|
||||||
|
&self,
|
||||||
|
epoch: Epoch,
|
||||||
|
history: Option<&StakeHistory>,
|
||||||
|
fix_stake_deactivate: bool,
|
||||||
|
) -> u64 {
|
||||||
|
self.delegation.stake(epoch, history, fix_stake_deactivate)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(
|
||||||
|
&mut self,
|
||||||
|
remaining_stake_delta: u64,
|
||||||
|
split_stake_amount: u64,
|
||||||
|
) -> Result<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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,12 +16,10 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{unique_signers, Signature, Signer},
|
signature::{unique_signers, Signature, Signer},
|
||||||
signers::Signers,
|
signers::Signers,
|
||||||
|
stake::{instruction::LockupArgs, state::Lockup},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
use solana_stake_program::stake_state;
|
||||||
stake_instruction::LockupArgs,
|
|
||||||
stake_state::{Lockup, StakeState},
|
|
||||||
};
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
@@ -52,7 +50,7 @@ fn get_balances(
|
|||||||
fn get_lockup(client: &RpcClient, address: &Pubkey) -> Result<Lockup, ClientError> {
|
fn get_lockup(client: &RpcClient, address: &Pubkey) -> Result<Lockup, ClientError> {
|
||||||
client
|
client
|
||||||
.get_account(address)
|
.get_account(address)
|
||||||
.map(|account| StakeState::lockup_from(&account).unwrap())
|
.map(|account| stake_state::lockup_from(&account).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_lockups(
|
fn get_lockups(
|
||||||
|
@@ -1,16 +1,20 @@
|
|||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::SECONDS_PER_DAY, instruction::Instruction, message::Message, pubkey::Pubkey,
|
clock::SECONDS_PER_DAY,
|
||||||
};
|
instruction::Instruction,
|
||||||
use solana_stake_program::{
|
message::Message,
|
||||||
stake_instruction::{self, LockupArgs},
|
pubkey::Pubkey,
|
||||||
stake_state::{Authorized, Lockup, StakeAuthorize},
|
stake::{
|
||||||
|
self,
|
||||||
|
instruction::{self as stake_instruction, LockupArgs},
|
||||||
|
state::{Authorized, Lockup, StakeAuthorize},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const DAYS_PER_YEAR: f64 = 365.25;
|
const DAYS_PER_YEAR: f64 = 365.25;
|
||||||
const SECONDS_PER_YEAR: i64 = (SECONDS_PER_DAY as f64 * DAYS_PER_YEAR) as i64;
|
const SECONDS_PER_YEAR: i64 = (SECONDS_PER_DAY as f64 * DAYS_PER_YEAR) as i64;
|
||||||
|
|
||||||
pub(crate) fn derive_stake_account_address(base_pubkey: &Pubkey, i: usize) -> Pubkey {
|
pub(crate) fn derive_stake_account_address(base_pubkey: &Pubkey, i: usize) -> Pubkey {
|
||||||
Pubkey::create_with_seed(base_pubkey, &i.to_string(), &solana_stake_program::id()).unwrap()
|
Pubkey::create_with_seed(base_pubkey, &i.to_string(), &stake::program::id()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return derived addresses
|
// Return derived addresses
|
||||||
@@ -284,8 +288,9 @@ mod tests {
|
|||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
genesis_config::create_genesis_config,
|
genesis_config::create_genesis_config,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::state::StakeState,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::StakeState;
|
use solana_stake_program::stake_state;
|
||||||
|
|
||||||
fn create_bank(lamports: u64) -> (Bank, Keypair, u64) {
|
fn create_bank(lamports: u64) -> (Bank, Keypair, u64) {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
||||||
@@ -338,7 +343,7 @@ mod tests {
|
|||||||
let address = derive_stake_account_address(&base_pubkey, i);
|
let address = derive_stake_account_address(&base_pubkey, i);
|
||||||
let account =
|
let account =
|
||||||
AccountSharedData::from(client.get_account(&address).unwrap().unwrap());
|
AccountSharedData::from(client.get_account(&address).unwrap().unwrap());
|
||||||
(address, StakeState::lockup_from(&account).unwrap())
|
(address, stake_state::lockup_from(&account).unwrap())
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@@ -375,7 +380,7 @@ mod tests {
|
|||||||
|
|
||||||
let account = get_account_at(&bank_client, &base_pubkey, 0);
|
let account = get_account_at(&bank_client, &base_pubkey, 0);
|
||||||
assert_eq!(account.lamports(), lamports);
|
assert_eq!(account.lamports(), lamports);
|
||||||
let authorized = StakeState::authorized_from(&account).unwrap();
|
let authorized = stake_state::authorized_from(&account).unwrap();
|
||||||
assert_eq!(authorized.staker, stake_authority_pubkey);
|
assert_eq!(authorized.staker, stake_authority_pubkey);
|
||||||
assert_eq!(authorized.withdrawer, withdraw_authority_pubkey);
|
assert_eq!(authorized.withdrawer, withdraw_authority_pubkey);
|
||||||
}
|
}
|
||||||
@@ -437,7 +442,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let account = get_account_at(&bank_client, &base_pubkey, 0);
|
let account = get_account_at(&bank_client, &base_pubkey, 0);
|
||||||
let authorized = StakeState::authorized_from(&account).unwrap();
|
let authorized = stake_state::authorized_from(&account).unwrap();
|
||||||
assert_eq!(authorized.staker, new_stake_authority_pubkey);
|
assert_eq!(authorized.staker, new_stake_authority_pubkey);
|
||||||
assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey);
|
assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey);
|
||||||
}
|
}
|
||||||
@@ -493,7 +498,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let account = get_account_at(&bank_client, &base_pubkey, 0);
|
let account = get_account_at(&bank_client, &base_pubkey, 0);
|
||||||
let lockup = StakeState::lockup_from(&account).unwrap();
|
let lockup = stake_state::lockup_from(&account).unwrap();
|
||||||
assert_eq!(lockup.unix_timestamp, 1);
|
assert_eq!(lockup.unix_timestamp, 1);
|
||||||
assert_eq!(lockup.epoch, 0);
|
assert_eq!(lockup.epoch, 0);
|
||||||
|
|
||||||
@@ -586,7 +591,7 @@ mod tests {
|
|||||||
|
|
||||||
// Ensure the new accounts are duplicates of the previous ones.
|
// Ensure the new accounts are duplicates of the previous ones.
|
||||||
let account = get_account_at(&bank_client, &new_base_pubkey, 0);
|
let account = get_account_at(&bank_client, &new_base_pubkey, 0);
|
||||||
let authorized = StakeState::authorized_from(&account).unwrap();
|
let authorized = stake_state::authorized_from(&account).unwrap();
|
||||||
assert_eq!(authorized.staker, stake_authority_pubkey);
|
assert_eq!(authorized.staker, stake_authority_pubkey);
|
||||||
assert_eq!(authorized.withdrawer, withdraw_authority_pubkey);
|
assert_eq!(authorized.withdrawer, withdraw_authority_pubkey);
|
||||||
}
|
}
|
||||||
@@ -655,7 +660,7 @@ mod tests {
|
|||||||
|
|
||||||
// Ensure the new accounts have the new authorities.
|
// Ensure the new accounts have the new authorities.
|
||||||
let account = get_account_at(&bank_client, &new_base_pubkey, 0);
|
let account = get_account_at(&bank_client, &new_base_pubkey, 0);
|
||||||
let authorized = StakeState::authorized_from(&account).unwrap();
|
let authorized = stake_state::authorized_from(&account).unwrap();
|
||||||
assert_eq!(authorized.staker, new_stake_authority_pubkey);
|
assert_eq!(authorized.staker, new_stake_authority_pubkey);
|
||||||
assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey);
|
assert_eq!(authorized.withdrawer, new_withdraw_authority_pubkey);
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,6 @@ solana-logger = { path = "../logger", version = "=1.7.2" }
|
|||||||
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
solana-metrics = { path = "../metrics", version = "=1.7.2" }
|
||||||
solana-rpc = { path = "../rpc", version = "=1.7.2" }
|
solana-rpc = { path = "../rpc", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||||
solana-version = { path = "../version", version = "=1.7.2" }
|
solana-version = { path = "../version", version = "=1.7.2" }
|
||||||
|
|
||||||
|
@@ -4,10 +4,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient};
|
use solana_client::{client_error::Result as ClientResult, rpc_client::RpcClient};
|
||||||
use solana_metrics::{datapoint_error, datapoint_info};
|
use solana_metrics::{datapoint_error, datapoint_info};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::Slot, native_token::LAMPORTS_PER_SOL, program_utils::limited_deserialize,
|
clock::Slot,
|
||||||
pubkey::Pubkey, signature::Signature, transaction::Transaction,
|
native_token::LAMPORTS_PER_SOL,
|
||||||
|
program_utils::limited_deserialize,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
signature::Signature,
|
||||||
|
stake::{self, instruction::StakeInstruction, state::Lockup},
|
||||||
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{stake_instruction::StakeInstruction, stake_state::Lockup};
|
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
EncodedConfirmedBlock, UiTransactionEncoding, UiTransactionStatusMeta,
|
EncodedConfirmedBlock, UiTransactionEncoding, UiTransactionStatusMeta,
|
||||||
};
|
};
|
||||||
@@ -78,7 +82,7 @@ fn process_transaction(
|
|||||||
// Look for stake operations
|
// Look for stake operations
|
||||||
for instruction in message.instructions.iter().rev() {
|
for instruction in message.instructions.iter().rev() {
|
||||||
let program_pubkey = message.account_keys[instruction.program_id_index as usize];
|
let program_pubkey = message.account_keys[instruction.program_id_index as usize];
|
||||||
if program_pubkey != solana_stake_program::id() {
|
if program_pubkey != stake::program::id() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,10 +372,10 @@ mod test {
|
|||||||
message::Message,
|
message::Message,
|
||||||
native_token::sol_to_lamports,
|
native_token::sol_to_lamports,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
|
stake::{instruction as stake_instruction, state::Authorized},
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{stake_instruction, stake_state::Authorized};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
|
@@ -27,7 +27,6 @@ solana-client = { path = "../client", version = "=1.7.2" }
|
|||||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.2" }
|
||||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
solana-transaction-status = { path = "../transaction-status", version = "=1.7.2" }
|
||||||
solana-version = { path = "../version", version = "=1.7.2" }
|
solana-version = { path = "../version", version = "=1.7.2" }
|
||||||
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2" }
|
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2" }
|
||||||
|
@@ -27,13 +27,13 @@ use solana_sdk::{
|
|||||||
message::Message,
|
message::Message,
|
||||||
native_token::{lamports_to_sol, sol_to_lamports},
|
native_token::{lamports_to_sol, sol_to_lamports},
|
||||||
signature::{unique_signers, Signature, Signer},
|
signature::{unique_signers, Signature, Signer},
|
||||||
|
stake::{
|
||||||
|
instruction::{self as stake_instruction, LockupArgs},
|
||||||
|
state::{Authorized, Lockup, StakeAuthorize},
|
||||||
|
},
|
||||||
system_instruction,
|
system_instruction,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::{
|
|
||||||
stake_instruction::{self, LockupArgs},
|
|
||||||
stake_state::{Authorized, Lockup, StakeAuthorize},
|
|
||||||
};
|
|
||||||
use solana_transaction_status::TransactionStatus;
|
use solana_transaction_status::TransactionStatus;
|
||||||
use spl_associated_token_account_v1_0::get_associated_token_address;
|
use spl_associated_token_account_v1_0::get_associated_token_address;
|
||||||
use spl_token_v2_0::solana_program::program_error::ProgramError;
|
use spl_token_v2_0::solana_program::program_error::ProgramError;
|
||||||
@@ -1204,8 +1204,10 @@ pub fn test_process_distribute_stake_with_client(client: &RpcClient, sender_keyp
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_core::test_validator::TestValidator;
|
use solana_core::test_validator::TestValidator;
|
||||||
use solana_sdk::signature::{read_keypair_file, write_keypair_file, Signer};
|
use solana_sdk::{
|
||||||
use solana_stake_program::stake_instruction::StakeInstruction;
|
signature::{read_keypair_file, write_keypair_file, Signer},
|
||||||
|
stake::instruction::StakeInstruction,
|
||||||
|
};
|
||||||
use solana_transaction_status::TransactionConfirmationStatus;
|
use solana_transaction_status::TransactionConfirmationStatus;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@@ -21,7 +21,6 @@ serde_json = "1.0.56"
|
|||||||
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
solana-account-decoder = { path = "../account-decoder", version = "=1.7.2" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
solana-sdk = { path = "../sdk", version = "=1.7.2" }
|
||||||
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
solana-runtime = { path = "../runtime", version = "=1.7.2" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.2" }
|
|
||||||
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
solana-vote-program = { path = "../programs/vote", version = "=1.7.2" }
|
||||||
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2", features = ["no-entrypoint"] }
|
spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", version = "=1.0.2", features = ["no-entrypoint"] }
|
||||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||||
|
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use solana_account_decoder::parse_token::spl_token_id_v2_0;
|
use solana_account_decoder::parse_token::spl_token_id_v2_0;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, system_program};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, stake, system_program};
|
||||||
use std::{collections::HashMap, str::from_utf8};
|
use std::{collections::HashMap, str::from_utf8};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ lazy_static! {
|
|||||||
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
|
||||||
static ref MEMO_V1_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::v1::id().to_bytes());
|
static ref MEMO_V1_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::v1::id().to_bytes());
|
||||||
static ref MEMO_V3_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::id().to_bytes());
|
static ref MEMO_V3_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_memo::id().to_bytes());
|
||||||
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
|
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
|
||||||
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
|
||||||
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
|
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();
|
||||||
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();
|
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();
|
||||||
|
@@ -3,8 +3,9 @@ use crate::parse_instruction::{
|
|||||||
};
|
};
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use serde_json::{json, Map};
|
use serde_json::{json, Map};
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{
|
||||||
use solana_stake_program::stake_instruction::StakeInstruction;
|
instruction::CompiledInstruction, pubkey::Pubkey, stake::instruction::StakeInstruction,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn parse_stake(
|
pub fn parse_stake(
|
||||||
instruction: &CompiledInstruction,
|
instruction: &CompiledInstruction,
|
||||||
@@ -195,10 +196,13 @@ fn check_num_stake_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInst
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_sdk::{message::Message, pubkey::Pubkey};
|
use solana_sdk::{
|
||||||
use solana_stake_program::{
|
message::Message,
|
||||||
stake_instruction::{self, LockupArgs},
|
pubkey::Pubkey,
|
||||||
stake_state::{Authorized, Lockup, StakeAuthorize},
|
stake::{
|
||||||
|
instruction::{self, LockupArgs},
|
||||||
|
state::{Authorized, Lockup, StakeAuthorize},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -221,7 +225,7 @@ mod test {
|
|||||||
let lamports = 55;
|
let lamports = 55;
|
||||||
|
|
||||||
let instructions =
|
let instructions =
|
||||||
stake_instruction::create_account(&keys[0], &keys[1], &authorized, &lockup, lamports);
|
instruction::create_account(&keys[0], &keys[1], &authorized, &lockup, lamports);
|
||||||
let message = Message::new(&instructions, None);
|
let message = Message::new(&instructions, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[1], &keys[0..3]).unwrap(),
|
parse_stake(&message.instructions[1], &keys[0..3]).unwrap(),
|
||||||
@@ -244,13 +248,8 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[1], &keys[0..2]).is_err());
|
assert!(parse_stake(&message.instructions[1], &keys[0..2]).is_err());
|
||||||
|
|
||||||
let instruction = stake_instruction::authorize(
|
let instruction =
|
||||||
&keys[1],
|
instruction::authorize(&keys[1], &keys[0], &keys[3], StakeAuthorize::Staker, None);
|
||||||
&keys[0],
|
|
||||||
&keys[3],
|
|
||||||
StakeAuthorize::Staker,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
|
||||||
@@ -267,7 +266,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
|
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
|
||||||
|
|
||||||
let instruction = stake_instruction::authorize(
|
let instruction = instruction::authorize(
|
||||||
&keys[1],
|
&keys[1],
|
||||||
&keys[0],
|
&keys[0],
|
||||||
&keys[3],
|
&keys[3],
|
||||||
@@ -291,7 +290,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
|
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
|
||||||
|
|
||||||
let instruction = stake_instruction::delegate_stake(&keys[1], &keys[0], &keys[2]);
|
let instruction = instruction::delegate_stake(&keys[1], &keys[0], &keys[2]);
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
|
||||||
@@ -313,7 +312,7 @@ mod test {
|
|||||||
// * split account (signer, allocate + assign first)
|
// * split account (signer, allocate + assign first)
|
||||||
// * stake authority (signer)
|
// * stake authority (signer)
|
||||||
// * stake account
|
// * stake account
|
||||||
let instructions = stake_instruction::split(&keys[2], &keys[1], lamports, &keys[0]);
|
let instructions = instruction::split(&keys[2], &keys[1], lamports, &keys[0]);
|
||||||
let message = Message::new(&instructions, None);
|
let message = Message::new(&instructions, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[2], &keys[0..3]).unwrap(),
|
parse_stake(&message.instructions[2], &keys[0..3]).unwrap(),
|
||||||
@@ -329,7 +328,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[2], &keys[0..2]).is_err());
|
assert!(parse_stake(&message.instructions[2], &keys[0..2]).is_err());
|
||||||
|
|
||||||
let instruction = stake_instruction::withdraw(&keys[1], &keys[0], &keys[2], lamports, None);
|
let instruction = instruction::withdraw(&keys[1], &keys[0], &keys[2], lamports, None);
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
|
||||||
@@ -346,7 +345,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
let instruction =
|
let instruction =
|
||||||
stake_instruction::withdraw(&keys[2], &keys[0], &keys[3], lamports, Some(&keys[1]));
|
instruction::withdraw(&keys[2], &keys[0], &keys[3], lamports, Some(&keys[1]));
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..6]).unwrap(),
|
||||||
@@ -365,7 +364,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
|
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
|
||||||
|
|
||||||
let instruction = stake_instruction::deactivate_stake(&keys[1], &keys[0]);
|
let instruction = instruction::deactivate_stake(&keys[1], &keys[0]);
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..3]).unwrap(),
|
||||||
@@ -380,7 +379,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
|
assert!(parse_stake(&message.instructions[0], &keys[0..2]).is_err());
|
||||||
|
|
||||||
let instructions = stake_instruction::merge(&keys[1], &keys[0], &keys[2]);
|
let instructions = instruction::merge(&keys[1], &keys[0], &keys[2]);
|
||||||
let message = Message::new(&instructions, None);
|
let message = Message::new(&instructions, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..5]).unwrap(),
|
||||||
@@ -398,7 +397,7 @@ mod test {
|
|||||||
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
|
assert!(parse_stake(&message.instructions[0], &keys[0..4]).is_err());
|
||||||
|
|
||||||
let seed = "test_seed";
|
let seed = "test_seed";
|
||||||
let instruction = stake_instruction::authorize_with_seed(
|
let instruction = instruction::authorize_with_seed(
|
||||||
&keys[1],
|
&keys[1],
|
||||||
&keys[0],
|
&keys[0],
|
||||||
seed.to_string(),
|
seed.to_string(),
|
||||||
@@ -425,7 +424,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
assert!(parse_stake(&message.instructions[0], &keys[0..1]).is_err());
|
assert!(parse_stake(&message.instructions[0], &keys[0..1]).is_err());
|
||||||
|
|
||||||
let instruction = stake_instruction::authorize_with_seed(
|
let instruction = instruction::authorize_with_seed(
|
||||||
&keys[1],
|
&keys[1],
|
||||||
&keys[0],
|
&keys[0],
|
||||||
seed.to_string(),
|
seed.to_string(),
|
||||||
@@ -470,7 +469,7 @@ mod test {
|
|||||||
epoch: None,
|
epoch: None,
|
||||||
custodian: None,
|
custodian: None,
|
||||||
};
|
};
|
||||||
let instruction = stake_instruction::set_lockup(&keys[1], &lockup, &keys[0]);
|
let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]);
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
|
||||||
@@ -491,7 +490,7 @@ mod test {
|
|||||||
epoch: Some(epoch),
|
epoch: Some(epoch),
|
||||||
custodian: None,
|
custodian: None,
|
||||||
};
|
};
|
||||||
let instruction = stake_instruction::set_lockup(&keys[1], &lockup, &keys[0]);
|
let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]);
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
|
||||||
@@ -513,7 +512,7 @@ mod test {
|
|||||||
epoch: Some(epoch),
|
epoch: Some(epoch),
|
||||||
custodian: Some(custodian),
|
custodian: Some(custodian),
|
||||||
};
|
};
|
||||||
let instruction = stake_instruction::set_lockup(&keys[1], &lockup, &keys[0]);
|
let instruction = instruction::set_lockup(&keys[1], &lockup, &keys[0]);
|
||||||
let message = Message::new(&[instruction], None);
|
let message = Message::new(&[instruction], None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
|
parse_stake(&message.instructions[0], &keys[0..2]).unwrap(),
|
||||||
|
Reference in New Issue
Block a user