Feature-gate stake-program-v3 (bp #14232) (#14249)

* Feature-gate stake-program-v3 (#14232)

* Remove deprecated legacy stake program

* Add legacy stake program

* Strip out duplicative legacy code

* Feature-deploy stake-program-v3

* Add ownership check in stake processor

(cherry picked from commit 7042f11791)

# Conflicts:
#	programs/stake/src/stake_instruction.rs
#	sdk/src/feature_set.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
This commit is contained in:
mergify[bot]
2020-12-23 00:12:01 +00:00
committed by GitHub
parent 266c63f105
commit 7e4bd087ae
5 changed files with 2512 additions and 338 deletions

File diff suppressed because it is too large Load Diff

View File

@ -457,6 +457,10 @@ pub fn process_instruction(
let keyed_accounts = &mut keyed_accounts.iter(); let keyed_accounts = &mut keyed_accounts.iter();
let me = &next_keyed_account(keyed_accounts)?; let me = &next_keyed_account(keyed_accounts)?;
if me.owner()? != id() {
return Err(InstructionError::IncorrectProgramId);
}
match limited_deserialize(data)? { match limited_deserialize(data)? {
StakeInstruction::Initialize(authorized, lockup) => me.initialize( StakeInstruction::Initialize(authorized, lockup) => me.initialize(
&authorized, &authorized,
@ -538,6 +542,13 @@ mod tests {
RefCell::new(Account::default()) RefCell::new(Account::default())
} }
fn create_default_stake_account() -> RefCell<Account> {
RefCell::new(Account {
owner: id(),
..Account::default()
})
}
fn invalid_stake_state_pubkey() -> Pubkey { fn invalid_stake_state_pubkey() -> Pubkey {
Pubkey::from_str("BadStake11111111111111111111111111111111111").unwrap() Pubkey::from_str("BadStake11111111111111111111111111111111111").unwrap()
} }
@ -546,6 +557,14 @@ mod tests {
Pubkey::from_str("BadVote111111111111111111111111111111111111").unwrap() Pubkey::from_str("BadVote111111111111111111111111111111111111").unwrap()
} }
fn spoofed_stake_state_pubkey() -> Pubkey {
Pubkey::from_str("SpoofedStake1111111111111111111111111111111").unwrap()
}
fn spoofed_stake_program_id() -> Pubkey {
Pubkey::from_str("Spoofed111111111111111111111111111111111111").unwrap()
}
fn process_instruction(instruction: &Instruction) -> Result<(), InstructionError> { fn process_instruction(instruction: &Instruction) -> Result<(), InstructionError> {
let accounts: Vec<_> = instruction let accounts: Vec<_> = instruction
.accounts .accounts
@ -569,8 +588,15 @@ mod tests {
let mut account = Account::default(); let mut account = Account::default();
account.owner = solana_vote_program::id(); account.owner = solana_vote_program::id();
account account
} else if meta.pubkey == spoofed_stake_state_pubkey() {
let mut account = Account::default();
account.owner = spoofed_stake_program_id();
account
} else { } else {
Account::default() Account {
owner: id(),
..Account::default()
}
}) })
}) })
.collect(); .collect();
@ -676,6 +702,115 @@ mod tests {
); );
} }
#[test]
fn test_spoofed_stake_accounts() {
assert_eq!(
process_instruction(&initialize(
&spoofed_stake_state_pubkey(),
&Authorized::default(),
&Lockup::default()
)),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(&authorize(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&Pubkey::default(),
StakeAuthorize::Staker
)),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(
&split(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
100,
&Pubkey::default(),
)[1]
),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(
&split(
&Pubkey::default(),
&Pubkey::default(),
100,
&spoofed_stake_state_pubkey(),
)[1]
),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(
&merge(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&Pubkey::default(),
)[0]
),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(
&merge(
&Pubkey::default(),
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
)[0]
),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(
&split_with_seed(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
100,
&Pubkey::default(),
&Pubkey::default(),
"seed"
)[1]
),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(&delegate_stake(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&Pubkey::default(),
)),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(&withdraw(
&spoofed_stake_state_pubkey(),
&Pubkey::default(),
&solana_sdk::pubkey::new_rand(),
100,
None,
)),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(&deactivate_stake(
&spoofed_stake_state_pubkey(),
&Pubkey::default()
)),
Err(InstructionError::IncorrectProgramId),
);
assert_eq!(
process_instruction(&set_lockup(
&spoofed_stake_state_pubkey(),
&LockupArgs::default(),
&Pubkey::default()
)),
Err(InstructionError::IncorrectProgramId),
);
}
#[test] #[test]
fn test_stake_process_instruction_decode_bail() { fn test_stake_process_instruction_decode_bail() {
// these will not call stake_state, have bogus contents // these will not call stake_state, have bogus contents
@ -702,7 +837,7 @@ mod tests {
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
false, false,
&create_default_account(), &create_default_stake_account(),
)], )],
&serialize(&StakeInstruction::Initialize( &serialize(&StakeInstruction::Initialize(
Authorized::default(), Authorized::default(),
@ -719,8 +854,8 @@ mod tests {
super::process_instruction( super::process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), false, &create_default_account(),), KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_account(),) KeyedAccount::new(&sysvar::rent::id(), false, &create_default_account())
], ],
&serialize(&StakeInstruction::Initialize( &serialize(&StakeInstruction::Initialize(
Authorized::default(), Authorized::default(),
@ -737,7 +872,7 @@ mod tests {
super::process_instruction( super::process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()), KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new( KeyedAccount::new(
&sysvar::rent::id(), &sysvar::rent::id(),
false, false,
@ -761,7 +896,7 @@ mod tests {
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
false, false,
&create_default_account() &create_default_stake_account()
),], ),],
&serialize(&StakeInstruction::DelegateStake).unwrap(), &serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default() &mut MockInvokeContext::default()
@ -776,7 +911,7 @@ mod tests {
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
false, false,
&create_default_account() &create_default_stake_account()
)], )],
&serialize(&StakeInstruction::DelegateStake).unwrap(), &serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default() &mut MockInvokeContext::default()
@ -791,7 +926,7 @@ mod tests {
super::process_instruction( super::process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()), KeyedAccount::new(&Pubkey::default(), true, &create_default_stake_account()),
KeyedAccount::new(&Pubkey::default(), false, &bad_vote_account), KeyedAccount::new(&Pubkey::default(), false, &bad_vote_account),
KeyedAccount::new( KeyedAccount::new(
&sysvar::clock::id(), &sysvar::clock::id(),
@ -823,7 +958,7 @@ mod tests {
super::process_instruction( super::process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()), KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()), KeyedAccount::new(&Pubkey::default(), false, &create_default_account()),
KeyedAccount::new( KeyedAccount::new(
&sysvar::rewards::id(), &sysvar::rewards::id(),
@ -852,7 +987,7 @@ mod tests {
&[KeyedAccount::new( &[KeyedAccount::new(
&Pubkey::default(), &Pubkey::default(),
false, false,
&create_default_account() &create_default_stake_account()
)], )],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(), &serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default() &mut MockInvokeContext::default()
@ -865,7 +1000,7 @@ mod tests {
super::process_instruction( super::process_instruction(
&Pubkey::default(), &Pubkey::default(),
&[ &[
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()), KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new( KeyedAccount::new(
&sysvar::rewards::id(), &sysvar::rewards::id(),
false, false,

View File

@ -42,7 +42,7 @@ pub enum InflationPointCalculationEvent {
CreditsObserved(u64, u64), CreditsObserved(u64, u64),
} }
fn null_tracer() -> Option<impl FnMut(&InflationPointCalculationEvent)> { pub(crate) fn null_tracer() -> Option<impl FnMut(&InflationPointCalculationEvent)> {
None::<fn(&_)> None::<fn(&_)>
} }
@ -415,7 +415,7 @@ impl Delegation {
} }
} }
fn rewrite_stake( pub(crate) fn rewrite_stake(
&mut self, &mut self,
account_balance: u64, account_balance: u64,
rent_exempt_balance: u64, rent_exempt_balance: u64,

View File

@ -104,11 +104,11 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey, ActivationType)> {
), ),
( (
Builtin::new( Builtin::new(
"stake_program_v2", "stake_program_v3",
solana_stake_program::id(), solana_stake_program::id(),
solana_stake_program::stake_instruction::process_instruction, solana_stake_program::stake_instruction::process_instruction,
), ),
feature_set::stake_program_v2::id(), feature_set::stake_program_v3::id(),
ActivationType::NewVersion, ActivationType::NewVersion,
), ),
] ]

View File

@ -102,6 +102,10 @@ pub mod simple_capitalization {
solana_sdk::declare_id!("9r69RnnxABmpcPFfj1yhg4n9YFR2MNaLdKJCC6v3Speb"); solana_sdk::declare_id!("9r69RnnxABmpcPFfj1yhg4n9YFR2MNaLdKJCC6v3Speb");
} }
pub mod stake_program_v3 {
solana_sdk::declare_id!("Ego6nTu7WsBcZBvVqJQKp6Yku2N3mrfG8oYCfaLZkAeK");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -129,6 +133,7 @@ lazy_static! {
(rewrite_stake::id(), "rewrite stake"), (rewrite_stake::id(), "rewrite stake"),
(filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"), (filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"),
(simple_capitalization::id(), "simple capitalization"), (simple_capitalization::id(), "simple capitalization"),
(stake_program_v3::id(), "solana_stake_program v3"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()