Durable Nonce: Re-introduce Initialize instruction (#7353)
Toward an Authorized Noncer
This commit is contained in:
parent
deb7ac549c
commit
059e631f41
|
@ -161,7 +161,7 @@ mod tests {
|
|||
assert_eq!(state, NonceState::Uninitialized);
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
nonce_account
|
||||
.nonce(&recent_blockhashes, &Rent::default(), &signers)
|
||||
.initialize(&recent_blockhashes, &Rent::default(), &signers)
|
||||
.unwrap();
|
||||
assert!(verify_nonce(&nonce_account.account, &recent_blockhashes[0]));
|
||||
});
|
||||
|
@ -184,7 +184,7 @@ mod tests {
|
|||
assert_eq!(state, NonceState::Uninitialized);
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
nonce_account
|
||||
.nonce(&recent_blockhashes, &Rent::default(), &signers)
|
||||
.initialize(&recent_blockhashes, &Rent::default(), &signers)
|
||||
.unwrap();
|
||||
assert!(!verify_nonce(
|
||||
&nonce_account.account,
|
||||
|
|
|
@ -56,6 +56,15 @@ pub enum NonceInstruction {
|
|||
/// The `u64` parameter is the lamports to withdraw, which must leave the
|
||||
/// account balance above the rent exempt reserve or at zero.
|
||||
Withdraw(u64),
|
||||
|
||||
/// `Initialize` drives state of Uninitalized NonceAccount to Initialized,
|
||||
/// setting the nonce value.
|
||||
///
|
||||
/// Expects 3 Accounts:
|
||||
/// 0 - A NonceAccount in the Uninitialized state
|
||||
/// 1 - RecentBlockHashes sysvar
|
||||
/// 2 - Rent sysvar
|
||||
Initialize,
|
||||
}
|
||||
|
||||
pub fn create_nonce_account(
|
||||
|
@ -71,10 +80,22 @@ pub fn create_nonce_account(
|
|||
NonceState::size() as u64,
|
||||
&id(),
|
||||
),
|
||||
nonce(nonce_pubkey),
|
||||
initialize(nonce_pubkey),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn initialize(nonce_pubkey: &Pubkey) -> Instruction {
|
||||
Instruction::new(
|
||||
id(),
|
||||
&NonceInstruction::Initialize,
|
||||
vec![
|
||||
AccountMeta::new(*nonce_pubkey, true),
|
||||
AccountMeta::new_readonly(recent_blockhashes::id(), false),
|
||||
AccountMeta::new_readonly(rent::id(), false),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn nonce(nonce_pubkey: &Pubkey) -> Instruction {
|
||||
Instruction::new(
|
||||
id(),
|
||||
|
@ -113,7 +134,6 @@ pub fn process_instruction(
|
|||
match limited_deserialize(data)? {
|
||||
NonceInstruction::Nonce => me.nonce(
|
||||
&RecentBlockhashes::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||
&Rent::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||
&signers,
|
||||
),
|
||||
NonceInstruction::Withdraw(lamports) => {
|
||||
|
@ -126,13 +146,22 @@ pub fn process_instruction(
|
|||
&signers,
|
||||
)
|
||||
}
|
||||
NonceInstruction::Initialize => me.initialize(
|
||||
&RecentBlockhashes::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||
&Rent::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
|
||||
&signers,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{account::Account, hash::Hash, nonce_state, system_program, sysvar};
|
||||
use crate::{
|
||||
account::Account,
|
||||
hash::{hash, Hash},
|
||||
nonce_state, system_program, sysvar,
|
||||
};
|
||||
use bincode::serialize;
|
||||
|
||||
fn process_instruction(instruction: &Instruction) -> Result<(), InstructionError> {
|
||||
|
@ -232,50 +261,43 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_nonce_ix_bad_rent_state_fail() {
|
||||
assert_eq!(
|
||||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default(),),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account(1),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),),
|
||||
],
|
||||
&serialize(&NonceInstruction::Nonce).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_nonce_ix_ok() {
|
||||
let mut nonce_acc = nonce_state::create_account(1_000_000);
|
||||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut nonce_acc),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
),
|
||||
),
|
||||
KeyedAccount::new(
|
||||
&sysvar::rent::id(),
|
||||
false,
|
||||
&mut sysvar::rent::create_account(1, &Rent::default()),
|
||||
),
|
||||
],
|
||||
&serialize(&NonceInstruction::Initialize).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [
|
||||
KeyedAccount::new(
|
||||
&Pubkey::default(),
|
||||
true,
|
||||
&mut nonce_state::create_account(1_000_000),
|
||||
),
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut nonce_acc,),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut sysvar::recent_blockhashes::create_account_with_data(
|
||||
1,
|
||||
vec![(0u64, &Hash::default()); 32].into_iter(),
|
||||
vec![(0u64, &hash(&serialize(&0).unwrap())); 32].into_iter(),
|
||||
),
|
||||
),
|
||||
KeyedAccount::new(
|
||||
&sysvar::rent::id(),
|
||||
false,
|
||||
&mut sysvar::rent::create_account(1, &Rent::default()),
|
||||
),
|
||||
],
|
||||
&serialize(&NonceInstruction::Nonce).unwrap(),
|
||||
),
|
||||
|
@ -339,27 +361,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_withdraw_ix_bad_rent_state_fail() {
|
||||
assert_eq!(
|
||||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [
|
||||
KeyedAccount::new(&Pubkey::default(), true, &mut Account::default(),),
|
||||
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default(),),
|
||||
KeyedAccount::new(
|
||||
&sysvar::recent_blockhashes::id(),
|
||||
false,
|
||||
&mut Account::default(),
|
||||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),),
|
||||
],
|
||||
&serialize(&NonceInstruction::Withdraw(42)).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_withdraw_ix_ok() {
|
||||
assert_eq!(
|
||||
|
|
|
@ -44,7 +44,6 @@ pub trait NonceAccount {
|
|||
fn nonce(
|
||||
&mut self,
|
||||
recent_blockhashes: &RecentBlockhashes,
|
||||
rent: &Rent,
|
||||
signers: &HashSet<Pubkey>,
|
||||
) -> Result<(), InstructionError>;
|
||||
fn withdraw(
|
||||
|
@ -55,13 +54,18 @@ pub trait NonceAccount {
|
|||
rent: &Rent,
|
||||
signers: &HashSet<Pubkey>,
|
||||
) -> Result<(), InstructionError>;
|
||||
fn initialize(
|
||||
&mut self,
|
||||
recent_blockhashes: &RecentBlockhashes,
|
||||
rent: &Rent,
|
||||
signers: &HashSet<Pubkey>,
|
||||
) -> Result<(), InstructionError>;
|
||||
}
|
||||
|
||||
impl<'a> NonceAccount for KeyedAccount<'a> {
|
||||
fn nonce(
|
||||
&mut self,
|
||||
recent_blockhashes: &RecentBlockhashes,
|
||||
rent: &Rent,
|
||||
signers: &HashSet<Pubkey>,
|
||||
) -> Result<(), InstructionError> {
|
||||
if recent_blockhashes.is_empty() {
|
||||
|
@ -79,13 +83,7 @@ impl<'a> NonceAccount for KeyedAccount<'a> {
|
|||
}
|
||||
meta
|
||||
}
|
||||
NonceState::Uninitialized => {
|
||||
let min_balance = rent.minimum_balance(self.account.data.len());
|
||||
if self.account.lamports < min_balance {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
Meta::new()
|
||||
}
|
||||
_ => return Err(NonceError::BadAccountState.into()),
|
||||
};
|
||||
|
||||
self.set_state(&NonceState::Initialized(meta, recent_blockhashes[0]))
|
||||
|
@ -129,6 +127,34 @@ impl<'a> NonceAccount for KeyedAccount<'a> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
recent_blockhashes: &RecentBlockhashes,
|
||||
rent: &Rent,
|
||||
signers: &HashSet<Pubkey>,
|
||||
) -> Result<(), InstructionError> {
|
||||
if recent_blockhashes.is_empty() {
|
||||
return Err(NonceError::NoRecentBlockhashes.into());
|
||||
}
|
||||
|
||||
if !signers.contains(self.unsigned_key()) {
|
||||
return Err(InstructionError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
let meta = match self.state()? {
|
||||
NonceState::Uninitialized => {
|
||||
let min_balance = rent.minimum_balance(self.account.data.len());
|
||||
if self.account.lamports < min_balance {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
Meta::new()
|
||||
}
|
||||
_ => return Err(NonceError::BadAccountState.into()),
|
||||
};
|
||||
|
||||
self.set_state(&NonceState::Initialized(meta, recent_blockhashes[0]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_account(lamports: u64) -> Account {
|
||||
|
@ -189,24 +215,20 @@ mod test {
|
|||
assert_eq!(state, NonceState::Uninitialized);
|
||||
let recent_blockhashes = create_test_recent_blockhashes(95);
|
||||
keyed_account
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
let state: NonceState = keyed_account.state().unwrap();
|
||||
let stored = recent_blockhashes[0];
|
||||
// First nonce instruction drives state from Uninitialized to Initialized
|
||||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
keyed_account
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
keyed_account.nonce(&recent_blockhashes, &signers).unwrap();
|
||||
let state: NonceState = keyed_account.state().unwrap();
|
||||
let stored = recent_blockhashes[0];
|
||||
// Second nonce instruction consumes and replaces stored nonce
|
||||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
let recent_blockhashes = create_test_recent_blockhashes(31);
|
||||
keyed_account
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
keyed_account.nonce(&recent_blockhashes, &signers).unwrap();
|
||||
let state: NonceState = keyed_account.state().unwrap();
|
||||
let stored = recent_blockhashes[0];
|
||||
// Third nonce instruction for fun and profit
|
||||
|
@ -237,21 +259,6 @@ mod test {
|
|||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonce_inx_uninitialized_account_not_signer_fail() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports + 42, false, |nonce_account| {
|
||||
let signers = HashSet::new();
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let result = nonce_account.nonce(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonce_inx_initialized_account_not_signer_fail() {
|
||||
let rent = Rent {
|
||||
|
@ -266,7 +273,7 @@ mod test {
|
|||
let recent_blockhashes = create_test_recent_blockhashes(31);
|
||||
let stored = recent_blockhashes[0];
|
||||
nonce_account
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
let pubkey = nonce_account.account.owner.clone();
|
||||
let mut nonce_account = KeyedAccount::new(&pubkey, false, nonce_account.account);
|
||||
|
@ -274,7 +281,7 @@ mod test {
|
|||
assert_eq!(state, NonceState::Initialized(meta, stored));
|
||||
let signers = HashSet::new();
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let result = nonce_account.nonce(&recent_blockhashes, &rent, &signers);
|
||||
let result = nonce_account.nonce(&recent_blockhashes, &signers);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
|
||||
})
|
||||
}
|
||||
|
@ -289,8 +296,12 @@ mod test {
|
|||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
keyed_account
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
let recent_blockhashes = RecentBlockhashes::from_iter(vec![].into_iter());
|
||||
let result = keyed_account.nonce(&recent_blockhashes, &rent, &signers);
|
||||
let result = keyed_account.nonce(&recent_blockhashes, &signers);
|
||||
assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into()));
|
||||
})
|
||||
}
|
||||
|
@ -307,26 +318,26 @@ mod test {
|
|||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
keyed_account
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
let result = keyed_account.nonce(&recent_blockhashes, &rent, &signers);
|
||||
let result = keyed_account.nonce(&recent_blockhashes, &signers);
|
||||
assert_eq!(result, Err(NonceError::NotExpired.into()));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nonce_inx_uninitialized_acc_insuff_funds_fail() {
|
||||
fn nonce_inx_uninitialized_account_fail() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports - 42, true, |keyed_account| {
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
let result = keyed_account.nonce(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
let result = keyed_account.nonce(&recent_blockhashes, &signers);
|
||||
assert_eq!(result, Err(NonceError::BadAccountState.into()));
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -480,7 +491,7 @@ mod test {
|
|||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(31);
|
||||
nonce_keyed
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
let state: NonceState = nonce_keyed.state().unwrap();
|
||||
let stored = recent_blockhashes[0];
|
||||
|
@ -536,7 +547,7 @@ mod test {
|
|||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
nonce_keyed
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
|
@ -566,7 +577,7 @@ mod test {
|
|||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(95);
|
||||
nonce_keyed
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
|
@ -597,7 +608,7 @@ mod test {
|
|||
signers.insert(nonce_keyed.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(95);
|
||||
nonce_keyed
|
||||
.nonce(&recent_blockhashes, &rent, &signers)
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
with_test_keyed_account(42, false, |mut to_keyed| {
|
||||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
|
@ -615,4 +626,92 @@ mod test {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_inx_ok() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
let state: NonceState = keyed_account.state().unwrap();
|
||||
assert_eq!(state, NonceState::Uninitialized);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let stored = recent_blockhashes[0];
|
||||
let result = keyed_account.initialize(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Ok(()));
|
||||
let state: NonceState = keyed_account.state().unwrap();
|
||||
assert_eq!(state, NonceState::Initialized(Meta::new(), stored));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_inx_empty_recent_blockhashes_fail() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = RecentBlockhashes::from_iter(vec![].into_iter());
|
||||
let result = keyed_account.initialize(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into()));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_inx_not_signer_fail() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports + 42, false, |keyed_account| {
|
||||
let signers = HashSet::new();
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let result = keyed_account.initialize(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_inx_initialized_account_fail() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(31);
|
||||
keyed_account
|
||||
.initialize(&recent_blockhashes, &rent, &signers)
|
||||
.unwrap();
|
||||
let recent_blockhashes = create_test_recent_blockhashes(0);
|
||||
let result = keyed_account.initialize(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Err(NonceError::BadAccountState.into()));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_inx_uninitialized_acc_insuff_funds_fail() {
|
||||
let rent = Rent {
|
||||
lamports_per_byte_year: 42,
|
||||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(NonceState::size());
|
||||
with_test_keyed_account(min_lamports - 42, true, |keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(keyed_account.signer_key().unwrap().clone());
|
||||
let recent_blockhashes = create_test_recent_blockhashes(63);
|
||||
let result = keyed_account.initialize(&recent_blockhashes, &rent, &signers);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue