* 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:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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, | ||||||
|   | |||||||
| @@ -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, | ||||||
|   | |||||||
| @@ -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, | ||||||
|         ), |         ), | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -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() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user