solana/sdk/src/nonce_account.rs

134 lines
4.4 KiB
Rust

//! Functions related to nonce accounts.
use {
crate::{
account::{AccountSharedData, ReadableAccount},
account_utils::StateMut,
hash::Hash,
nonce::{
state::{Data, Versions},
State,
},
},
std::cell::RefCell,
};
pub fn create_account(lamports: u64) -> RefCell<AccountSharedData> {
RefCell::new(
AccountSharedData::new_data_with_space(
lamports,
&Versions::new(State::Uninitialized),
State::size(),
&crate::system_program::id(),
)
.expect("nonce_account"),
)
}
/// Checks if the recent_blockhash field in Transaction verifies, and returns
/// nonce account data if so.
pub fn verify_nonce_account(
account: &AccountSharedData,
recent_blockhash: &Hash, // Transaction.message.recent_blockhash
) -> Option<Data> {
(account.owner() == &crate::system_program::id())
.then(|| {
StateMut::<Versions>::state(account)
.ok()?
.verify_recent_blockhash(recent_blockhash)
.cloned()
})
.flatten()
}
pub fn lamports_per_signature_of(account: &AccountSharedData) -> Option<u64> {
match StateMut::<Versions>::state(account).ok()?.state() {
State::Initialized(data) => Some(data.fee_calculator.lamports_per_signature),
State::Uninitialized => None,
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::{
fee_calculator::FeeCalculator,
nonce::state::{Data, DurableNonce},
pubkey::Pubkey,
system_program,
},
};
#[test]
fn test_verify_bad_account_owner_fails() {
let program_id = Pubkey::new_unique();
assert_ne!(program_id, crate::system_program::id());
let account = AccountSharedData::new_data_with_space(
42,
&Versions::new(State::Uninitialized),
State::size(),
&program_id,
)
.expect("nonce_account");
assert_eq!(verify_nonce_account(&account, &Hash::default()), None);
}
fn new_nonce_account(versions: Versions) -> AccountSharedData {
AccountSharedData::new_data(
1_000_000, // lamports
&versions, // state
&system_program::id(), // owner
)
.unwrap()
}
#[test]
fn test_verify_nonce_account() {
let blockhash = Hash::from([171; 32]);
let versions = Versions::Legacy(Box::new(State::Uninitialized));
let account = new_nonce_account(versions);
assert_eq!(verify_nonce_account(&account, &blockhash), None);
assert_eq!(verify_nonce_account(&account, &Hash::default()), None);
let versions = Versions::Current(Box::new(State::Uninitialized));
let account = new_nonce_account(versions);
assert_eq!(verify_nonce_account(&account, &blockhash), None);
assert_eq!(verify_nonce_account(&account, &Hash::default()), None);
let durable_nonce = DurableNonce::from_blockhash(&blockhash);
let data = Data {
authority: Pubkey::new_unique(),
durable_nonce,
fee_calculator: FeeCalculator {
lamports_per_signature: 2718,
},
};
let versions = Versions::Legacy(Box::new(State::Initialized(data.clone())));
let account = new_nonce_account(versions);
assert_eq!(verify_nonce_account(&account, &blockhash), None);
assert_eq!(verify_nonce_account(&account, &Hash::default()), None);
assert_eq!(verify_nonce_account(&account, &data.blockhash()), None);
assert_eq!(
verify_nonce_account(&account, durable_nonce.as_hash()),
None
);
let durable_nonce = DurableNonce::from_blockhash(durable_nonce.as_hash());
assert_ne!(data.durable_nonce, durable_nonce);
let data = Data {
durable_nonce,
..data
};
let versions = Versions::Current(Box::new(State::Initialized(data.clone())));
let account = new_nonce_account(versions);
assert_eq!(verify_nonce_account(&account, &blockhash), None);
assert_eq!(verify_nonce_account(&account, &Hash::default()), None);
assert_eq!(
verify_nonce_account(&account, &data.blockhash()),
Some(data.clone())
);
assert_eq!(
verify_nonce_account(&account, durable_nonce.as_hash()),
Some(data)
);
}
}