Add error reporting to system program (#15644)
This commit is contained in:
parent
a4f0033bd7
commit
a9c8dbfd0c
|
@ -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),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
Loading…
Reference in New Issue