From 1b343665a10f146ba6f6443600c7968234ab926a Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 26 Oct 2020 09:14:57 -0700 Subject: [PATCH] Move KeyedAccount out of solana-program. Native programs are not supported by solana-program --- programs/bpf/benches/bpf_loader.rs | 2 +- programs/bpf/tests/programs.rs | 3 +- programs/bpf_loader/src/lib.rs | 2 +- programs/bpf_loader/src/serialization.rs | 4 +- programs/bpf_loader/src/syscalls.rs | 2 +- programs/budget/src/budget_processor.rs | 2 +- programs/config/src/config_processor.rs | 5 +- programs/exchange/src/exchange_processor.rs | 2 +- programs/failure/src/lib.rs | 2 +- programs/noop/src/lib.rs | 2 +- programs/ownable/src/ownable_processor.rs | 2 +- programs/secp256k1/src/lib.rs | 2 +- programs/stake/src/config.rs | 5 +- programs/stake/src/stake_instruction.rs | 26 ++- programs/stake/src/stake_state.rs | 3 +- programs/vest/src/vest_processor.rs | 3 +- programs/vote/src/vote_instruction.rs | 28 ++- programs/vote/src/vote_state/mod.rs | 6 +- runtime/benches/bank.rs | 2 +- runtime/src/bank.rs | 2 +- runtime/src/message_processor.rs | 3 +- runtime/src/native_loader.rs | 2 +- runtime/src/process_instruction.rs | 3 +- runtime/src/system_instruction_processor.rs | 18 +- sdk/program/src/account.rs | 195 +--------------- sdk/program/src/account_utils.rs | 17 +- sdk/program/src/nonce/mod.rs | 19 +- sdk/program/src/nonce/utils.rs | 62 ----- sdk/program/src/sysvar/mod.rs | 13 +- sdk/program/src/sysvar/rent.rs | 18 +- sdk/src/builtins.rs | 4 +- sdk/src/entrypoint_native.rs | 8 +- sdk/src/keyed_account.rs | 219 ++++++++++++++++++ sdk/src/lib.rs | 2 + .../account.rs => src/nonce_keyed_account.rs} | 78 +++++-- 35 files changed, 384 insertions(+), 382 deletions(-) create mode 100644 sdk/src/keyed_account.rs rename sdk/{program/src/nonce/account.rs => src/nonce_keyed_account.rs} (94%) diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index 99822c8b21..826f3c8363 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -216,7 +216,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { let keyed_accounts: Vec<_> = keys .iter() .zip(&accounts) - .map(|(key, account)| solana_sdk::account::KeyedAccount::new(&key, false, &account)) + .map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account)) .collect(); let instruction_data = vec![0u8]; diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 920f8dc878..e11b1864d8 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -18,12 +18,13 @@ use solana_runtime::{ }, }; use solana_sdk::{ - account::{Account, KeyedAccount}, + account::Account, bpf_loader, bpf_loader_deprecated, client::SyncClient, clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE}, entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, + keyed_account::KeyedAccount, message::Message, pubkey::Pubkey, signature::{Keypair, Signer}, diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 32fdd93632..6a85961088 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -21,11 +21,11 @@ use solana_runtime::{ process_instruction::{ComputeMeter, Executor, InvokeContext}, }; use solana_sdk::{ - account::{is_executable, next_keyed_account, KeyedAccount}, bpf_loader, bpf_loader_deprecated, decode_error::DecodeError, entrypoint::SUCCESS, instruction::InstructionError, + keyed_account::{is_executable, next_keyed_account, KeyedAccount}, loader_instruction::LoaderInstruction, program_utils::limited_deserialize, pubkey::Pubkey, diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index b2d0948dd3..117c52bed8 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -1,7 +1,7 @@ use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; use solana_sdk::{ - account::KeyedAccount, bpf_loader_deprecated, entrypoint::MAX_PERMITTED_DATA_INCREASE, - instruction::InstructionError, pubkey::Pubkey, + bpf_loader_deprecated, entrypoint::MAX_PERMITTED_DATA_INCREASE, instruction::InstructionError, + keyed_account::KeyedAccount, pubkey::Pubkey, }; use std::{ io::prelude::*, diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index bf04d7b91a..cee61d7343 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -16,12 +16,12 @@ use solana_runtime::{ }; use solana_sdk::{ account::Account, - account::KeyedAccount, account_info::AccountInfo, bpf_loader, bpf_loader_deprecated, entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, hash::{Hasher, HASH_BYTES}, instruction::{AccountMeta, Instruction, InstructionError}, + keyed_account::KeyedAccount, message::Message, program_error::ProgramError, pubkey::{Pubkey, PubkeyError}, diff --git a/programs/budget/src/budget_processor.rs b/programs/budget/src/budget_processor.rs index c4685a0df1..3fbe344c0c 100644 --- a/programs/budget/src/budget_processor.rs +++ b/programs/budget/src/budget_processor.rs @@ -7,9 +7,9 @@ use crate::{ use chrono::prelude::{DateTime, Utc}; use log::*; use solana_sdk::{ - account::{next_keyed_account, KeyedAccount}, hash::hash, instruction::InstructionError, + keyed_account::{next_keyed_account, KeyedAccount}, program_utils::limited_deserialize, pubkey::Pubkey, }; diff --git a/programs/config/src/config_processor.rs b/programs/config/src/config_processor.rs index 533ede1213..177b3cd073 100644 --- a/programs/config/src/config_processor.rs +++ b/programs/config/src/config_processor.rs @@ -3,8 +3,8 @@ use crate::ConfigKeys; use bincode::deserialize; use log::*; -use solana_sdk::account::{next_keyed_account, KeyedAccount}; use solana_sdk::instruction::InstructionError; +use solana_sdk::keyed_account::{next_keyed_account, KeyedAccount}; use solana_sdk::program_utils::limited_deserialize; use solana_sdk::pubkey::Pubkey; @@ -107,7 +107,8 @@ mod tests { use bincode::serialized_size; use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ - account::{create_keyed_is_signer_accounts, Account}, + account::Account, + keyed_account::create_keyed_is_signer_accounts, signature::{Keypair, Signer}, system_instruction::SystemInstruction, }; diff --git a/programs/exchange/src/exchange_processor.rs b/programs/exchange/src/exchange_processor.rs index a31df31c8c..c01aa290f2 100644 --- a/programs/exchange/src/exchange_processor.rs +++ b/programs/exchange/src/exchange_processor.rs @@ -8,7 +8,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use serde_derive::Serialize; use solana_metrics::inc_new_counter_info; use solana_sdk::{ - account::KeyedAccount, decode_error::DecodeError, instruction::InstructionError, + decode_error::DecodeError, instruction::InstructionError, keyed_account::KeyedAccount, program_utils::limited_deserialize, pubkey::Pubkey, }; use std::cmp; diff --git a/programs/failure/src/lib.rs b/programs/failure/src/lib.rs index 9c19c3c16d..3225355d3a 100644 --- a/programs/failure/src/lib.rs +++ b/programs/failure/src/lib.rs @@ -1,5 +1,5 @@ -use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; +use solana_sdk::keyed_account::KeyedAccount; use solana_sdk::pubkey::Pubkey; solana_sdk::declare_program!( diff --git a/programs/noop/src/lib.rs b/programs/noop/src/lib.rs index bba88dd908..fb9548f5cf 100644 --- a/programs/noop/src/lib.rs +++ b/programs/noop/src/lib.rs @@ -1,6 +1,6 @@ use log::*; -use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; +use solana_sdk::keyed_account::KeyedAccount; use solana_sdk::pubkey::Pubkey; solana_sdk::declare_program!( diff --git a/programs/ownable/src/ownable_processor.rs b/programs/ownable/src/ownable_processor.rs index 11a83ddb28..785600c981 100644 --- a/programs/ownable/src/ownable_processor.rs +++ b/programs/ownable/src/ownable_processor.rs @@ -3,8 +3,8 @@ use crate::ownable_instruction::OwnableError; use bincode::serialize_into; use solana_sdk::{ - account::{next_keyed_account, KeyedAccount}, instruction::InstructionError, + keyed_account::{next_keyed_account, KeyedAccount}, program_utils::limited_deserialize, pubkey::Pubkey, }; diff --git a/programs/secp256k1/src/lib.rs b/programs/secp256k1/src/lib.rs index 25e7892998..abba7bf2b0 100644 --- a/programs/secp256k1/src/lib.rs +++ b/programs/secp256k1/src/lib.rs @@ -1,7 +1,7 @@ use solana_sdk::pubkey::Pubkey; use solana_sdk::{ - account::KeyedAccount, instruction::{Instruction, InstructionError}, + keyed_account::KeyedAccount, }; pub fn process_instruction( diff --git a/programs/stake/src/config.rs b/programs/stake/src/config.rs index e69b1ea8d7..35d2a53db8 100644 --- a/programs/stake/src/config.rs +++ b/programs/stake/src/config.rs @@ -4,9 +4,8 @@ use bincode::{deserialize, serialized_size}; use serde_derive::{Deserialize, Serialize}; use solana_config_program::{create_config_account, get_config_data, ConfigState}; use solana_sdk::{ - account::{Account, KeyedAccount}, - genesis_config::GenesisConfig, - instruction::InstructionError, + account::Account, genesis_config::GenesisConfig, instruction::InstructionError, + keyed_account::KeyedAccount, }; // stake config ID diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 03e6a06626..6a6a9116f0 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -6,14 +6,14 @@ use log::*; use num_derive::{FromPrimitive, ToPrimitive}; use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ - account::{get_signers, next_keyed_account, KeyedAccount}, clock::{Epoch, UnixTimestamp}, decode_error::DecodeError, instruction::{AccountMeta, Instruction, InstructionError}, + keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction, - sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory, Sysvar}, + sysvar::{self, clock::Clock, rent::Rent, stake_history::StakeHistory}, }; use thiserror::Error; @@ -459,7 +459,7 @@ pub fn process_instruction( StakeInstruction::Initialize(authorized, lockup) => me.initialize( &authorized, &lockup, - &Rent::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, ), StakeInstruction::Authorize(authorized_pubkey, stake_authorize) => { me.authorize(&signers, &authorized_pubkey, stake_authorize) @@ -479,8 +479,8 @@ pub fn process_instruction( me.delegate( &vote, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, - &StakeHistory::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, &config::from_keyed_account(next_keyed_account(keyed_accounts)?)?, &signers, ) @@ -493,8 +493,8 @@ pub fn process_instruction( let source_stake = &next_keyed_account(keyed_accounts)?; me.merge( source_stake, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, - &StakeHistory::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, &signers, ) } @@ -504,14 +504,14 @@ pub fn process_instruction( me.withdraw( lamports, to, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, - &StakeHistory::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, next_keyed_account(keyed_accounts)?, keyed_accounts.next(), ) } StakeInstruction::Deactivate => me.deactivate( - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, &signers, ), @@ -523,7 +523,11 @@ pub fn process_instruction( mod tests { use super::*; use bincode::serialize; - use solana_sdk::{account::Account, rent::Rent, sysvar::stake_history::StakeHistory}; + use solana_sdk::{ + account::Account, + rent::Rent, + sysvar::{stake_history::StakeHistory, Sysvar}, + }; use std::cell::RefCell; fn create_default_account() -> RefCell { diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index 0eadf93c2d..73b860c0db 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -10,10 +10,11 @@ use crate::{ }; use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ - account::{Account, KeyedAccount}, + account::Account, account_utils::{State, StateMut}, clock::{Clock, Epoch, UnixTimestamp}, instruction::InstructionError, + keyed_account::KeyedAccount, pubkey::Pubkey, rent::Rent, stake_history::{StakeHistory, StakeHistoryEntry}, diff --git a/programs/vest/src/vest_processor.rs b/programs/vest/src/vest_processor.rs index cd4b11f90b..20a0f8f2b1 100644 --- a/programs/vest/src/vest_processor.rs +++ b/programs/vest/src/vest_processor.rs @@ -7,8 +7,9 @@ use chrono::prelude::*; use solana_config_program::date_instruction::DateConfig; use solana_config_program::get_config_data; use solana_sdk::{ - account::{next_keyed_account, Account, KeyedAccount}, + account::Account, instruction::InstructionError, + keyed_account::{next_keyed_account, KeyedAccount}, program_utils::limited_deserialize, pubkey::Pubkey, }; diff --git a/programs/vote/src/vote_instruction.rs b/programs/vote/src/vote_instruction.rs index ad1cccdff9..40a902d4e4 100644 --- a/programs/vote/src/vote_instruction.rs +++ b/programs/vote/src/vote_instruction.rs @@ -10,14 +10,14 @@ use num_derive::{FromPrimitive, ToPrimitive}; use serde_derive::{Deserialize, Serialize}; use solana_metrics::inc_new_counter_info; use solana_sdk::{ - account::{get_signers, next_keyed_account, KeyedAccount}, decode_error::DecodeError, hash::Hash, instruction::{AccountMeta, Instruction, InstructionError}, + keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction, - sysvar::{self, clock::Clock, slot_hashes::SlotHashes, Sysvar}, + sysvar::{self, clock::Clock, slot_hashes::SlotHashes}, }; use std::collections::HashSet; use thiserror::Error; @@ -261,6 +261,18 @@ pub fn withdraw( Instruction::new(id(), &VoteInstruction::Withdraw(lamports), account_metas) } +fn verify_rent_exemption( + keyed_account: &KeyedAccount, + rent_sysvar_account: &KeyedAccount, +) -> Result<(), InstructionError> { + let rent: sysvar::rent::Rent = from_keyed_account(rent_sysvar_account)?; + if !rent.is_exempt(keyed_account.lamports()?, keyed_account.data_len()?) { + Err(InstructionError::InsufficientFunds) + } else { + Ok(()) + } +} + pub fn process_instruction( _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], @@ -276,12 +288,12 @@ pub fn process_instruction( match limited_deserialize(data)? { VoteInstruction::InitializeAccount(vote_init) => { - sysvar::rent::verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?; + verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?; vote_state::initialize_account( me, &vote_init, &signers, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, ) } VoteInstruction::Authorize(voter_pubkey, vote_authorize) => vote_state::authorize( @@ -289,7 +301,7 @@ pub fn process_instruction( &voter_pubkey, vote_authorize, &signers, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, ), VoteInstruction::UpdateValidatorIdentity => vote_state::update_validator_identity( me, @@ -303,8 +315,8 @@ pub fn process_instruction( inc_new_counter_info!("vote-native", 1); vote_state::process_vote( me, - &SlotHashes::from_keyed_account(next_keyed_account(keyed_accounts)?)?, - &Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts)?)?, &vote, &signers, ) @@ -319,7 +331,7 @@ pub fn process_instruction( #[cfg(test)] mod tests { use super::*; - use solana_sdk::{account::Account, rent::Rent}; + use solana_sdk::{account::Account, rent::Rent, sysvar::Sysvar}; use std::cell::RefCell; // these are for 100% coverage in this file diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index 628eabea30..9e3801a150 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -6,12 +6,13 @@ use bincode::{deserialize, serialize_into, serialized_size, ErrorKind}; use log::*; use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ - account::{Account, KeyedAccount}, + account::Account, account_utils::State, clock::{Epoch, Slot, UnixTimestamp}, epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET, hash::Hash, instruction::InstructionError, + keyed_account::KeyedAccount, pubkey::Pubkey, rent::Rent, slot_hashes::SlotHash, @@ -759,9 +760,10 @@ mod tests { use super::*; use crate::vote_state; use solana_sdk::{ - account::{get_signers, next_keyed_account, Account}, + account::Account, account_utils::StateMut, hash::hash, + keyed_account::{get_signers, next_keyed_account}, }; use std::cell::RefCell; diff --git a/runtime/benches/bank.rs b/runtime/benches/bank.rs index 1392304c54..3283a36be0 100644 --- a/runtime/benches/bank.rs +++ b/runtime/benches/bank.rs @@ -5,12 +5,12 @@ extern crate test; use log::*; use solana_runtime::{bank::*, bank_client::BankClient, loader_utils::create_invoke_instruction}; use solana_sdk::{ - account::KeyedAccount, client::AsyncClient, client::SyncClient, clock::MAX_RECENT_BLOCKHASHES, genesis_config::create_genesis_config, instruction::InstructionError, + keyed_account::KeyedAccount, message::Message, pubkey::Pubkey, signature::{Keypair, Signer}, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 62926c6c20..fdb1d065e4 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -4118,12 +4118,12 @@ mod tests { status_cache::MAX_CACHE_ENTRIES, }; use solana_sdk::{ - account::KeyedAccount, account_utils::StateMut, clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT}, epoch_schedule::MINIMUM_SLOTS_PER_EPOCH, genesis_config::create_genesis_config, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, + keyed_account::KeyedAccount, message::{Message, MessageHeader}, nonce, poh_config::PohConfig, diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index e355c8c284..7d25b869ec 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -12,9 +12,10 @@ use crate::{ use log::*; use serde::{Deserialize, Serialize}; use solana_sdk::{ - account::{create_keyed_readonly_accounts, Account, KeyedAccount}, + account::Account, clock::Epoch, instruction::{CompiledInstruction, Instruction, InstructionError}, + keyed_account::{create_keyed_readonly_accounts, KeyedAccount}, message::Message, native_loader, pubkey::Pubkey, diff --git a/runtime/src/native_loader.rs b/runtime/src/native_loader.rs index 8f8188ea3d..9e6c368ee8 100644 --- a/runtime/src/native_loader.rs +++ b/runtime/src/native_loader.rs @@ -7,10 +7,10 @@ use libloading::os::windows::*; use log::*; use num_derive::{FromPrimitive, ToPrimitive}; use solana_sdk::{ - account::{next_keyed_account, KeyedAccount}, decode_error::DecodeError, entrypoint_native::ProgramEntrypoint, instruction::InstructionError, + keyed_account::{next_keyed_account, KeyedAccount}, pubkey::Pubkey, }; use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock}; diff --git a/runtime/src/process_instruction.rs b/runtime/src/process_instruction.rs index 529181a819..87089016bd 100644 --- a/runtime/src/process_instruction.rs +++ b/runtime/src/process_instruction.rs @@ -3,8 +3,9 @@ use crate::feature_set::{ pubkey_log_syscall_enabled, FeatureSet, }; use solana_sdk::{ - account::{Account, KeyedAccount}, + account::Account, instruction::{CompiledInstruction, Instruction, InstructionError}, + keyed_account::KeyedAccount, message::Message, pubkey::Pubkey, }; diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index 9b187041fd..1b6fa20c60 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -1,14 +1,16 @@ use log::*; use solana_sdk::{ - account::{get_signers, next_keyed_account, Account, KeyedAccount}, + account::Account, account_utils::StateMut, instruction::InstructionError, - nonce::{self, Account as NonceAccount}, + keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount}, + nonce, + nonce_keyed_account::NonceKeyedAccount, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH}, system_program, - sysvar::{self, recent_blockhashes::RecentBlockhashes, rent::Rent, Sysvar}, + sysvar::{self, recent_blockhashes::RecentBlockhashes, rent::Rent}, }; use std::collections::HashSet; @@ -267,7 +269,7 @@ pub fn process_instruction( SystemInstruction::AdvanceNonceAccount => { let me = &mut next_keyed_account(keyed_accounts_iter)?; me.advance_nonce_account( - &RecentBlockhashes::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, &signers, ) } @@ -277,8 +279,8 @@ pub fn process_instruction( me.withdraw_nonce_account( lamports, to, - &RecentBlockhashes::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?, - &Rent::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, &signers, ) } @@ -286,8 +288,8 @@ pub fn process_instruction( let me = &mut next_keyed_account(keyed_accounts_iter)?; me.initialize_nonce_account( &authorized, - &RecentBlockhashes::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?, - &Rent::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, + &from_keyed_account::(next_keyed_account(keyed_accounts_iter)?)?, ) } SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { diff --git a/sdk/program/src/account.rs b/sdk/program/src/account.rs index fd16d08020..2986c4e715 100644 --- a/sdk/program/src/account.rs +++ b/sdk/program/src/account.rs @@ -1,10 +1,5 @@ -use crate::{clock::Epoch, instruction::InstructionError, pubkey::Pubkey}; -use std::{ - cell::{Ref, RefCell, RefMut}, - cmp, fmt, - iter::FromIterator, - rc::Rc, -}; +use crate::{clock::Epoch, pubkey::Pubkey}; +use std::{cell::RefCell, cmp, fmt, rc::Rc}; /// An Account with data that is stored on chain #[repr(C)] @@ -114,189 +109,3 @@ impl Account { bincode::serialize_into(&mut self.data[..], state) } } - -#[repr(C)] -#[derive(Debug)] -pub struct KeyedAccount<'a> { - is_signer: bool, // Transaction was signed by this account's key - is_writable: bool, - key: &'a Pubkey, - pub account: &'a RefCell, -} - -impl<'a> KeyedAccount<'a> { - pub fn signer_key(&self) -> Option<&Pubkey> { - if self.is_signer { - Some(self.key) - } else { - None - } - } - - pub fn unsigned_key(&self) -> &Pubkey { - self.key - } - - pub fn is_writable(&self) -> bool { - self.is_writable - } - - pub fn lamports(&self) -> Result { - Ok(self.try_borrow()?.lamports) - } - - pub fn data_len(&self) -> Result { - Ok(self.try_borrow()?.data.len()) - } - - pub fn data_is_empty(&self) -> Result { - Ok(self.try_borrow()?.data.is_empty()) - } - - pub fn owner(&self) -> Result { - Ok(self.try_borrow()?.owner) - } - - pub fn executable(&self) -> Result { - Ok(self.try_borrow()?.executable) - } - - pub fn rent_epoch(&self) -> Result { - Ok(self.try_borrow()?.rent_epoch) - } - - pub fn try_account_ref(&'a self) -> Result, InstructionError> { - self.try_borrow() - } - - pub fn try_account_ref_mut(&'a self) -> Result, InstructionError> { - self.try_borrow_mut() - } - - fn try_borrow(&self) -> Result, InstructionError> { - self.account - .try_borrow() - .map_err(|_| InstructionError::AccountBorrowFailed) - } - fn try_borrow_mut(&self) -> Result, InstructionError> { - self.account - .try_borrow_mut() - .map_err(|_| InstructionError::AccountBorrowFailed) - } - - pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a RefCell) -> Self { - Self { - is_signer, - is_writable: true, - key, - account, - } - } - - pub fn new_readonly(key: &'a Pubkey, is_signer: bool, account: &'a RefCell) -> Self { - Self { - is_signer, - is_writable: false, - key, - account, - } - } -} - -impl<'a> PartialEq for KeyedAccount<'a> { - fn eq(&self, other: &Self) -> bool { - self.key == other.key - } -} - -impl<'a> From<(&'a Pubkey, &'a RefCell)> for KeyedAccount<'a> { - fn from((key, account): (&'a Pubkey, &'a RefCell)) -> Self { - Self { - is_signer: false, - is_writable: true, - key, - account, - } - } -} - -impl<'a> From<(&'a Pubkey, bool, &'a RefCell)> for KeyedAccount<'a> { - fn from((key, is_signer, account): (&'a Pubkey, bool, &'a RefCell)) -> Self { - Self { - is_signer, - is_writable: true, - key, - account, - } - } -} - -impl<'a> From<&'a (&'a Pubkey, &'a RefCell)> for KeyedAccount<'a> { - fn from((key, account): &'a (&'a Pubkey, &'a RefCell)) -> Self { - Self { - is_signer: false, - is_writable: true, - key, - account, - } - } -} - -pub fn create_keyed_accounts<'a>( - accounts: &'a [(&'a Pubkey, &'a RefCell)], -) -> Vec> { - accounts.iter().map(Into::into).collect() -} - -pub fn create_keyed_is_signer_accounts<'a>( - accounts: &'a [(&'a Pubkey, bool, &'a RefCell)], -) -> Vec> { - accounts - .iter() - .map(|(key, is_signer, account)| KeyedAccount { - is_signer: *is_signer, - is_writable: false, - key, - account, - }) - .collect() -} - -pub fn create_keyed_readonly_accounts( - accounts: &[(Pubkey, RefCell)], -) -> Vec { - accounts - .iter() - .map(|(key, account)| KeyedAccount { - is_signer: false, - is_writable: false, - key, - account, - }) - .collect() -} - -/// Return all the signers from a set of KeyedAccounts -pub fn get_signers(keyed_accounts: &[KeyedAccount]) -> A -where - A: FromIterator, -{ - keyed_accounts - .iter() - .filter_map(|keyed_account| keyed_account.signer_key()) - .cloned() - .collect::() -} - -/// Return the next KeyedAccount or a NotEnoughAccountKeys error -pub fn next_keyed_account<'a, 'b, I: Iterator>>( - iter: &mut I, -) -> Result { - iter.next().ok_or(InstructionError::NotEnoughAccountKeys) -} - -/// Return true if the first keyed_account is executable, used to determine if -/// the loader should call a program's 'main' -pub fn is_executable(keyed_accounts: &[KeyedAccount]) -> Result { - Ok(!keyed_accounts.is_empty() && keyed_accounts[0].executable()?) -} diff --git a/sdk/program/src/account_utils.rs b/sdk/program/src/account_utils.rs index 7b97dde5b5..c1096c1e95 100644 --- a/sdk/program/src/account_utils.rs +++ b/sdk/program/src/account_utils.rs @@ -1,8 +1,5 @@ //! useful extras for Account state -use crate::{ - account::{Account, KeyedAccount}, - instruction::InstructionError, -}; +use crate::{account::Account, instruction::InstructionError}; use bincode::ErrorKind; /// Convenience trait to covert bincode errors to instruction errors. @@ -31,18 +28,6 @@ where } } -impl<'a, T> State for KeyedAccount<'a> -where - T: serde::Serialize + serde::de::DeserializeOwned, -{ - fn state(&self) -> Result { - self.try_account_ref()?.state() - } - fn set_state(&self, state: &T) -> Result<(), InstructionError> { - self.try_account_ref_mut()?.set_state(state) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/sdk/program/src/nonce/mod.rs b/sdk/program/src/nonce/mod.rs index f9a34f27cd..db8e79aa81 100644 --- a/sdk/program/src/nonce/mod.rs +++ b/sdk/program/src/nonce/mod.rs @@ -1,5 +1,18 @@ -pub mod account; -pub use account::{create_account, Account}; pub mod state; -pub use state::State; pub mod utils; +pub use state::State; + +use crate::{account, nonce::state::Versions}; +use std::cell::RefCell; + +pub fn create_account(lamports: u64) -> RefCell { + RefCell::new( + account::Account::new_data_with_space( + lamports, + &Versions::new_current(State::Uninitialized), + State::size(), + &crate::system_program::id(), + ) + .expect("nonce_account"), + ) +} diff --git a/sdk/program/src/nonce/utils.rs b/sdk/program/src/nonce/utils.rs index e97ef16929..e2ac487a2a 100644 --- a/sdk/program/src/nonce/utils.rs +++ b/sdk/program/src/nonce/utils.rs @@ -22,65 +22,3 @@ pub fn fee_calculator_of(account: &Account) -> Option { _ => None, } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - account_utils::State as AccountUtilsState, - hash::Hash, - nonce::{account::with_test_keyed_account, Account as NonceAccount, State}, - sysvar::{recent_blockhashes::create_test_recent_blockhashes, rent::Rent}, - }; - use std::collections::HashSet; - - #[test] - fn verify_nonce_ok() { - with_test_keyed_account(42, true, |nonce_account| { - let mut signers = HashSet::new(); - signers.insert(nonce_account.signer_key().unwrap()); - let state: State = nonce_account.state().unwrap(); - // New is in Uninitialzed state - assert_eq!(state, State::Uninitialized); - let recent_blockhashes = create_test_recent_blockhashes(0); - let authorized = nonce_account.unsigned_key(); - nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) - .unwrap(); - assert!(verify_nonce_account( - &nonce_account.account.borrow(), - &recent_blockhashes[0].blockhash, - )); - }); - } - - #[test] - fn verify_nonce_bad_acc_state_fail() { - with_test_keyed_account(42, true, |nonce_account| { - assert!(!verify_nonce_account( - &nonce_account.account.borrow(), - &Hash::default() - )); - }); - } - - #[test] - fn verify_nonce_bad_query_hash_fail() { - with_test_keyed_account(42, true, |nonce_account| { - let mut signers = HashSet::new(); - signers.insert(nonce_account.signer_key().unwrap()); - let state: State = nonce_account.state().unwrap(); - // New is in Uninitialzed state - assert_eq!(state, State::Uninitialized); - let recent_blockhashes = create_test_recent_blockhashes(0); - let authorized = nonce_account.unsigned_key(); - nonce_account - .initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) - .unwrap(); - assert!(!verify_nonce_account( - &nonce_account.account.borrow(), - &recent_blockhashes[1].blockhash, - )); - }); - } -} diff --git a/sdk/program/src/sysvar/mod.rs b/sdk/program/src/sysvar/mod.rs index 79d169513a..1f01aa543b 100644 --- a/sdk/program/src/sysvar/mod.rs +++ b/sdk/program/src/sysvar/mod.rs @@ -1,11 +1,7 @@ //! named accounts for synthesized data accounts for bank state, etc. //! use crate::{ - account::{Account, KeyedAccount}, - account_info::AccountInfo, - instruction::InstructionError, - program_error::ProgramError, - pubkey::Pubkey, + account::Account, account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, }; pub mod clock; @@ -79,13 +75,6 @@ pub trait Sysvar: fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> { bincode::serialize_into(&mut account_info.data.borrow_mut()[..], self).ok() } - fn from_keyed_account(keyed_account: &KeyedAccount) -> Result { - if !Self::check_id(keyed_account.unsigned_key()) { - return Err(InstructionError::InvalidArgument); - } - Self::from_account(&*keyed_account.try_account_ref()?) - .ok_or(InstructionError::InvalidArgument) - } fn create_account(&self, lamports: u64) -> Account { let data_len = Self::size_of().max(bincode::serialized_size(self).unwrap() as usize); let mut account = Account::new(lamports, data_len, &id()); diff --git a/sdk/program/src/sysvar/rent.rs b/sdk/program/src/sysvar/rent.rs index ff005762d9..ac2028dfad 100644 --- a/sdk/program/src/sysvar/rent.rs +++ b/sdk/program/src/sysvar/rent.rs @@ -2,11 +2,7 @@ //! pub use crate::rent::Rent; -use crate::{ - account::{Account, KeyedAccount}, - instruction::InstructionError, - sysvar::Sysvar, -}; +use crate::{account::Account, sysvar::Sysvar}; crate::declare_sysvar_id!("SysvarRent111111111111111111111111111111111", Rent); @@ -16,18 +12,6 @@ pub fn create_account(lamports: u64, rent: &Rent) -> Account { rent.create_account(lamports) } -pub fn verify_rent_exemption( - keyed_account: &KeyedAccount, - rent_sysvar_account: &KeyedAccount, -) -> Result<(), InstructionError> { - let rent = Rent::from_keyed_account(rent_sysvar_account)?; - if !rent.is_exempt(keyed_account.lamports()?, keyed_account.data_len()?) { - Err(InstructionError::InsufficientFunds) - } else { - Ok(()) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/sdk/src/builtins.rs b/sdk/src/builtins.rs index 9df4fdd482..7cdddb76bf 100644 --- a/sdk/src/builtins.rs +++ b/sdk/src/builtins.rs @@ -73,7 +73,7 @@ macro_rules! declare_builtin_name { /// // wrapper is used so that the macro invocation occurs in the item position /// // rather than in the statement position which isn't allowed. /// mod item_wrapper { -/// use solana_sdk::account::KeyedAccount; +/// use solana_sdk::keyed_account::KeyedAccount; /// use solana_sdk::instruction::InstructionError; /// use solana_sdk::pubkey::Pubkey; /// use solana_sdk::declare_builtin; @@ -104,7 +104,7 @@ macro_rules! declare_builtin_name { /// # // wrapper is used so that the macro invocation occurs in the item position /// # // rather than in the statement position which isn't allowed. /// # mod item_wrapper { -/// use solana_sdk::account::KeyedAccount; +/// use solana_sdk::keyed_account::KeyedAccount; /// use solana_sdk::instruction::InstructionError; /// use solana_sdk::pubkey::Pubkey; /// use solana_sdk::declare_builtin; diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index 3990a7fbd2..ddd4359d3c 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -1,6 +1,6 @@ //! @brief Solana Native program entry point -use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey}; +use crate::{instruction::InstructionError, keyed_account::KeyedAccount, pubkey::Pubkey}; // Prototype of a native program entry point /// @@ -86,7 +86,7 @@ macro_rules! declare_name { /// # // wrapper is used so that the macro invocation occurs in the item position /// # // rather than in the statement position which isn't allowed. /// # mod item_wrapper { -/// use solana_sdk::account::KeyedAccount; +/// use solana_sdk::keyed_account::KeyedAccount; /// use solana_sdk::instruction::InstructionError; /// use solana_sdk::pubkey::Pubkey; /// use solana_sdk::declare_program; @@ -117,7 +117,7 @@ macro_rules! declare_name { /// # // wrapper is used so that the macro invocation occurs in the item position /// # // rather than in the statement position which isn't allowed. /// # mod item_wrapper { -/// use solana_sdk::account::KeyedAccount; +/// use solana_sdk::keyed_account::KeyedAccount; /// use solana_sdk::instruction::InstructionError; /// use solana_sdk::pubkey::Pubkey; /// use solana_sdk::declare_program; @@ -150,7 +150,7 @@ macro_rules! declare_program( #[no_mangle] pub extern "C" fn $name( program_id: &$crate::pubkey::Pubkey, - keyed_accounts: &[$crate::account::KeyedAccount], + keyed_accounts: &[$crate::keyed_account::KeyedAccount], instruction_data: &[u8], ) -> Result<(), $crate::instruction::InstructionError> { $entrypoint(program_id, keyed_accounts, instruction_data) diff --git a/sdk/src/keyed_account.rs b/sdk/src/keyed_account.rs new file mode 100644 index 0000000000..67f7141ef1 --- /dev/null +++ b/sdk/src/keyed_account.rs @@ -0,0 +1,219 @@ +use solana_program::{ + account::Account, + account_utils::{State, StateMut}, + clock::Epoch, + instruction::InstructionError, + pubkey::Pubkey, + sysvar::Sysvar, +}; +use std::{ + cell::{Ref, RefCell, RefMut}, + iter::FromIterator, +}; + +#[repr(C)] +#[derive(Debug)] +pub struct KeyedAccount<'a> { + is_signer: bool, // Transaction was signed by this account's key + is_writable: bool, + key: &'a Pubkey, + pub account: &'a RefCell, +} + +impl<'a> KeyedAccount<'a> { + pub fn signer_key(&self) -> Option<&Pubkey> { + if self.is_signer { + Some(self.key) + } else { + None + } + } + + pub fn unsigned_key(&self) -> &Pubkey { + self.key + } + + pub fn is_writable(&self) -> bool { + self.is_writable + } + + pub fn lamports(&self) -> Result { + Ok(self.try_borrow()?.lamports) + } + + pub fn data_len(&self) -> Result { + Ok(self.try_borrow()?.data.len()) + } + + pub fn data_is_empty(&self) -> Result { + Ok(self.try_borrow()?.data.is_empty()) + } + + pub fn owner(&self) -> Result { + Ok(self.try_borrow()?.owner) + } + + pub fn executable(&self) -> Result { + Ok(self.try_borrow()?.executable) + } + + pub fn rent_epoch(&self) -> Result { + Ok(self.try_borrow()?.rent_epoch) + } + + pub fn try_account_ref(&'a self) -> Result, InstructionError> { + self.try_borrow() + } + + pub fn try_account_ref_mut(&'a self) -> Result, InstructionError> { + self.try_borrow_mut() + } + + fn try_borrow(&self) -> Result, InstructionError> { + self.account + .try_borrow() + .map_err(|_| InstructionError::AccountBorrowFailed) + } + fn try_borrow_mut(&self) -> Result, InstructionError> { + self.account + .try_borrow_mut() + .map_err(|_| InstructionError::AccountBorrowFailed) + } + + pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a RefCell) -> Self { + Self { + is_signer, + is_writable: true, + key, + account, + } + } + + pub fn new_readonly(key: &'a Pubkey, is_signer: bool, account: &'a RefCell) -> Self { + Self { + is_signer, + is_writable: false, + key, + account, + } + } +} + +impl<'a> PartialEq for KeyedAccount<'a> { + fn eq(&self, other: &Self) -> bool { + self.key == other.key + } +} + +impl<'a> From<(&'a Pubkey, &'a RefCell)> for KeyedAccount<'a> { + fn from((key, account): (&'a Pubkey, &'a RefCell)) -> Self { + Self { + is_signer: false, + is_writable: true, + key, + account, + } + } +} + +impl<'a> From<(&'a Pubkey, bool, &'a RefCell)> for KeyedAccount<'a> { + fn from((key, is_signer, account): (&'a Pubkey, bool, &'a RefCell)) -> Self { + Self { + is_signer, + is_writable: true, + key, + account, + } + } +} + +impl<'a> From<&'a (&'a Pubkey, &'a RefCell)> for KeyedAccount<'a> { + fn from((key, account): &'a (&'a Pubkey, &'a RefCell)) -> Self { + Self { + is_signer: false, + is_writable: true, + key, + account, + } + } +} + +pub fn create_keyed_accounts<'a>( + accounts: &'a [(&'a Pubkey, &'a RefCell)], +) -> Vec> { + accounts.iter().map(Into::into).collect() +} + +pub fn create_keyed_is_signer_accounts<'a>( + accounts: &'a [(&'a Pubkey, bool, &'a RefCell)], +) -> Vec> { + accounts + .iter() + .map(|(key, is_signer, account)| KeyedAccount { + is_signer: *is_signer, + is_writable: false, + key, + account, + }) + .collect() +} + +pub fn create_keyed_readonly_accounts( + accounts: &[(Pubkey, RefCell)], +) -> Vec { + accounts + .iter() + .map(|(key, account)| KeyedAccount { + is_signer: false, + is_writable: false, + key, + account, + }) + .collect() +} + +/// Return all the signers from a set of KeyedAccounts +pub fn get_signers(keyed_accounts: &[KeyedAccount]) -> A +where + A: FromIterator, +{ + keyed_accounts + .iter() + .filter_map(|keyed_account| keyed_account.signer_key()) + .cloned() + .collect::() +} + +/// Return the next KeyedAccount or a NotEnoughAccountKeys error +pub fn next_keyed_account<'a, 'b, I: Iterator>>( + iter: &mut I, +) -> Result { + iter.next().ok_or(InstructionError::NotEnoughAccountKeys) +} + +/// Return true if the first keyed_account is executable, used to determine if +/// the loader should call a program's 'main' +pub fn is_executable(keyed_accounts: &[KeyedAccount]) -> Result { + Ok(!keyed_accounts.is_empty() && keyed_accounts[0].executable()?) +} + +impl<'a, T> State for crate::keyed_account::KeyedAccount<'a> +where + T: serde::Serialize + serde::de::DeserializeOwned, +{ + fn state(&self) -> Result { + self.try_account_ref()?.state() + } + fn set_state(&self, state: &T) -> Result<(), InstructionError> { + self.try_account_ref_mut()?.set_state(state) + } +} + +pub fn from_keyed_account( + keyed_account: &crate::keyed_account::KeyedAccount, +) -> Result { + if !S::check_id(keyed_account.unsigned_key()) { + return Err(InstructionError::InvalidArgument); + } + S::from_account(&*keyed_account.try_account_ref()?).ok_or(InstructionError::InvalidArgument) +} diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index f27f436410..9f89598d5d 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -18,8 +18,10 @@ pub mod genesis_config; pub mod hard_forks; pub mod hash; pub mod inflation; +pub mod keyed_account; pub mod log; pub mod native_loader; +pub mod nonce_keyed_account; pub mod packet; pub mod poh_config; pub mod program_utils; diff --git a/sdk/program/src/nonce/account.rs b/sdk/src/nonce_keyed_account.rs similarity index 94% rename from sdk/program/src/nonce/account.rs rename to sdk/src/nonce_keyed_account.rs index 6c73a110eb..2690b70917 100644 --- a/sdk/program/src/nonce/account.rs +++ b/sdk/src/nonce_keyed_account.rs @@ -1,16 +1,15 @@ -use crate::{ - account::{self, KeyedAccount}, +use crate::keyed_account::KeyedAccount; +use solana_program::{ account_utils::State as AccountUtilsState, instruction::InstructionError, nonce::{self, state::Versions, State}, pubkey::Pubkey, system_instruction::NonceError, - system_program, sysvar::{recent_blockhashes::RecentBlockhashes, rent::Rent}, }; -use std::{cell::RefCell, collections::HashSet}; +use std::collections::HashSet; -pub trait Account { +pub trait NonceKeyedAccount { fn advance_nonce_account( &self, recent_blockhashes: &RecentBlockhashes, @@ -37,7 +36,7 @@ pub trait Account { ) -> Result<(), InstructionError>; } -impl<'a> Account for KeyedAccount<'a> { +impl<'a> NonceKeyedAccount for KeyedAccount<'a> { fn advance_nonce_account( &self, recent_blockhashes: &RecentBlockhashes, @@ -157,25 +156,13 @@ impl<'a> Account for KeyedAccount<'a> { } } -pub fn create_account(lamports: u64) -> RefCell { - RefCell::new( - account::Account::new_data_with_space( - lamports, - &Versions::new_current(State::Uninitialized), - State::size(), - &system_program::id(), - ) - .expect("nonce_account"), - ) -} - /// Convenience function for working with keyed accounts in tests pub fn with_test_keyed_account(lamports: u64, signer: bool, f: F) where F: Fn(&KeyedAccount), { let pubkey = Pubkey::new_unique(); - let account = create_account(lamports); + let account = solana_program::nonce::create_account(lamports); let keyed_account = KeyedAccount::new(&pubkey, signer, &account); f(&keyed_account) } @@ -184,12 +171,13 @@ where mod test { use super::*; use crate::{ - account::KeyedAccount, account_utils::State as AccountUtilsState, + keyed_account::KeyedAccount, nonce::{self, State}, system_instruction::NonceError, sysvar::recent_blockhashes::{create_test_recent_blockhashes, RecentBlockhashes}, }; + use solana_program::{hash::Hash, nonce::utils::verify_nonce_account}; use std::iter::FromIterator; #[test] @@ -881,4 +869,54 @@ mod test { assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); }) } + + #[test] + fn verify_nonce_ok() { + with_test_keyed_account(42, true, |nonce_account| { + let mut signers = HashSet::new(); + signers.insert(nonce_account.signer_key().unwrap()); + let state: State = nonce_account.state().unwrap(); + // New is in Uninitialzed state + assert_eq!(state, State::Uninitialized); + let recent_blockhashes = create_test_recent_blockhashes(0); + let authorized = nonce_account.unsigned_key(); + nonce_account + .initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) + .unwrap(); + assert!(verify_nonce_account( + &nonce_account.account.borrow(), + &recent_blockhashes[0].blockhash, + )); + }); + } + + #[test] + fn verify_nonce_bad_acc_state_fail() { + with_test_keyed_account(42, true, |nonce_account| { + assert!(!verify_nonce_account( + &nonce_account.account.borrow(), + &Hash::default() + )); + }); + } + + #[test] + fn verify_nonce_bad_query_hash_fail() { + with_test_keyed_account(42, true, |nonce_account| { + let mut signers = HashSet::new(); + signers.insert(nonce_account.signer_key().unwrap()); + let state: State = nonce_account.state().unwrap(); + // New is in Uninitialzed state + assert_eq!(state, State::Uninitialized); + let recent_blockhashes = create_test_recent_blockhashes(0); + let authorized = nonce_account.unsigned_key(); + nonce_account + .initialize_nonce_account(&authorized, &recent_blockhashes, &Rent::free()) + .unwrap(); + assert!(!verify_nonce_account( + &nonce_account.account.borrow(), + &recent_blockhashes[1].blockhash, + )); + }); + } }