diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index 1441ef395..da4c1ade7 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -2,6 +2,7 @@ use log::*; use solana_sdk::{ account::Account, account_utils::StateMut, + ic_msg, instruction::InstructionError, keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, nonce, @@ -34,10 +35,18 @@ impl Address { fn create( address: &Pubkey, with_seed: Option<(&Pubkey, &str, &Pubkey)>, + invoke_context: &mut dyn InvokeContext, ) -> Result { 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 - 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()); } Some(*base) @@ -57,26 +66,34 @@ fn allocate( address: &Address, space: u64, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { 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); } // if it looks like the `to` account is already in use, bail // (note that the id check is also enforced by message_processor) if !account.data.is_empty() || !system_program::check_id(&account.owner) { - debug!( - "Allocate: invalid argument; account {:?} already in use", + ic_msg!( + invoke_context, + "Allocate: account {:?} already in use", address ); return Err(SystemError::AccountAlreadyInUse.into()); } if space > MAX_PERMITTED_DATA_LENGTH { - debug!( - "Allocate: requested space: {} is more than maximum allowed", - space + ic_msg!( + invoke_context, + "Allocate: requested {}, max allowed {}", + space, + MAX_PERMITTED_DATA_LENGTH ); return Err(SystemError::InvalidAccountDataLength.into()); } @@ -91,6 +108,7 @@ fn assign( address: &Address, owner: &Pubkey, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { // no work to do, just return if account.owner == *owner { @@ -98,13 +116,13 @@ fn assign( } if !address.is_signer(&signers) { - debug!("Assign: account must sign"); + ic_msg!(invoke_context, "Assign: account {:?} must sign", address); return Err(InstructionError::MissingRequiredSignature); } // guard against sysvars being made 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()); } @@ -118,9 +136,10 @@ fn allocate_and_assign( space: u64, owner: &Pubkey, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { - allocate(to, to_address, space, signers)?; - assign(to, to_address, owner, signers) + allocate(to, to_address, space, signers, invoke_context)?; + assign(to, to_address, owner, signers, invoke_context) } fn create_account( @@ -131,35 +150,39 @@ fn create_account( space: u64, owner: &Pubkey, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { // if it looks like the `to` account is already in use, bail { let to = &mut to.try_account_ref_mut()?; if to.lamports > 0 { - debug!( - "Create Account: invalid argument; account {:?} already in use", + ic_msg!( + invoke_context, + "Create Account: account {:?} already in use", to_address ); 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( from: &KeyedAccount, to: &KeyedAccount, lamports: u64, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { 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); } if lamports > from.lamports()? { - debug!( - "Transfer: insufficient lamports ({}, need {})", + ic_msg!( + invoke_context, + "Transfer: insufficient lamports {}, need {}", from.lamports()?, lamports ); @@ -171,17 +194,26 @@ fn transfer_verified( 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 { return Ok(()); } 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); } - transfer_verified(from, to, lamports) + transfer_verified(from, to, lamports, invoke_context) } fn transfer_with_seed( @@ -191,30 +223,41 @@ fn transfer_with_seed( from_owner: &Pubkey, to: &KeyedAccount, lamports: u64, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { if lamports == 0 { return Ok(()); } 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); } - if *from.unsigned_key() - != Pubkey::create_with_seed(from_base.unsigned_key(), from_seed, from_owner)? - { + let address_from_seed = + 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()); } - transfer_verified(from, to, lamports) + transfer_verified(from, to, lamports, invoke_context) } pub fn process_instruction( _owner: &Pubkey, keyed_accounts: &[KeyedAccount], instruction_data: &[u8], - _invoke_context: &mut dyn InvokeContext, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let instruction = limited_deserialize(instruction_data)?; @@ -232,8 +275,17 @@ pub fn process_instruction( } => { let from = next_keyed_account(keyed_accounts_iter)?; let to = next_keyed_account(keyed_accounts_iter)?; - let to_address = Address::create(to.unsigned_key(), None)?; - create_account(from, to, &to_address, lamports, space, &owner, &signers) + let to_address = Address::create(to.unsigned_key(), None, invoke_context)?; + create_account( + from, + to, + &to_address, + lamports, + space, + &owner, + &signers, + invoke_context, + ) } SystemInstruction::CreateAccountWithSeed { base, @@ -244,19 +296,32 @@ pub fn process_instruction( } => { let from = 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)))?; - create_account(from, &to, &to_address, lamports, space, &owner, &signers) + let to_address = Address::create( + &to.unsigned_key(), + Some((&base, &seed, &owner)), + invoke_context, + )?; + create_account( + from, + &to, + &to_address, + lamports, + space, + &owner, + &signers, + invoke_context, + ) } SystemInstruction::Assign { owner } => { let keyed_account = next_keyed_account(keyed_accounts_iter)?; let mut account = keyed_account.try_account_ref_mut()?; - let address = Address::create(keyed_account.unsigned_key(), None)?; - assign(&mut account, &address, &owner, &signers) + let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?; + assign(&mut account, &address, &owner, &signers, invoke_context) } SystemInstruction::Transfer { lamports } => { let from = 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 { lamports, @@ -266,13 +331,22 @@ pub fn process_instruction( let from = next_keyed_account(keyed_accounts_iter)?; let base = 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 => { let me = &mut next_keyed_account(keyed_accounts_iter)?; me.advance_nonce_account( &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, &signers, + invoke_context, ) } SystemInstruction::WithdrawNonceAccount(lamports) => { @@ -284,6 +358,7 @@ pub fn process_instruction( &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, &signers, + invoke_context, ) } SystemInstruction::InitializeNonceAccount(authorized) => { @@ -292,17 +367,18 @@ pub fn process_instruction( &authorized, &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, + invoke_context, ) } SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { 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 } => { let keyed_account = next_keyed_account(keyed_accounts_iter)?; let mut account = keyed_account.try_account_ref_mut()?; - let address = Address::create(keyed_account.unsigned_key(), None)?; - allocate(&mut account, &address, space, &signers) + let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?; + allocate(&mut account, &address, space, &signers, invoke_context) } SystemInstruction::AllocateWithSeed { base, @@ -312,17 +388,29 @@ pub fn process_instruction( } => { let keyed_account = next_keyed_account(keyed_accounts_iter)?; let mut account = keyed_account.try_account_ref_mut()?; - let address = - Address::create(keyed_account.unsigned_key(), Some((&base, &seed, &owner)))?; - allocate_and_assign(&mut account, &address, space, &owner, &signers) + let address = Address::create( + keyed_account.unsigned_key(), + Some((&base, &seed, &owner)), + invoke_context, + )?; + allocate_and_assign( + &mut account, + &address, + space, + &owner, + &signers, + invoke_context, + ) } SystemInstruction::AssignWithSeed { base, seed, owner } => { let keyed_account = next_keyed_account(keyed_accounts_iter)?; let mut account = keyed_account.try_account_ref_mut()?; - let address = - Address::create(keyed_account.unsigned_key(), Some((&base, &seed, &owner)))?; - - assign(&mut account, &address, &owner, &signers) + let address = Address::create( + keyed_account.unsigned_key(), + Some((&base, &seed, &owner)), + invoke_context, + )?; + assign(&mut account, &address, &owner, &signers, invoke_context) } } } @@ -524,7 +612,11 @@ mod tests { let owner = solana_sdk::pubkey::new_rand(); assert_eq!( - Address::create(&to, Some((&from, seed, &owner))), + Address::create( + &to, + Some((&from, seed, &owner)), + &mut MockInvokeContext::default(), + ), Err(SystemError::AddressWithSeedMismatch.into()) ); } @@ -538,7 +630,12 @@ mod tests { let from_account = Account::new_ref(100, 0, &system_program::id()); 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!( create_account( @@ -549,6 +646,7 @@ mod tests { 2, &new_owner, &HashSet::new(), + &mut MockInvokeContext::default(), ), Err(InstructionError::MissingRequiredSignature) ); @@ -575,6 +673,7 @@ mod tests { 2, &new_owner, &[to].iter().cloned().collect::>(), + &mut MockInvokeContext::default(), ), Ok(()) ); @@ -607,6 +706,7 @@ mod tests { 2, &new_owner, &[from, to].iter().cloned().collect::>(), + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into())); } @@ -630,6 +730,7 @@ mod tests { MAX_PERMITTED_DATA_LENGTH + 1, &system_program::id(), &signers, + &mut MockInvokeContext::default(), ); assert!(result.is_err()); assert_eq!( @@ -646,6 +747,7 @@ mod tests { MAX_PERMITTED_DATA_LENGTH, &system_program::id(), &signers, + &mut MockInvokeContext::default(), ); assert!(result.is_ok()); assert_eq!(to_account.borrow().lamports, 50); @@ -678,6 +780,7 @@ mod tests { 2, &new_owner, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); @@ -696,6 +799,7 @@ mod tests { 2, &new_owner, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); let from_lamports = from_account.borrow().lamports; @@ -713,6 +817,7 @@ mod tests { 2, &new_owner, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); assert_eq!(from_lamports, 100); @@ -740,6 +845,7 @@ mod tests { 2, &new_owner, &[owned_key].iter().cloned().collect::>(), + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); @@ -753,6 +859,7 @@ mod tests { 2, &new_owner, &[from].iter().cloned().collect::>(), + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); @@ -766,6 +873,7 @@ mod tests { 2, &new_owner, &[owned_key].iter().cloned().collect::>(), + &mut MockInvokeContext::default(), ); assert_eq!(result, Ok(())); } @@ -791,6 +899,7 @@ mod tests { 2, &sysvar::id(), &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::InvalidProgramId.into())); @@ -824,6 +933,7 @@ mod tests { 2, &new_owner, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into())); } @@ -856,7 +966,8 @@ mod tests { 42, 0, &solana_sdk::pubkey::new_rand(), - &signers + &signers, + &mut MockInvokeContext::default(), ), Err(InstructionError::InvalidArgument), ); @@ -870,7 +981,13 @@ mod tests { let mut account = Account::new(100, 0, &system_program::id()); 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) ); // no change, no signature needed @@ -879,7 +996,8 @@ mod tests { &mut account, &pubkey.into(), &system_program::id(), - &HashSet::new() + &HashSet::new(), + &mut MockInvokeContext::default(), ), Ok(()) ); @@ -908,6 +1026,7 @@ mod tests { &from.into(), &new_owner, &[from].iter().cloned().collect::>(), + &mut MockInvokeContext::default(), ), 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 from_keyed_account = KeyedAccount::new(&from, true, &from_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 to_lamports = to_keyed_account.account.borrow().lamports; assert_eq!(from_lamports, 50); @@ -952,14 +1077,26 @@ mod tests { // Attempt to move more lamports than remaining in 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!(from_keyed_account.account.borrow().lamports, 50); assert_eq!(to_keyed_account.account.borrow().lamports, 51); // test unsigned transfer of zero 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!(to_keyed_account.account.borrow().lamports, 51); } @@ -984,6 +1121,7 @@ mod tests { &from_owner, &to_keyed_account, 50, + &mut MockInvokeContext::default(), ) .unwrap(); let from_lamports = from_keyed_account.account.borrow().lamports; @@ -1000,6 +1138,7 @@ mod tests { &from_owner, &to_keyed_account, 100, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into())); assert_eq!(from_keyed_account.account.borrow().lamports, 50); @@ -1014,6 +1153,7 @@ mod tests { &from_owner, &to_keyed_account, 0, + &mut MockInvokeContext::default(), ) .is_ok(),); assert_eq!(from_keyed_account.account.borrow().lamports, 50); @@ -1044,6 +1184,7 @@ mod tests { &KeyedAccount::new(&from, true, &from_account), &KeyedAccount::new(&to, false, &to_account), 50, + &mut MockInvokeContext::default(), ), Err(InstructionError::InvalidArgument), ) diff --git a/sdk/src/nonce_keyed_account.rs b/sdk/src/nonce_keyed_account.rs index 08f702fa1..81e3ab7c0 100644 --- a/sdk/src/nonce_keyed_account.rs +++ b/sdk/src/nonce_keyed_account.rs @@ -1,6 +1,6 @@ use crate::{ - account_utils::State as AccountUtilsState, keyed_account::KeyedAccount, - nonce_account::create_account, + account_utils::State as AccountUtilsState, ic_msg, keyed_account::KeyedAccount, + nonce_account::create_account, process_instruction::InvokeContext, }; use solana_program::{ instruction::{checked_add, InstructionError}, @@ -16,6 +16,7 @@ pub trait NonceKeyedAccount { &self, recent_blockhashes: &RecentBlockhashes, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError>; fn withdraw_nonce_account( &self, @@ -24,17 +25,20 @@ pub trait NonceKeyedAccount { recent_blockhashes: &RecentBlockhashes, rent: &Rent, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError>; fn initialize_nonce_account( &self, nonce_authority: &Pubkey, recent_blockhashes: &RecentBlockhashes, rent: &Rent, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError>; fn authorize_nonce_account( &self, nonce_authority: &Pubkey, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError>; } @@ -43,8 +47,13 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { &self, recent_blockhashes: &RecentBlockhashes, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { if recent_blockhashes.is_empty() { + ic_msg!( + invoke_context, + "Advance nonce account: recent blockhash list is empty", + ); return Err(NonceError::NoRecentBlockhashes.into()); } @@ -52,10 +61,19 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { match state { State::Initialized(data) => { if !signers.contains(&data.authority) { + ic_msg!( + invoke_context, + "Advance nonce account: Account {} must be a signer", + data.authority + ); return Err(InstructionError::MissingRequiredSignature); } let recent_blockhash = recent_blockhashes[0].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()); } @@ -66,7 +84,14 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { }; 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, rent: &Rent, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let signer = match AccountUtilsState::::state(self)?.convert_to_current() { State::Uninitialized => { if lamports > self.lamports()? { + ic_msg!( + invoke_context, + "Withdraw nonce account: insufficient lamports {}, need {}", + self.lamports()?, + lamports, + ); return Err(InstructionError::InsufficientFunds); } *self.unsigned_key() @@ -88,12 +120,23 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { State::Initialized(ref data) => { if lamports == self.lamports()? { 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()); } self.set_state(&Versions::new_current(State::Uninitialized))?; } else { 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); } } @@ -102,6 +145,11 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { }; if !signers.contains(&signer) { + ic_msg!( + invoke_context, + "Withdraw nonce account: Account {} must sign", + signer + ); return Err(InstructionError::MissingRequiredSignature); } @@ -116,8 +164,13 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { nonce_authority: &Pubkey, recent_blockhashes: &RecentBlockhashes, rent: &Rent, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { if recent_blockhashes.is_empty() { + ic_msg!( + invoke_context, + "Initialize nonce account: recent blockhash list is empty", + ); return Err(NonceError::NoRecentBlockhashes.into()); } @@ -125,6 +178,12 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { State::Uninitialized => { let min_balance = rent.minimum_balance(self.data_len()?); if self.lamports()? < min_balance { + ic_msg!( + invoke_context, + "Initialize nonce account: insufficient lamports {}, need {}", + self.lamports()?, + min_balance + ); return Err(InstructionError::InsufficientFunds); } let data = nonce::state::Data { @@ -134,7 +193,14 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { }; 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, nonce_authority: &Pubkey, signers: &HashSet, + invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { match AccountUtilsState::::state(self)?.convert_to_current() { State::Initialized(data) => { if !signers.contains(&data.authority) { + ic_msg!( + invoke_context, + "Authorize nonce account: Account {} must sign", + data.authority + ); return Err(InstructionError::MissingRequiredSignature); } 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))) } - _ => 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, nonce::{self, State}, nonce_account::verify_nonce_account, + process_instruction::MockInvokeContext, system_instruction::NonceError, sysvar::recent_blockhashes::create_test_recent_blockhashes, }; @@ -210,7 +290,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(95); let authorized = keyed_account.unsigned_key(); keyed_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); let state = AccountUtilsState::::state(keyed_account) .unwrap() @@ -224,7 +309,11 @@ mod test { assert_eq!(state, State::Initialized(data.clone())); let recent_blockhashes = create_test_recent_blockhashes(63); keyed_account - .advance_nonce_account(&recent_blockhashes, &signers) + .advance_nonce_account( + &recent_blockhashes, + &signers, + &mut MockInvokeContext::default(), + ) .unwrap(); let state = AccountUtilsState::::state(keyed_account) .unwrap() @@ -238,7 +327,11 @@ mod test { assert_eq!(state, State::Initialized(data.clone())); let recent_blockhashes = create_test_recent_blockhashes(31); keyed_account - .advance_nonce_account(&recent_blockhashes, &signers) + .advance_nonce_account( + &recent_blockhashes, + &signers, + &mut MockInvokeContext::default(), + ) .unwrap(); let state = AccountUtilsState::::state(keyed_account) .unwrap() @@ -263,6 +356,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ) .unwrap(); // Empties Account balance @@ -292,7 +386,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(31); let authority = *nonce_account.unsigned_key(); nonce_account - .initialize_nonce_account(&authority, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authority, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); let pubkey = nonce_account.account.borrow().owner; let nonce_account = KeyedAccount::new(&pubkey, false, nonce_account.account); @@ -307,7 +406,11 @@ mod test { assert_eq!(state, State::Initialized(data)); let signers = HashSet::new(); 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),); }) } @@ -325,10 +428,19 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(0); let authorized = *keyed_account.unsigned_key(); keyed_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); 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())); }) } @@ -346,9 +458,18 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(63); let authorized = *keyed_account.unsigned_key(); keyed_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .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())); }) } @@ -364,7 +485,11 @@ mod test { let mut signers = HashSet::new(); signers.insert(*keyed_account.signer_key().unwrap()); 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())); }) } @@ -383,12 +508,21 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(63); let authorized = *nonce_authority.unsigned_key(); nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); let mut signers = HashSet::new(); signers.insert(*nonce_authority.signer_key().unwrap()); 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(())); }); }); @@ -408,9 +542,18 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(63); let authorized = *nonce_authority.unsigned_key(); nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .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),); }); }); @@ -443,6 +586,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ) .unwrap(); let state = AccountUtilsState::::state(nonce_keyed) @@ -481,6 +625,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::MissingRequiredSignature),); }) @@ -510,6 +655,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); }) @@ -539,6 +685,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ) .unwrap(); let state = AccountUtilsState::::state(nonce_keyed) @@ -558,6 +705,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ) .unwrap(); let state = AccountUtilsState::::state(nonce_keyed) @@ -583,7 +731,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(31); let authority = *nonce_keyed.unsigned_key(); nonce_keyed - .initialize_nonce_account(&authority, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authority, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); let state = AccountUtilsState::::state(nonce_keyed) .unwrap() @@ -606,6 +759,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ) .unwrap(); let state = AccountUtilsState::::state(nonce_keyed) @@ -631,6 +785,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ) .unwrap(); let state = AccountUtilsState::::state(nonce_keyed) @@ -654,7 +809,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(0); let authorized = *nonce_keyed.unsigned_key(); nonce_keyed - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); with_test_keyed_account(42, false, |to_keyed| { let mut signers = HashSet::new(); @@ -666,6 +826,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(NonceError::NotExpired.into())); }) @@ -683,7 +844,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(95); let authorized = *nonce_keyed.unsigned_key(); nonce_keyed - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); with_test_keyed_account(42, false, |to_keyed| { let recent_blockhashes = create_test_recent_blockhashes(63); @@ -696,6 +862,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); }) @@ -713,7 +880,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(95); let authorized = *nonce_keyed.unsigned_key(); nonce_keyed - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); with_test_keyed_account(42, false, |to_keyed| { let recent_blockhashes = create_test_recent_blockhashes(63); @@ -726,6 +898,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); }) @@ -743,7 +916,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(95); let authorized = *nonce_keyed.unsigned_key(); nonce_keyed - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); with_test_keyed_account(55, false, |to_keyed| { let recent_blockhashes = create_test_recent_blockhashes(63); @@ -756,6 +934,7 @@ mod test { &recent_blockhashes, &rent, &signers, + &mut MockInvokeContext::default(), ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); }) @@ -778,8 +957,12 @@ mod test { signers.insert(*keyed_account.signer_key().unwrap()); let recent_blockhashes = create_test_recent_blockhashes(0); let authority = *keyed_account.unsigned_key(); - let result = - keyed_account.initialize_nonce_account(&authority, &recent_blockhashes, &rent); + let result = keyed_account.initialize_nonce_account( + &authority, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ); let data = nonce::state::Data { authority, blockhash: recent_blockhashes[0].blockhash, @@ -805,8 +988,12 @@ mod test { signers.insert(*keyed_account.signer_key().unwrap()); let recent_blockhashes = vec![].into_iter().collect(); let authorized = *keyed_account.unsigned_key(); - let result = - keyed_account.initialize_nonce_account(&authorized, &recent_blockhashes, &rent); + let result = keyed_account.initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ); assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into())); }) } @@ -822,11 +1009,20 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(31); let authorized = *keyed_account.unsigned_key(); keyed_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); let recent_blockhashes = create_test_recent_blockhashes(0); - let result = - keyed_account.initialize_nonce_account(&authorized, &recent_blockhashes, &rent); + let result = keyed_account.initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ); assert_eq!(result, Err(NonceError::BadAccountState.into())); }) } @@ -841,8 +1037,12 @@ mod test { with_test_keyed_account(min_lamports - 42, true, |keyed_account| { let recent_blockhashes = create_test_recent_blockhashes(63); let authorized = *keyed_account.unsigned_key(); - let result = - keyed_account.initialize_nonce_account(&authorized, &recent_blockhashes, &rent); + let result = keyed_account.initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); }) } @@ -860,7 +1060,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(31); let authorized = *nonce_account.unsigned_key(); nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .unwrap(); let authority = Pubkey::default(); let data = nonce::state::Data { @@ -868,7 +1073,11 @@ mod test { blockhash: recent_blockhashes[0].blockhash, 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(())); let state = AccountUtilsState::::state(nonce_account) .unwrap() @@ -887,7 +1096,11 @@ mod test { with_test_keyed_account(min_lamports + 42, true, |nonce_account| { let mut signers = HashSet::new(); 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())); }) } @@ -905,9 +1118,18 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(31); let authorized = &Pubkey::default().clone(); nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &rent) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &rent, + &mut MockInvokeContext::default(), + ) .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)); }) } @@ -923,7 +1145,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(0); let authorized = nonce_account.unsigned_key(); nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &Rent::free(), + &mut MockInvokeContext::default(), + ) .unwrap(); assert!(verify_nonce_account( &nonce_account.account.borrow(), @@ -953,7 +1180,12 @@ mod test { let recent_blockhashes = create_test_recent_blockhashes(0); let authorized = nonce_account.unsigned_key(); nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) + .initialize_nonce_account( + &authorized, + &recent_blockhashes, + &Rent::free(), + &mut MockInvokeContext::default(), + ) .unwrap(); assert!(!verify_nonce_account( &nonce_account.account.borrow(),