Add error reporting to system program (#15644)

This commit is contained in:
Jack May 2021-03-02 21:44:25 -08:00 committed by GitHub
parent a4f0033bd7
commit a9c8dbfd0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 467 additions and 94 deletions

View File

@ -2,6 +2,7 @@ use log::*;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
account_utils::StateMut, account_utils::StateMut,
ic_msg,
instruction::InstructionError, instruction::InstructionError,
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
nonce, nonce,
@ -34,10 +35,18 @@ impl Address {
fn create( fn create(
address: &Pubkey, address: &Pubkey,
with_seed: Option<(&Pubkey, &str, &Pubkey)>, with_seed: Option<(&Pubkey, &str, &Pubkey)>,
invoke_context: &mut dyn InvokeContext,
) -> Result<Self, InstructionError> { ) -> Result<Self, InstructionError> {
let base = if let Some((base, seed, owner)) = with_seed { let base = if let Some((base, seed, owner)) = with_seed {
let address_with_seed = Pubkey::create_with_seed(base, seed, owner)?;
// re-derive the address, must match the supplied address // re-derive the address, must match the supplied address
if *address != Pubkey::create_with_seed(base, seed, owner)? { if *address != address_with_seed {
ic_msg!(
invoke_context,
"Create: address {} does not match derived address {}",
address,
address_with_seed
);
return Err(SystemError::AddressWithSeedMismatch.into()); return Err(SystemError::AddressWithSeedMismatch.into());
} }
Some(*base) Some(*base)
@ -57,26 +66,34 @@ fn allocate(
address: &Address, address: &Address,
space: u64, space: u64,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if !address.is_signer(signers) { if !address.is_signer(signers) {
debug!("Allocate: must carry signature of `to`"); ic_msg!(
invoke_context,
"Allocate: 'to' account {:?} must sign",
address
);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
// if it looks like the `to` account is already in use, bail // if it looks like the `to` account is already in use, bail
// (note that the id check is also enforced by message_processor) // (note that the id check is also enforced by message_processor)
if !account.data.is_empty() || !system_program::check_id(&account.owner) { if !account.data.is_empty() || !system_program::check_id(&account.owner) {
debug!( ic_msg!(
"Allocate: invalid argument; account {:?} already in use", invoke_context,
"Allocate: account {:?} already in use",
address address
); );
return Err(SystemError::AccountAlreadyInUse.into()); return Err(SystemError::AccountAlreadyInUse.into());
} }
if space > MAX_PERMITTED_DATA_LENGTH { if space > MAX_PERMITTED_DATA_LENGTH {
debug!( ic_msg!(
"Allocate: requested space: {} is more than maximum allowed", invoke_context,
space "Allocate: requested {}, max allowed {}",
space,
MAX_PERMITTED_DATA_LENGTH
); );
return Err(SystemError::InvalidAccountDataLength.into()); return Err(SystemError::InvalidAccountDataLength.into());
} }
@ -91,6 +108,7 @@ fn assign(
address: &Address, address: &Address,
owner: &Pubkey, owner: &Pubkey,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// no work to do, just return // no work to do, just return
if account.owner == *owner { if account.owner == *owner {
@ -98,13 +116,13 @@ fn assign(
} }
if !address.is_signer(&signers) { if !address.is_signer(&signers) {
debug!("Assign: account must sign"); ic_msg!(invoke_context, "Assign: account {:?} must sign", address);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
// guard against sysvars being made // guard against sysvars being made
if sysvar::check_id(&owner) { if sysvar::check_id(&owner) {
debug!("Assign: program id {} invalid", owner); ic_msg!(invoke_context, "Assign: cannot assign to sysvar, {}", owner);
return Err(SystemError::InvalidProgramId.into()); return Err(SystemError::InvalidProgramId.into());
} }
@ -118,9 +136,10 @@ fn allocate_and_assign(
space: u64, space: u64,
owner: &Pubkey, owner: &Pubkey,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
allocate(to, to_address, space, signers)?; allocate(to, to_address, space, signers, invoke_context)?;
assign(to, to_address, owner, signers) assign(to, to_address, owner, signers, invoke_context)
} }
fn create_account( fn create_account(
@ -131,35 +150,39 @@ fn create_account(
space: u64, space: u64,
owner: &Pubkey, owner: &Pubkey,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// if it looks like the `to` account is already in use, bail // if it looks like the `to` account is already in use, bail
{ {
let to = &mut to.try_account_ref_mut()?; let to = &mut to.try_account_ref_mut()?;
if to.lamports > 0 { if to.lamports > 0 {
debug!( ic_msg!(
"Create Account: invalid argument; account {:?} already in use", invoke_context,
"Create Account: account {:?} already in use",
to_address to_address
); );
return Err(SystemError::AccountAlreadyInUse.into()); return Err(SystemError::AccountAlreadyInUse.into());
} }
allocate_and_assign(to, to_address, space, owner, signers)?; allocate_and_assign(to, to_address, space, owner, signers, invoke_context)?;
} }
transfer(from, to, lamports) transfer(from, to, lamports, invoke_context)
} }
fn transfer_verified( fn transfer_verified(
from: &KeyedAccount, from: &KeyedAccount,
to: &KeyedAccount, to: &KeyedAccount,
lamports: u64, lamports: u64,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if !from.data_is_empty()? { if !from.data_is_empty()? {
debug!("Transfer: `from` must not carry data"); ic_msg!(invoke_context, "Transfer: `from` must not carry data");
return Err(InstructionError::InvalidArgument); return Err(InstructionError::InvalidArgument);
} }
if lamports > from.lamports()? { if lamports > from.lamports()? {
debug!( ic_msg!(
"Transfer: insufficient lamports ({}, need {})", invoke_context,
"Transfer: insufficient lamports {}, need {}",
from.lamports()?, from.lamports()?,
lamports lamports
); );
@ -171,17 +194,26 @@ fn transfer_verified(
Ok(()) Ok(())
} }
fn transfer(from: &KeyedAccount, to: &KeyedAccount, lamports: u64) -> Result<(), InstructionError> { fn transfer(
from: &KeyedAccount,
to: &KeyedAccount,
lamports: u64,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
if lamports == 0 { if lamports == 0 {
return Ok(()); return Ok(());
} }
if from.signer_key().is_none() { if from.signer_key().is_none() {
debug!("Transfer: from must sign"); ic_msg!(
invoke_context,
"Transfer: `from` accont {} must sign",
from.unsigned_key()
);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
transfer_verified(from, to, lamports) transfer_verified(from, to, lamports, invoke_context)
} }
fn transfer_with_seed( fn transfer_with_seed(
@ -191,30 +223,41 @@ fn transfer_with_seed(
from_owner: &Pubkey, from_owner: &Pubkey,
to: &KeyedAccount, to: &KeyedAccount,
lamports: u64, lamports: u64,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if lamports == 0 { if lamports == 0 {
return Ok(()); return Ok(());
} }
if from_base.signer_key().is_none() { if from_base.signer_key().is_none() {
debug!("Transfer: from must sign"); ic_msg!(
invoke_context,
"Transfer: 'from' account {:?} must sign",
from_base
);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
if *from.unsigned_key() let address_from_seed =
!= Pubkey::create_with_seed(from_base.unsigned_key(), from_seed, from_owner)? Pubkey::create_with_seed(from_base.unsigned_key(), from_seed, from_owner)?;
{ if *from.unsigned_key() != address_from_seed {
ic_msg!(
invoke_context,
"Transfer: 'from' address {} does not match derived address {}",
from.unsigned_key(),
address_from_seed
);
return Err(SystemError::AddressWithSeedMismatch.into()); return Err(SystemError::AddressWithSeedMismatch.into());
} }
transfer_verified(from, to, lamports) transfer_verified(from, to, lamports, invoke_context)
} }
pub fn process_instruction( pub fn process_instruction(
_owner: &Pubkey, _owner: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
instruction_data: &[u8], instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let instruction = limited_deserialize(instruction_data)?; let instruction = limited_deserialize(instruction_data)?;
@ -232,8 +275,17 @@ pub fn process_instruction(
} => { } => {
let from = next_keyed_account(keyed_accounts_iter)?; let from = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?; let to = next_keyed_account(keyed_accounts_iter)?;
let to_address = Address::create(to.unsigned_key(), None)?; let to_address = Address::create(to.unsigned_key(), None, invoke_context)?;
create_account(from, to, &to_address, lamports, space, &owner, &signers) create_account(
from,
to,
&to_address,
lamports,
space,
&owner,
&signers,
invoke_context,
)
} }
SystemInstruction::CreateAccountWithSeed { SystemInstruction::CreateAccountWithSeed {
base, base,
@ -244,19 +296,32 @@ pub fn process_instruction(
} => { } => {
let from = next_keyed_account(keyed_accounts_iter)?; let from = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?; let to = next_keyed_account(keyed_accounts_iter)?;
let to_address = Address::create(&to.unsigned_key(), Some((&base, &seed, &owner)))?; let to_address = Address::create(
create_account(from, &to, &to_address, lamports, space, &owner, &signers) &to.unsigned_key(),
Some((&base, &seed, &owner)),
invoke_context,
)?;
create_account(
from,
&to,
&to_address,
lamports,
space,
&owner,
&signers,
invoke_context,
)
} }
SystemInstruction::Assign { owner } => { SystemInstruction::Assign { owner } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?; let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut account = keyed_account.try_account_ref_mut()?; let mut account = keyed_account.try_account_ref_mut()?;
let address = Address::create(keyed_account.unsigned_key(), None)?; let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?;
assign(&mut account, &address, &owner, &signers) assign(&mut account, &address, &owner, &signers, invoke_context)
} }
SystemInstruction::Transfer { lamports } => { SystemInstruction::Transfer { lamports } => {
let from = next_keyed_account(keyed_accounts_iter)?; let from = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?; let to = next_keyed_account(keyed_accounts_iter)?;
transfer(from, to, lamports) transfer(from, to, lamports, invoke_context)
} }
SystemInstruction::TransferWithSeed { SystemInstruction::TransferWithSeed {
lamports, lamports,
@ -266,13 +331,22 @@ pub fn process_instruction(
let from = next_keyed_account(keyed_accounts_iter)?; let from = next_keyed_account(keyed_accounts_iter)?;
let base = next_keyed_account(keyed_accounts_iter)?; let base = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?; let to = next_keyed_account(keyed_accounts_iter)?;
transfer_with_seed(from, base, &from_seed, &from_owner, to, lamports) transfer_with_seed(
from,
base,
&from_seed,
&from_owner,
to,
lamports,
invoke_context,
)
} }
SystemInstruction::AdvanceNonceAccount => { SystemInstruction::AdvanceNonceAccount => {
let me = &mut next_keyed_account(keyed_accounts_iter)?; let me = &mut next_keyed_account(keyed_accounts_iter)?;
me.advance_nonce_account( me.advance_nonce_account(
&from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?,
&signers, &signers,
invoke_context,
) )
} }
SystemInstruction::WithdrawNonceAccount(lamports) => { SystemInstruction::WithdrawNonceAccount(lamports) => {
@ -284,6 +358,7 @@ pub fn process_instruction(
&from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<Rent>(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::<Rent>(next_keyed_account(keyed_accounts_iter)?)?,
&signers, &signers,
invoke_context,
) )
} }
SystemInstruction::InitializeNonceAccount(authorized) => { SystemInstruction::InitializeNonceAccount(authorized) => {
@ -292,17 +367,18 @@ pub fn process_instruction(
&authorized, &authorized,
&from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<Rent>(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::<Rent>(next_keyed_account(keyed_accounts_iter)?)?,
invoke_context,
) )
} }
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
let me = &mut next_keyed_account(keyed_accounts_iter)?; let me = &mut next_keyed_account(keyed_accounts_iter)?;
me.authorize_nonce_account(&nonce_authority, &signers) me.authorize_nonce_account(&nonce_authority, &signers, invoke_context)
} }
SystemInstruction::Allocate { space } => { SystemInstruction::Allocate { space } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?; let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut account = keyed_account.try_account_ref_mut()?; let mut account = keyed_account.try_account_ref_mut()?;
let address = Address::create(keyed_account.unsigned_key(), None)?; let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?;
allocate(&mut account, &address, space, &signers) allocate(&mut account, &address, space, &signers, invoke_context)
} }
SystemInstruction::AllocateWithSeed { SystemInstruction::AllocateWithSeed {
base, base,
@ -312,17 +388,29 @@ pub fn process_instruction(
} => { } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?; let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut account = keyed_account.try_account_ref_mut()?; let mut account = keyed_account.try_account_ref_mut()?;
let address = let address = Address::create(
Address::create(keyed_account.unsigned_key(), Some((&base, &seed, &owner)))?; keyed_account.unsigned_key(),
allocate_and_assign(&mut account, &address, space, &owner, &signers) Some((&base, &seed, &owner)),
invoke_context,
)?;
allocate_and_assign(
&mut account,
&address,
space,
&owner,
&signers,
invoke_context,
)
} }
SystemInstruction::AssignWithSeed { base, seed, owner } => { SystemInstruction::AssignWithSeed { base, seed, owner } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?; let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let mut account = keyed_account.try_account_ref_mut()?; let mut account = keyed_account.try_account_ref_mut()?;
let address = let address = Address::create(
Address::create(keyed_account.unsigned_key(), Some((&base, &seed, &owner)))?; keyed_account.unsigned_key(),
Some((&base, &seed, &owner)),
assign(&mut account, &address, &owner, &signers) invoke_context,
)?;
assign(&mut account, &address, &owner, &signers, invoke_context)
} }
} }
} }
@ -524,7 +612,11 @@ mod tests {
let owner = solana_sdk::pubkey::new_rand(); let owner = solana_sdk::pubkey::new_rand();
assert_eq!( assert_eq!(
Address::create(&to, Some((&from, seed, &owner))), Address::create(
&to,
Some((&from, seed, &owner)),
&mut MockInvokeContext::default(),
),
Err(SystemError::AddressWithSeedMismatch.into()) Err(SystemError::AddressWithSeedMismatch.into())
); );
} }
@ -538,7 +630,12 @@ mod tests {
let from_account = Account::new_ref(100, 0, &system_program::id()); let from_account = Account::new_ref(100, 0, &system_program::id());
let to_account = Account::new_ref(0, 0, &Pubkey::default()); let to_account = Account::new_ref(0, 0, &Pubkey::default());
let to_address = Address::create(&to, Some((&from, seed, &new_owner))).unwrap(); let to_address = Address::create(
&to,
Some((&from, seed, &new_owner)),
&mut MockInvokeContext::default(),
)
.unwrap();
assert_eq!( assert_eq!(
create_account( create_account(
@ -549,6 +646,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&HashSet::new(), &HashSet::new(),
&mut MockInvokeContext::default(),
), ),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
@ -575,6 +673,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&[to].iter().cloned().collect::<HashSet<_>>(), &[to].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
), ),
Ok(()) Ok(())
); );
@ -607,6 +706,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&[from, to].iter().cloned().collect::<HashSet<_>>(), &[from, to].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into())); assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
} }
@ -630,6 +730,7 @@ mod tests {
MAX_PERMITTED_DATA_LENGTH + 1, MAX_PERMITTED_DATA_LENGTH + 1,
&system_program::id(), &system_program::id(),
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
@ -646,6 +747,7 @@ mod tests {
MAX_PERMITTED_DATA_LENGTH, MAX_PERMITTED_DATA_LENGTH,
&system_program::id(), &system_program::id(),
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert!(result.is_ok()); assert!(result.is_ok());
assert_eq!(to_account.borrow().lamports, 50); assert_eq!(to_account.borrow().lamports, 50);
@ -678,6 +780,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
@ -696,6 +799,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
let from_lamports = from_account.borrow().lamports; let from_lamports = from_account.borrow().lamports;
@ -713,6 +817,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
assert_eq!(from_lamports, 100); assert_eq!(from_lamports, 100);
@ -740,6 +845,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&[owned_key].iter().cloned().collect::<HashSet<_>>(), &[owned_key].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
@ -753,6 +859,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&[from].iter().cloned().collect::<HashSet<_>>(), &[from].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
@ -766,6 +873,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&[owned_key].iter().cloned().collect::<HashSet<_>>(), &[owned_key].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
} }
@ -791,6 +899,7 @@ mod tests {
2, 2,
&sysvar::id(), &sysvar::id(),
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::InvalidProgramId.into())); assert_eq!(result, Err(SystemError::InvalidProgramId.into()));
@ -824,6 +933,7 @@ mod tests {
2, 2,
&new_owner, &new_owner,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
} }
@ -856,7 +966,8 @@ mod tests {
42, 42,
0, 0,
&solana_sdk::pubkey::new_rand(), &solana_sdk::pubkey::new_rand(),
&signers &signers,
&mut MockInvokeContext::default(),
), ),
Err(InstructionError::InvalidArgument), Err(InstructionError::InvalidArgument),
); );
@ -870,7 +981,13 @@ mod tests {
let mut account = Account::new(100, 0, &system_program::id()); let mut account = Account::new(100, 0, &system_program::id());
assert_eq!( assert_eq!(
assign(&mut account, &pubkey.into(), &new_owner, &HashSet::new()), assign(
&mut account,
&pubkey.into(),
&new_owner,
&HashSet::new(),
&mut MockInvokeContext::default(),
),
Err(InstructionError::MissingRequiredSignature) Err(InstructionError::MissingRequiredSignature)
); );
// no change, no signature needed // no change, no signature needed
@ -879,7 +996,8 @@ mod tests {
&mut account, &mut account,
&pubkey.into(), &pubkey.into(),
&system_program::id(), &system_program::id(),
&HashSet::new() &HashSet::new(),
&mut MockInvokeContext::default(),
), ),
Ok(()) Ok(())
); );
@ -908,6 +1026,7 @@ mod tests {
&from.into(), &from.into(),
&new_owner, &new_owner,
&[from].iter().cloned().collect::<HashSet<_>>(), &[from].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
), ),
Err(SystemError::InvalidProgramId.into()) Err(SystemError::InvalidProgramId.into())
); );
@ -944,7 +1063,13 @@ mod tests {
let to_account = Account::new_ref(1, 0, &to); // account owner should not matter let to_account = Account::new_ref(1, 0, &to); // account owner should not matter
let from_keyed_account = KeyedAccount::new(&from, true, &from_account); let from_keyed_account = KeyedAccount::new(&from, true, &from_account);
let to_keyed_account = KeyedAccount::new(&to, false, &to_account); let to_keyed_account = KeyedAccount::new(&to, false, &to_account);
transfer(&from_keyed_account, &to_keyed_account, 50).unwrap(); transfer(
&from_keyed_account,
&to_keyed_account,
50,
&mut MockInvokeContext::default(),
)
.unwrap();
let from_lamports = from_keyed_account.account.borrow().lamports; let from_lamports = from_keyed_account.account.borrow().lamports;
let to_lamports = to_keyed_account.account.borrow().lamports; let to_lamports = to_keyed_account.account.borrow().lamports;
assert_eq!(from_lamports, 50); assert_eq!(from_lamports, 50);
@ -952,14 +1077,26 @@ mod tests {
// Attempt to move more lamports than remaining in from_account // Attempt to move more lamports than remaining in from_account
let from_keyed_account = KeyedAccount::new(&from, true, &from_account); let from_keyed_account = KeyedAccount::new(&from, true, &from_account);
let result = transfer(&from_keyed_account, &to_keyed_account, 100); let result = transfer(
&from_keyed_account,
&to_keyed_account,
100,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into())); assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
assert_eq!(from_keyed_account.account.borrow().lamports, 50); assert_eq!(from_keyed_account.account.borrow().lamports, 50);
assert_eq!(to_keyed_account.account.borrow().lamports, 51); assert_eq!(to_keyed_account.account.borrow().lamports, 51);
// test unsigned transfer of zero // test unsigned transfer of zero
let from_keyed_account = KeyedAccount::new(&from, false, &from_account); let from_keyed_account = KeyedAccount::new(&from, false, &from_account);
assert!(transfer(&from_keyed_account, &to_keyed_account, 0,).is_ok(),);
assert!(transfer(
&from_keyed_account,
&to_keyed_account,
0,
&mut MockInvokeContext::default(),
)
.is_ok(),);
assert_eq!(from_keyed_account.account.borrow().lamports, 50); assert_eq!(from_keyed_account.account.borrow().lamports, 50);
assert_eq!(to_keyed_account.account.borrow().lamports, 51); assert_eq!(to_keyed_account.account.borrow().lamports, 51);
} }
@ -984,6 +1121,7 @@ mod tests {
&from_owner, &from_owner,
&to_keyed_account, &to_keyed_account,
50, 50,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
let from_lamports = from_keyed_account.account.borrow().lamports; let from_lamports = from_keyed_account.account.borrow().lamports;
@ -1000,6 +1138,7 @@ mod tests {
&from_owner, &from_owner,
&to_keyed_account, &to_keyed_account,
100, 100,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into())); assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
assert_eq!(from_keyed_account.account.borrow().lamports, 50); assert_eq!(from_keyed_account.account.borrow().lamports, 50);
@ -1014,6 +1153,7 @@ mod tests {
&from_owner, &from_owner,
&to_keyed_account, &to_keyed_account,
0, 0,
&mut MockInvokeContext::default(),
) )
.is_ok(),); .is_ok(),);
assert_eq!(from_keyed_account.account.borrow().lamports, 50); assert_eq!(from_keyed_account.account.borrow().lamports, 50);
@ -1044,6 +1184,7 @@ mod tests {
&KeyedAccount::new(&from, true, &from_account), &KeyedAccount::new(&from, true, &from_account),
&KeyedAccount::new(&to, false, &to_account), &KeyedAccount::new(&to, false, &to_account),
50, 50,
&mut MockInvokeContext::default(),
), ),
Err(InstructionError::InvalidArgument), Err(InstructionError::InvalidArgument),
) )

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
account_utils::State as AccountUtilsState, keyed_account::KeyedAccount, account_utils::State as AccountUtilsState, ic_msg, keyed_account::KeyedAccount,
nonce_account::create_account, nonce_account::create_account, process_instruction::InvokeContext,
}; };
use solana_program::{ use solana_program::{
instruction::{checked_add, InstructionError}, instruction::{checked_add, InstructionError},
@ -16,6 +16,7 @@ pub trait NonceKeyedAccount {
&self, &self,
recent_blockhashes: &RecentBlockhashes, recent_blockhashes: &RecentBlockhashes,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
fn withdraw_nonce_account( fn withdraw_nonce_account(
&self, &self,
@ -24,17 +25,20 @@ pub trait NonceKeyedAccount {
recent_blockhashes: &RecentBlockhashes, recent_blockhashes: &RecentBlockhashes,
rent: &Rent, rent: &Rent,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
fn initialize_nonce_account( fn initialize_nonce_account(
&self, &self,
nonce_authority: &Pubkey, nonce_authority: &Pubkey,
recent_blockhashes: &RecentBlockhashes, recent_blockhashes: &RecentBlockhashes,
rent: &Rent, rent: &Rent,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
fn authorize_nonce_account( fn authorize_nonce_account(
&self, &self,
nonce_authority: &Pubkey, nonce_authority: &Pubkey,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
} }
@ -43,8 +47,13 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
&self, &self,
recent_blockhashes: &RecentBlockhashes, recent_blockhashes: &RecentBlockhashes,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if recent_blockhashes.is_empty() { if recent_blockhashes.is_empty() {
ic_msg!(
invoke_context,
"Advance nonce account: recent blockhash list is empty",
);
return Err(NonceError::NoRecentBlockhashes.into()); return Err(NonceError::NoRecentBlockhashes.into());
} }
@ -52,10 +61,19 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
match state { match state {
State::Initialized(data) => { State::Initialized(data) => {
if !signers.contains(&data.authority) { if !signers.contains(&data.authority) {
ic_msg!(
invoke_context,
"Advance nonce account: Account {} must be a signer",
data.authority
);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
let recent_blockhash = recent_blockhashes[0].blockhash; let recent_blockhash = recent_blockhashes[0].blockhash;
if data.blockhash == recent_blockhash { if data.blockhash == recent_blockhash {
ic_msg!(
invoke_context,
"Advance nonce account: nonce can only advance once per slot"
);
return Err(NonceError::NotExpired.into()); return Err(NonceError::NotExpired.into());
} }
@ -66,7 +84,14 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
}; };
self.set_state(&Versions::new_current(State::Initialized(new_data))) self.set_state(&Versions::new_current(State::Initialized(new_data)))
} }
_ => Err(NonceError::BadAccountState.into()), _ => {
ic_msg!(
invoke_context,
"Advance nonce account: Account {} state is invalid",
self.unsigned_key()
);
Err(NonceError::BadAccountState.into())
}
} }
} }
@ -77,10 +102,17 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
recent_blockhashes: &RecentBlockhashes, recent_blockhashes: &RecentBlockhashes,
rent: &Rent, rent: &Rent,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let signer = match AccountUtilsState::<Versions>::state(self)?.convert_to_current() { let signer = match AccountUtilsState::<Versions>::state(self)?.convert_to_current() {
State::Uninitialized => { State::Uninitialized => {
if lamports > self.lamports()? { if lamports > self.lamports()? {
ic_msg!(
invoke_context,
"Withdraw nonce account: insufficient lamports {}, need {}",
self.lamports()?,
lamports,
);
return Err(InstructionError::InsufficientFunds); return Err(InstructionError::InsufficientFunds);
} }
*self.unsigned_key() *self.unsigned_key()
@ -88,12 +120,23 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
State::Initialized(ref data) => { State::Initialized(ref data) => {
if lamports == self.lamports()? { if lamports == self.lamports()? {
if data.blockhash == recent_blockhashes[0].blockhash { if data.blockhash == recent_blockhashes[0].blockhash {
ic_msg!(
invoke_context,
"Withdraw nonce account: nonce can only advance once per slot"
);
return Err(NonceError::NotExpired.into()); return Err(NonceError::NotExpired.into());
} }
self.set_state(&Versions::new_current(State::Uninitialized))?; self.set_state(&Versions::new_current(State::Uninitialized))?;
} else { } else {
let min_balance = rent.minimum_balance(self.data_len()?); let min_balance = rent.minimum_balance(self.data_len()?);
if checked_add(lamports, min_balance)? > self.lamports()? { let amount = checked_add(lamports, min_balance)?;
if amount > self.lamports()? {
ic_msg!(
invoke_context,
"Withdraw nonce account: insufficient lamports {}, need {}",
self.lamports()?,
amount,
);
return Err(InstructionError::InsufficientFunds); return Err(InstructionError::InsufficientFunds);
} }
} }
@ -102,6 +145,11 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
}; };
if !signers.contains(&signer) { if !signers.contains(&signer) {
ic_msg!(
invoke_context,
"Withdraw nonce account: Account {} must sign",
signer
);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
@ -116,8 +164,13 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
nonce_authority: &Pubkey, nonce_authority: &Pubkey,
recent_blockhashes: &RecentBlockhashes, recent_blockhashes: &RecentBlockhashes,
rent: &Rent, rent: &Rent,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if recent_blockhashes.is_empty() { if recent_blockhashes.is_empty() {
ic_msg!(
invoke_context,
"Initialize nonce account: recent blockhash list is empty",
);
return Err(NonceError::NoRecentBlockhashes.into()); return Err(NonceError::NoRecentBlockhashes.into());
} }
@ -125,6 +178,12 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
State::Uninitialized => { State::Uninitialized => {
let min_balance = rent.minimum_balance(self.data_len()?); let min_balance = rent.minimum_balance(self.data_len()?);
if self.lamports()? < min_balance { if self.lamports()? < min_balance {
ic_msg!(
invoke_context,
"Initialize nonce account: insufficient lamports {}, need {}",
self.lamports()?,
min_balance
);
return Err(InstructionError::InsufficientFunds); return Err(InstructionError::InsufficientFunds);
} }
let data = nonce::state::Data { let data = nonce::state::Data {
@ -134,7 +193,14 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
}; };
self.set_state(&Versions::new_current(State::Initialized(data))) self.set_state(&Versions::new_current(State::Initialized(data)))
} }
_ => Err(NonceError::BadAccountState.into()), _ => {
ic_msg!(
invoke_context,
"Initialize nonce account: Account {} state is invalid",
self.unsigned_key()
);
Err(NonceError::BadAccountState.into())
}
} }
} }
@ -142,10 +208,16 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
&self, &self,
nonce_authority: &Pubkey, nonce_authority: &Pubkey,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
match AccountUtilsState::<Versions>::state(self)?.convert_to_current() { match AccountUtilsState::<Versions>::state(self)?.convert_to_current() {
State::Initialized(data) => { State::Initialized(data) => {
if !signers.contains(&data.authority) { if !signers.contains(&data.authority) {
ic_msg!(
invoke_context,
"Authorize nonce account: Account {} must sign",
data.authority
);
return Err(InstructionError::MissingRequiredSignature); return Err(InstructionError::MissingRequiredSignature);
} }
let new_data = nonce::state::Data { let new_data = nonce::state::Data {
@ -154,7 +226,14 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
}; };
self.set_state(&Versions::new_current(State::Initialized(new_data))) self.set_state(&Versions::new_current(State::Initialized(new_data)))
} }
_ => Err(NonceError::BadAccountState.into()), _ => {
ic_msg!(
invoke_context,
"Authorize nonce account: Account {} state is invalid",
self.unsigned_key()
);
Err(NonceError::BadAccountState.into())
}
} }
} }
} }
@ -178,6 +257,7 @@ mod test {
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
nonce::{self, State}, nonce::{self, State},
nonce_account::verify_nonce_account, nonce_account::verify_nonce_account,
process_instruction::MockInvokeContext,
system_instruction::NonceError, system_instruction::NonceError,
sysvar::recent_blockhashes::create_test_recent_blockhashes, sysvar::recent_blockhashes::create_test_recent_blockhashes,
}; };
@ -210,7 +290,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(95); let recent_blockhashes = create_test_recent_blockhashes(95);
let authorized = keyed_account.unsigned_key(); let authorized = keyed_account.unsigned_key();
keyed_account keyed_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(keyed_account) let state = AccountUtilsState::<Versions>::state(keyed_account)
.unwrap() .unwrap()
@ -224,7 +309,11 @@ mod test {
assert_eq!(state, State::Initialized(data.clone())); assert_eq!(state, State::Initialized(data.clone()));
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
keyed_account keyed_account
.advance_nonce_account(&recent_blockhashes, &signers) .advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(keyed_account) let state = AccountUtilsState::<Versions>::state(keyed_account)
.unwrap() .unwrap()
@ -238,7 +327,11 @@ mod test {
assert_eq!(state, State::Initialized(data.clone())); assert_eq!(state, State::Initialized(data.clone()));
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
keyed_account keyed_account
.advance_nonce_account(&recent_blockhashes, &signers) .advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(keyed_account) let state = AccountUtilsState::<Versions>::state(keyed_account)
.unwrap() .unwrap()
@ -263,6 +356,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
// Empties Account balance // Empties Account balance
@ -292,7 +386,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
let authority = *nonce_account.unsigned_key(); let authority = *nonce_account.unsigned_key();
nonce_account nonce_account
.initialize_nonce_account(&authority, &recent_blockhashes, &rent) .initialize_nonce_account(
&authority,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let pubkey = nonce_account.account.borrow().owner; let pubkey = nonce_account.account.borrow().owner;
let nonce_account = KeyedAccount::new(&pubkey, false, nonce_account.account); let nonce_account = KeyedAccount::new(&pubkey, false, nonce_account.account);
@ -307,7 +406,11 @@ mod test {
assert_eq!(state, State::Initialized(data)); assert_eq!(state, State::Initialized(data));
let signers = HashSet::new(); let signers = HashSet::new();
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let result = nonce_account.advance_nonce_account(&recent_blockhashes, &signers); let result = nonce_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),); assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
}) })
} }
@ -325,10 +428,19 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let authorized = *keyed_account.unsigned_key(); let authorized = *keyed_account.unsigned_key();
keyed_account keyed_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let recent_blockhashes = vec![].into_iter().collect(); let recent_blockhashes = vec![].into_iter().collect();
let result = keyed_account.advance_nonce_account(&recent_blockhashes, &signers); let result = keyed_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into())); assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into()));
}) })
} }
@ -346,9 +458,18 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
let authorized = *keyed_account.unsigned_key(); let authorized = *keyed_account.unsigned_key();
keyed_account keyed_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let result = keyed_account.advance_nonce_account(&recent_blockhashes, &signers); let result = keyed_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(NonceError::NotExpired.into())); assert_eq!(result, Err(NonceError::NotExpired.into()));
}) })
} }
@ -364,7 +485,11 @@ mod test {
let mut signers = HashSet::new(); let mut signers = HashSet::new();
signers.insert(*keyed_account.signer_key().unwrap()); signers.insert(*keyed_account.signer_key().unwrap());
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
let result = keyed_account.advance_nonce_account(&recent_blockhashes, &signers); let result = keyed_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(NonceError::BadAccountState.into())); assert_eq!(result, Err(NonceError::BadAccountState.into()));
}) })
} }
@ -383,12 +508,21 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
let authorized = *nonce_authority.unsigned_key(); let authorized = *nonce_authority.unsigned_key();
nonce_account nonce_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let mut signers = HashSet::new(); let mut signers = HashSet::new();
signers.insert(*nonce_authority.signer_key().unwrap()); signers.insert(*nonce_authority.signer_key().unwrap());
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
let result = nonce_account.advance_nonce_account(&recent_blockhashes, &signers); let result = nonce_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
}); });
}); });
@ -408,9 +542,18 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
let authorized = *nonce_authority.unsigned_key(); let authorized = *nonce_authority.unsigned_key();
nonce_account nonce_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let result = nonce_account.advance_nonce_account(&recent_blockhashes, &signers); let result = nonce_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),); assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
}); });
}); });
@ -443,6 +586,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed) let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -481,6 +625,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),); assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
}) })
@ -510,6 +655,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::InsufficientFunds)); assert_eq!(result, Err(InstructionError::InsufficientFunds));
}) })
@ -539,6 +685,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed) let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -558,6 +705,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed) let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -583,7 +731,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
let authority = *nonce_keyed.unsigned_key(); let authority = *nonce_keyed.unsigned_key();
nonce_keyed nonce_keyed
.initialize_nonce_account(&authority, &recent_blockhashes, &rent) .initialize_nonce_account(
&authority,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed) let state = AccountUtilsState::<Versions>::state(nonce_keyed)
.unwrap() .unwrap()
@ -606,6 +759,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed) let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -631,6 +785,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
) )
.unwrap(); .unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed) let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -654,7 +809,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let authorized = *nonce_keyed.unsigned_key(); let authorized = *nonce_keyed.unsigned_key();
nonce_keyed nonce_keyed
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
with_test_keyed_account(42, false, |to_keyed| { with_test_keyed_account(42, false, |to_keyed| {
let mut signers = HashSet::new(); let mut signers = HashSet::new();
@ -666,6 +826,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(NonceError::NotExpired.into())); assert_eq!(result, Err(NonceError::NotExpired.into()));
}) })
@ -683,7 +844,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(95); let recent_blockhashes = create_test_recent_blockhashes(95);
let authorized = *nonce_keyed.unsigned_key(); let authorized = *nonce_keyed.unsigned_key();
nonce_keyed nonce_keyed
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
with_test_keyed_account(42, false, |to_keyed| { with_test_keyed_account(42, false, |to_keyed| {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
@ -696,6 +862,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::InsufficientFunds)); assert_eq!(result, Err(InstructionError::InsufficientFunds));
}) })
@ -713,7 +880,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(95); let recent_blockhashes = create_test_recent_blockhashes(95);
let authorized = *nonce_keyed.unsigned_key(); let authorized = *nonce_keyed.unsigned_key();
nonce_keyed nonce_keyed
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
with_test_keyed_account(42, false, |to_keyed| { with_test_keyed_account(42, false, |to_keyed| {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
@ -726,6 +898,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::InsufficientFunds)); assert_eq!(result, Err(InstructionError::InsufficientFunds));
}) })
@ -743,7 +916,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(95); let recent_blockhashes = create_test_recent_blockhashes(95);
let authorized = *nonce_keyed.unsigned_key(); let authorized = *nonce_keyed.unsigned_key();
nonce_keyed nonce_keyed
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
with_test_keyed_account(55, false, |to_keyed| { with_test_keyed_account(55, false, |to_keyed| {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
@ -756,6 +934,7 @@ mod test {
&recent_blockhashes, &recent_blockhashes,
&rent, &rent,
&signers, &signers,
&mut MockInvokeContext::default(),
); );
assert_eq!(result, Err(InstructionError::InsufficientFunds)); assert_eq!(result, Err(InstructionError::InsufficientFunds));
}) })
@ -778,8 +957,12 @@ mod test {
signers.insert(*keyed_account.signer_key().unwrap()); signers.insert(*keyed_account.signer_key().unwrap());
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let authority = *keyed_account.unsigned_key(); let authority = *keyed_account.unsigned_key();
let result = let result = keyed_account.initialize_nonce_account(
keyed_account.initialize_nonce_account(&authority, &recent_blockhashes, &rent); &authority,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
);
let data = nonce::state::Data { let data = nonce::state::Data {
authority, authority,
blockhash: recent_blockhashes[0].blockhash, blockhash: recent_blockhashes[0].blockhash,
@ -805,8 +988,12 @@ mod test {
signers.insert(*keyed_account.signer_key().unwrap()); signers.insert(*keyed_account.signer_key().unwrap());
let recent_blockhashes = vec![].into_iter().collect(); let recent_blockhashes = vec![].into_iter().collect();
let authorized = *keyed_account.unsigned_key(); let authorized = *keyed_account.unsigned_key();
let result = let result = keyed_account.initialize_nonce_account(
keyed_account.initialize_nonce_account(&authorized, &recent_blockhashes, &rent); &authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into())); assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into()));
}) })
} }
@ -822,11 +1009,20 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
let authorized = *keyed_account.unsigned_key(); let authorized = *keyed_account.unsigned_key();
keyed_account keyed_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let result = let result = keyed_account.initialize_nonce_account(
keyed_account.initialize_nonce_account(&authorized, &recent_blockhashes, &rent); &authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(NonceError::BadAccountState.into())); assert_eq!(result, Err(NonceError::BadAccountState.into()));
}) })
} }
@ -841,8 +1037,12 @@ mod test {
with_test_keyed_account(min_lamports - 42, true, |keyed_account| { with_test_keyed_account(min_lamports - 42, true, |keyed_account| {
let recent_blockhashes = create_test_recent_blockhashes(63); let recent_blockhashes = create_test_recent_blockhashes(63);
let authorized = *keyed_account.unsigned_key(); let authorized = *keyed_account.unsigned_key();
let result = let result = keyed_account.initialize_nonce_account(
keyed_account.initialize_nonce_account(&authorized, &recent_blockhashes, &rent); &authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(InstructionError::InsufficientFunds)); assert_eq!(result, Err(InstructionError::InsufficientFunds));
}) })
} }
@ -860,7 +1060,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
let authorized = *nonce_account.unsigned_key(); let authorized = *nonce_account.unsigned_key();
nonce_account nonce_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let authority = Pubkey::default(); let authority = Pubkey::default();
let data = nonce::state::Data { let data = nonce::state::Data {
@ -868,7 +1073,11 @@ mod test {
blockhash: recent_blockhashes[0].blockhash, blockhash: recent_blockhashes[0].blockhash,
fee_calculator: recent_blockhashes[0].fee_calculator.clone(), fee_calculator: recent_blockhashes[0].fee_calculator.clone(),
}; };
let result = nonce_account.authorize_nonce_account(&Pubkey::default(), &signers); let result = nonce_account.authorize_nonce_account(
&Pubkey::default(),
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
let state = AccountUtilsState::<Versions>::state(nonce_account) let state = AccountUtilsState::<Versions>::state(nonce_account)
.unwrap() .unwrap()
@ -887,7 +1096,11 @@ mod test {
with_test_keyed_account(min_lamports + 42, true, |nonce_account| { with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
let mut signers = HashSet::new(); let mut signers = HashSet::new();
signers.insert(*nonce_account.signer_key().unwrap()); signers.insert(*nonce_account.signer_key().unwrap());
let result = nonce_account.authorize_nonce_account(&Pubkey::default(), &signers); let result = nonce_account.authorize_nonce_account(
&Pubkey::default(),
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(NonceError::BadAccountState.into())); assert_eq!(result, Err(NonceError::BadAccountState.into()));
}) })
} }
@ -905,9 +1118,18 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(31); let recent_blockhashes = create_test_recent_blockhashes(31);
let authorized = &Pubkey::default().clone(); let authorized = &Pubkey::default().clone();
nonce_account nonce_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &rent) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
let result = nonce_account.authorize_nonce_account(&Pubkey::default(), &signers); let result = nonce_account.authorize_nonce_account(
&Pubkey::default(),
&signers,
&mut MockInvokeContext::default(),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
}) })
} }
@ -923,7 +1145,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let authorized = nonce_account.unsigned_key(); let authorized = nonce_account.unsigned_key();
nonce_account nonce_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&Rent::free(),
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
assert!(verify_nonce_account( assert!(verify_nonce_account(
&nonce_account.account.borrow(), &nonce_account.account.borrow(),
@ -953,7 +1180,12 @@ mod test {
let recent_blockhashes = create_test_recent_blockhashes(0); let recent_blockhashes = create_test_recent_blockhashes(0);
let authorized = nonce_account.unsigned_key(); let authorized = nonce_account.unsigned_key();
nonce_account nonce_account
.initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) .initialize_nonce_account(
&authorized,
&recent_blockhashes,
&Rent::free(),
&mut MockInvokeContext::default(),
)
.unwrap(); .unwrap();
assert!(!verify_nonce_account( assert!(!verify_nonce_account(
&nonce_account.account.borrow(), &nonce_account.account.borrow(),