Account->AccountSharedData (#15691)
This commit is contained in:
committed by
GitHub
parent
61c7ce857e
commit
8a3135d17b
@ -1,6 +1,6 @@
|
||||
use crate::{clock::Epoch, pubkey::Pubkey};
|
||||
use solana_program::{account_info::AccountInfo, sysvar::Sysvar};
|
||||
use std::{cell::RefCell, cmp, fmt, rc::Rc};
|
||||
use std::{cell::Ref, cell::RefCell, cmp, fmt, rc::Rc};
|
||||
|
||||
/// An Account with data that is stored on chain
|
||||
#[repr(C)]
|
||||
@ -21,72 +21,361 @@ pub struct Account {
|
||||
pub rent_epoch: Epoch,
|
||||
}
|
||||
|
||||
/// An Account with data that is stored on chain
|
||||
/// This will become a new in-memory representation of the 'Account' struct data.
|
||||
/// The existing 'Account' structure cannot easily change due to downstream projects.
|
||||
/// This struct will shortly rely on something like the ReadableAccount trait for access to the fields.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Default, AbiExample)]
|
||||
pub struct AccountSharedData {
|
||||
/// lamports in the account
|
||||
pub lamports: u64,
|
||||
/// data held in this account
|
||||
#[serde(with = "serde_bytes")]
|
||||
pub data: Vec<u8>, // will be: Arc<Vec<u8>>,
|
||||
/// the program that owns this account. If executable, the program that loads this account.
|
||||
pub owner: Pubkey,
|
||||
/// this account's data contains a loaded program (and is now read-only)
|
||||
pub executable: bool,
|
||||
/// the epoch at which this account will next owe rent
|
||||
pub rent_epoch: Epoch,
|
||||
}
|
||||
|
||||
/// Compares two ReadableAccounts
|
||||
///
|
||||
/// Returns true if accounts are essentially equivalent as in all fields are equivalent.
|
||||
pub fn accounts_equal<T: ReadableAccount, U: ReadableAccount>(me: &T, other: &U) -> bool {
|
||||
me.lamports() == other.lamports()
|
||||
&& me.data() == other.data()
|
||||
&& me.owner() == other.owner()
|
||||
&& me.executable() == other.executable()
|
||||
&& me.rent_epoch() == other.rent_epoch()
|
||||
}
|
||||
|
||||
impl From<AccountSharedData> for Account {
|
||||
fn from(other: AccountSharedData) -> Self {
|
||||
Self {
|
||||
lamports: other.lamports,
|
||||
data: other.data,
|
||||
owner: other.owner,
|
||||
executable: other.executable,
|
||||
rent_epoch: other.rent_epoch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Account> for AccountSharedData {
|
||||
fn from(other: Account) -> Self {
|
||||
Self {
|
||||
lamports: other.lamports,
|
||||
data: other.data,
|
||||
owner: other.owner,
|
||||
executable: other.executable,
|
||||
rent_epoch: other.rent_epoch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WritableAccount: ReadableAccount {
|
||||
fn set_lamports(&mut self, lamports: u64);
|
||||
fn data_as_mut_slice(&mut self) -> &mut [u8];
|
||||
fn set_owner(&mut self, owner: Pubkey);
|
||||
fn set_executable(&mut self, executable: bool);
|
||||
fn set_rent_epoch(&mut self, epoch: Epoch);
|
||||
fn create(
|
||||
lamports: u64,
|
||||
data: Vec<u8>,
|
||||
owner: Pubkey,
|
||||
executable: bool,
|
||||
rent_epoch: Epoch,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait ReadableAccount: Sized {
|
||||
fn lamports(&self) -> u64;
|
||||
fn data(&self) -> &Vec<u8>;
|
||||
fn owner(&self) -> &Pubkey;
|
||||
fn executable(&self) -> bool;
|
||||
fn rent_epoch(&self) -> Epoch;
|
||||
}
|
||||
|
||||
impl ReadableAccount for Account {
|
||||
fn lamports(&self) -> u64 {
|
||||
self.lamports
|
||||
}
|
||||
fn data(&self) -> &Vec<u8> {
|
||||
&self.data
|
||||
}
|
||||
fn owner(&self) -> &Pubkey {
|
||||
&self.owner
|
||||
}
|
||||
fn executable(&self) -> bool {
|
||||
self.executable
|
||||
}
|
||||
fn rent_epoch(&self) -> Epoch {
|
||||
self.rent_epoch
|
||||
}
|
||||
}
|
||||
|
||||
impl WritableAccount for Account {
|
||||
fn set_lamports(&mut self, lamports: u64) {
|
||||
self.lamports = lamports;
|
||||
}
|
||||
fn data_as_mut_slice(&mut self) -> &mut [u8] {
|
||||
&mut self.data
|
||||
}
|
||||
fn set_owner(&mut self, owner: Pubkey) {
|
||||
self.owner = owner;
|
||||
}
|
||||
fn set_executable(&mut self, executable: bool) {
|
||||
self.executable = executable;
|
||||
}
|
||||
fn set_rent_epoch(&mut self, epoch: Epoch) {
|
||||
self.rent_epoch = epoch;
|
||||
}
|
||||
fn create(
|
||||
lamports: u64,
|
||||
data: Vec<u8>,
|
||||
owner: Pubkey,
|
||||
executable: bool,
|
||||
rent_epoch: Epoch,
|
||||
) -> Self {
|
||||
Account {
|
||||
lamports,
|
||||
data,
|
||||
owner,
|
||||
executable,
|
||||
rent_epoch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WritableAccount for AccountSharedData {
|
||||
fn set_lamports(&mut self, lamports: u64) {
|
||||
self.lamports = lamports;
|
||||
}
|
||||
fn data_as_mut_slice(&mut self) -> &mut [u8] {
|
||||
&mut self.data
|
||||
}
|
||||
fn set_owner(&mut self, owner: Pubkey) {
|
||||
self.owner = owner;
|
||||
}
|
||||
fn set_executable(&mut self, executable: bool) {
|
||||
self.executable = executable;
|
||||
}
|
||||
fn set_rent_epoch(&mut self, epoch: Epoch) {
|
||||
self.rent_epoch = epoch;
|
||||
}
|
||||
fn create(
|
||||
lamports: u64,
|
||||
data: Vec<u8>,
|
||||
owner: Pubkey,
|
||||
executable: bool,
|
||||
rent_epoch: Epoch,
|
||||
) -> Self {
|
||||
AccountSharedData {
|
||||
lamports,
|
||||
data,
|
||||
owner,
|
||||
executable,
|
||||
rent_epoch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadableAccount for AccountSharedData {
|
||||
fn lamports(&self) -> u64 {
|
||||
self.lamports
|
||||
}
|
||||
fn data(&self) -> &Vec<u8> {
|
||||
&self.data
|
||||
}
|
||||
fn owner(&self) -> &Pubkey {
|
||||
&self.owner
|
||||
}
|
||||
fn executable(&self) -> bool {
|
||||
self.executable
|
||||
}
|
||||
fn rent_epoch(&self) -> Epoch {
|
||||
self.rent_epoch
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadableAccount for Ref<'_, AccountSharedData> {
|
||||
fn lamports(&self) -> u64 {
|
||||
self.lamports
|
||||
}
|
||||
fn data(&self) -> &Vec<u8> {
|
||||
&self.data
|
||||
}
|
||||
fn owner(&self) -> &Pubkey {
|
||||
&self.owner
|
||||
}
|
||||
fn executable(&self) -> bool {
|
||||
self.executable
|
||||
}
|
||||
fn rent_epoch(&self) -> Epoch {
|
||||
self.rent_epoch
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadableAccount for Ref<'_, Account> {
|
||||
fn lamports(&self) -> u64 {
|
||||
self.lamports
|
||||
}
|
||||
fn data(&self) -> &Vec<u8> {
|
||||
&self.data
|
||||
}
|
||||
fn owner(&self) -> &Pubkey {
|
||||
&self.owner
|
||||
}
|
||||
fn executable(&self) -> bool {
|
||||
self.executable
|
||||
}
|
||||
fn rent_epoch(&self) -> Epoch {
|
||||
self.rent_epoch
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_fmt<T: ReadableAccount>(item: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let data_len = cmp::min(64, item.data().len());
|
||||
let data_str = if data_len > 0 {
|
||||
format!(" data: {}", hex::encode(item.data()[..data_len].to_vec()))
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"Account {{ lamports: {} data.len: {} owner: {} executable: {} rent_epoch: {}{} }}",
|
||||
item.lamports(),
|
||||
data_len,
|
||||
item.owner(),
|
||||
item.executable(),
|
||||
item.rent_epoch(),
|
||||
data_str,
|
||||
)
|
||||
}
|
||||
|
||||
impl fmt::Debug for Account {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let data_len = cmp::min(64, self.data.len());
|
||||
let data_str = if data_len > 0 {
|
||||
format!(" data: {}", hex::encode(self.data[..data_len].to_vec()))
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"Account {{ lamports: {} data.len: {} owner: {} executable: {} rent_epoch: {}{} }}",
|
||||
self.lamports,
|
||||
self.data.len(),
|
||||
self.owner,
|
||||
self.executable,
|
||||
self.rent_epoch,
|
||||
data_str,
|
||||
)
|
||||
debug_fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AccountSharedData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
debug_fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
fn shared_new<T: WritableAccount>(lamports: u64, space: usize, owner: &Pubkey) -> T {
|
||||
T::create(
|
||||
lamports,
|
||||
vec![0u8; space],
|
||||
*owner,
|
||||
bool::default(),
|
||||
Epoch::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn shared_new_ref<T: WritableAccount>(
|
||||
lamports: u64,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Rc<RefCell<T>> {
|
||||
Rc::new(RefCell::new(shared_new::<T>(lamports, space, owner)))
|
||||
}
|
||||
|
||||
fn shared_new_data<T: serde::Serialize, U: WritableAccount>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<U, bincode::Error> {
|
||||
let data = bincode::serialize(state)?;
|
||||
Ok(U::create(
|
||||
lamports,
|
||||
data,
|
||||
*owner,
|
||||
bool::default(),
|
||||
Epoch::default(),
|
||||
))
|
||||
}
|
||||
fn shared_new_ref_data<T: serde::Serialize, U: WritableAccount>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<U>, bincode::Error> {
|
||||
Ok(RefCell::new(shared_new_data::<T, U>(
|
||||
lamports, state, owner,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn shared_new_data_with_space<T: serde::Serialize, U: WritableAccount>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<U, bincode::Error> {
|
||||
let mut account = shared_new::<U>(lamports, space, owner);
|
||||
|
||||
shared_serialize_data(&mut account, state)?;
|
||||
|
||||
Ok(account)
|
||||
}
|
||||
fn shared_new_ref_data_with_space<T: serde::Serialize, U: WritableAccount>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<U>, bincode::Error> {
|
||||
Ok(RefCell::new(shared_new_data_with_space::<T, U>(
|
||||
lamports, state, space, owner,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn shared_deserialize_data<T: serde::de::DeserializeOwned, U: ReadableAccount>(
|
||||
account: &U,
|
||||
) -> Result<T, bincode::Error> {
|
||||
bincode::deserialize(account.data())
|
||||
}
|
||||
|
||||
fn shared_serialize_data<T: serde::Serialize, U: WritableAccount>(
|
||||
account: &mut U,
|
||||
state: &T,
|
||||
) -> Result<(), bincode::Error> {
|
||||
if bincode::serialized_size(state)? > account.data().len() as u64 {
|
||||
return Err(Box::new(bincode::ErrorKind::SizeLimit));
|
||||
}
|
||||
bincode::serialize_into(&mut account.data_as_mut_slice(), state)
|
||||
}
|
||||
|
||||
impl Account {
|
||||
pub fn new(lamports: u64, space: usize, owner: &Pubkey) -> Self {
|
||||
Self {
|
||||
lamports,
|
||||
data: vec![0u8; space],
|
||||
owner: *owner,
|
||||
..Self::default()
|
||||
}
|
||||
shared_new(lamports, space, owner)
|
||||
}
|
||||
pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
|
||||
Rc::new(RefCell::new(Self::new(lamports, space, owner)))
|
||||
shared_new_ref(lamports, space, owner)
|
||||
}
|
||||
|
||||
pub fn new_data<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<Self, bincode::Error> {
|
||||
let data = bincode::serialize(state)?;
|
||||
Ok(Self {
|
||||
lamports,
|
||||
data,
|
||||
owner: *owner,
|
||||
..Self::default()
|
||||
})
|
||||
shared_new_data(lamports, state, owner)
|
||||
}
|
||||
pub fn new_ref_data<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<Self>, bincode::Error> {
|
||||
Ok(RefCell::new(Self::new_data(lamports, state, owner)?))
|
||||
shared_new_ref_data(lamports, state, owner)
|
||||
}
|
||||
|
||||
pub fn new_data_with_space<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<Self, bincode::Error> {
|
||||
let mut account = Self::new(lamports, space, owner);
|
||||
|
||||
account.serialize_data(state)?;
|
||||
|
||||
Ok(account)
|
||||
shared_new_data_with_space(lamports, state, space, owner)
|
||||
}
|
||||
pub fn new_ref_data_with_space<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
@ -94,20 +383,58 @@ impl Account {
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<Self>, bincode::Error> {
|
||||
Ok(RefCell::new(Self::new_data_with_space(
|
||||
lamports, state, space, owner,
|
||||
)?))
|
||||
shared_new_ref_data_with_space(lamports, state, space, owner)
|
||||
}
|
||||
|
||||
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
|
||||
bincode::deserialize(&self.data)
|
||||
shared_deserialize_data(self)
|
||||
}
|
||||
|
||||
pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
|
||||
if bincode::serialized_size(state)? > self.data.len() as u64 {
|
||||
return Err(Box::new(bincode::ErrorKind::SizeLimit));
|
||||
}
|
||||
bincode::serialize_into(&mut self.data[..], state)
|
||||
shared_serialize_data(self, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountSharedData {
|
||||
pub fn new(lamports: u64, space: usize, owner: &Pubkey) -> Self {
|
||||
shared_new(lamports, space, owner)
|
||||
}
|
||||
pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
|
||||
shared_new_ref(lamports, space, owner)
|
||||
}
|
||||
pub fn new_data<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<Self, bincode::Error> {
|
||||
shared_new_data(lamports, state, owner)
|
||||
}
|
||||
pub fn new_ref_data<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<Self>, bincode::Error> {
|
||||
shared_new_ref_data(lamports, state, owner)
|
||||
}
|
||||
pub fn new_data_with_space<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<Self, bincode::Error> {
|
||||
shared_new_data_with_space(lamports, state, space, owner)
|
||||
}
|
||||
pub fn new_ref_data_with_space<T: serde::Serialize>(
|
||||
lamports: u64,
|
||||
state: &T,
|
||||
space: usize,
|
||||
owner: &Pubkey,
|
||||
) -> Result<RefCell<Self>, bincode::Error> {
|
||||
shared_new_ref_data_with_space(lamports, state, space, owner)
|
||||
}
|
||||
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
|
||||
shared_deserialize_data(self)
|
||||
}
|
||||
pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
|
||||
shared_serialize_data(self, state)
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,18 +442,37 @@ impl Account {
|
||||
pub fn create_account<S: Sysvar>(sysvar: &S, lamports: u64) -> Account {
|
||||
let data_len = S::size_of().max(bincode::serialized_size(sysvar).unwrap() as usize);
|
||||
let mut account = Account::new(lamports, data_len, &solana_program::sysvar::id());
|
||||
to_account::<S>(sysvar, &mut account).unwrap();
|
||||
to_account::<S, Account>(sysvar, &mut account).unwrap();
|
||||
account
|
||||
}
|
||||
|
||||
/// Create an `Account` from a `Sysvar`.
|
||||
pub fn create_account_shared_data<S: Sysvar>(sysvar: &S, lamports: u64) -> AccountSharedData {
|
||||
AccountSharedData::from(create_account(sysvar, lamports))
|
||||
}
|
||||
|
||||
/// Create a `Sysvar` from an `Account`'s data.
|
||||
pub fn from_account<S: Sysvar>(account: &Account) -> Option<S> {
|
||||
bincode::deserialize(&account.data).ok()
|
||||
pub fn from_account<S: Sysvar, T: ReadableAccount>(account: &T) -> Option<S> {
|
||||
bincode::deserialize(account.data()).ok()
|
||||
}
|
||||
|
||||
/// Serialize a `Sysvar` into an `Account`'s data.
|
||||
pub fn to_account<S: Sysvar>(sysvar: &S, account: &mut Account) -> Option<()> {
|
||||
bincode::serialize_into(&mut account.data[..], sysvar).ok()
|
||||
pub fn to_account<S: Sysvar, T: WritableAccount>(sysvar: &S, account: &mut T) -> Option<()> {
|
||||
bincode::serialize_into(account.data_as_mut_slice(), sysvar).ok()
|
||||
}
|
||||
|
||||
/// Return the information required to construct an `AccountInfo`. Used by the
|
||||
/// `AccountInfo` conversion implementations.
|
||||
impl solana_program::account_info::Account for AccountSharedData {
|
||||
fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch) {
|
||||
(
|
||||
&mut self.lamports,
|
||||
&mut self.data,
|
||||
&self.owner,
|
||||
self.executable,
|
||||
self.rent_epoch,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the information required to construct an `AccountInfo`. Used by the
|
||||
@ -144,7 +490,7 @@ impl solana_program::account_info::Account for Account {
|
||||
}
|
||||
|
||||
/// Create `AccountInfo`s
|
||||
pub fn create_account_infos(accounts: &mut [(Pubkey, Account)]) -> Vec<AccountInfo> {
|
||||
pub fn create_account_infos(accounts: &mut [(Pubkey, AccountSharedData)]) -> Vec<AccountInfo> {
|
||||
accounts.iter_mut().map(Into::into).collect()
|
||||
}
|
||||
|
||||
@ -168,3 +514,292 @@ pub fn create_is_signer_account_infos<'a>(
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
fn make_two_accounts(key: &Pubkey) -> (Account, AccountSharedData) {
|
||||
let mut account1 = Account::new(1, 2, &key);
|
||||
account1.executable = true;
|
||||
account1.rent_epoch = 4;
|
||||
let mut account2 = AccountSharedData::new(1, 2, key);
|
||||
account2.executable = true;
|
||||
account2.rent_epoch = 4;
|
||||
assert!(accounts_equal(&account1, &account2));
|
||||
(account1, account2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))"
|
||||
)]
|
||||
fn test_account_deserialize() {
|
||||
let key = Pubkey::new_unique();
|
||||
let (account1, _account2) = make_two_accounts(&key);
|
||||
account1.deserialize_data::<String>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: SizeLimit")]
|
||||
fn test_account_serialize() {
|
||||
let key = Pubkey::new_unique();
|
||||
let (mut account1, _account2) = make_two_accounts(&key);
|
||||
account1.serialize_data(&"hello world").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "called `Result::unwrap()` on an `Err` value: Io(Kind(UnexpectedEof))"
|
||||
)]
|
||||
fn test_account_shared_data_deserialize() {
|
||||
let key = Pubkey::new_unique();
|
||||
let (_account1, account2) = make_two_accounts(&key);
|
||||
account2.deserialize_data::<String>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: SizeLimit")]
|
||||
fn test_account_shared_data_serialize() {
|
||||
let key = Pubkey::new_unique();
|
||||
let (_account1, mut account2) = make_two_accounts(&key);
|
||||
account2.serialize_data(&"hello world").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_account_shared_data() {
|
||||
let key = Pubkey::new_unique();
|
||||
let (account1, account2) = make_two_accounts(&key);
|
||||
assert!(accounts_equal(&account1, &account2));
|
||||
let account = account1;
|
||||
assert_eq!(account.lamports, 1);
|
||||
assert_eq!(account.lamports(), 1);
|
||||
assert_eq!(account.data.len(), 2);
|
||||
assert_eq!(account.data().len(), 2);
|
||||
assert_eq!(account.owner, key);
|
||||
assert_eq!(account.owner(), &key);
|
||||
assert_eq!(account.executable, true);
|
||||
assert_eq!(account.executable(), true);
|
||||
assert_eq!(account.rent_epoch, 4);
|
||||
assert_eq!(account.rent_epoch(), 4);
|
||||
let account = account2;
|
||||
assert_eq!(account.lamports, 1);
|
||||
assert_eq!(account.lamports(), 1);
|
||||
assert_eq!(account.data.len(), 2);
|
||||
assert_eq!(account.data().len(), 2);
|
||||
assert_eq!(account.owner, key);
|
||||
assert_eq!(account.owner(), &key);
|
||||
assert_eq!(account.executable, true);
|
||||
assert_eq!(account.executable(), true);
|
||||
assert_eq!(account.rent_epoch, 4);
|
||||
assert_eq!(account.rent_epoch(), 4);
|
||||
}
|
||||
|
||||
// test clone and from for both types against expected
|
||||
fn test_equal(
|
||||
should_be_equal: bool,
|
||||
account1: &Account,
|
||||
account2: &AccountSharedData,
|
||||
account_expected: &Account,
|
||||
) {
|
||||
assert_eq!(should_be_equal, accounts_equal(account1, account2));
|
||||
if should_be_equal {
|
||||
assert!(accounts_equal(account_expected, account2));
|
||||
}
|
||||
assert_eq!(
|
||||
accounts_equal(account_expected, account1),
|
||||
accounts_equal(account_expected, &account1.clone())
|
||||
);
|
||||
assert_eq!(
|
||||
accounts_equal(account_expected, account2),
|
||||
accounts_equal(account_expected, &account2.clone())
|
||||
);
|
||||
assert_eq!(
|
||||
accounts_equal(account_expected, account1),
|
||||
accounts_equal(account_expected, &AccountSharedData::from(account1.clone()))
|
||||
);
|
||||
assert_eq!(
|
||||
accounts_equal(account_expected, account2),
|
||||
accounts_equal(account_expected, &Account::from(account2.clone()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::redundant_clone)]
|
||||
fn test_account_shared_data_all_fields() {
|
||||
let key = Pubkey::new_unique();
|
||||
let key2 = Pubkey::new_unique();
|
||||
let key3 = Pubkey::new_unique();
|
||||
let (mut account1, mut account2) = make_two_accounts(&key);
|
||||
assert!(accounts_equal(&account1, &account2));
|
||||
|
||||
let mut account_expected = account1.clone();
|
||||
assert!(accounts_equal(&account1, &account_expected));
|
||||
assert!(accounts_equal(&account1, &account2.clone())); // test the clone here
|
||||
|
||||
for field_index in 0..5 {
|
||||
for pass in 0..4 {
|
||||
if field_index == 0 {
|
||||
if pass == 0 {
|
||||
account1.lamports += 1;
|
||||
} else if pass == 1 {
|
||||
account_expected.lamports += 1;
|
||||
account2.set_lamports(account2.lamports + 1);
|
||||
} else if pass == 2 {
|
||||
account1.set_lamports(account1.lamports + 1);
|
||||
} else if pass == 3 {
|
||||
account_expected.lamports += 1;
|
||||
account2.lamports += 1;
|
||||
}
|
||||
} else if field_index == 1 {
|
||||
if pass == 0 {
|
||||
account1.data[0] += 1;
|
||||
} else if pass == 1 {
|
||||
account_expected.data[0] += 1;
|
||||
account2.data_as_mut_slice()[0] = account2.data[0] + 1;
|
||||
} else if pass == 2 {
|
||||
account1.data_as_mut_slice()[0] = account1.data[0] + 1;
|
||||
} else if pass == 3 {
|
||||
account_expected.data[0] += 1;
|
||||
account2.data[0] += 1;
|
||||
}
|
||||
} else if field_index == 2 {
|
||||
if pass == 0 {
|
||||
account1.owner = key2;
|
||||
} else if pass == 1 {
|
||||
account_expected.owner = key2;
|
||||
account2.set_owner(key2);
|
||||
} else if pass == 2 {
|
||||
account1.set_owner(key3);
|
||||
} else if pass == 3 {
|
||||
account_expected.owner = key3;
|
||||
account2.owner = key3;
|
||||
}
|
||||
} else if field_index == 3 {
|
||||
if pass == 0 {
|
||||
account1.executable = !account1.executable;
|
||||
} else if pass == 1 {
|
||||
account_expected.executable = !account_expected.executable;
|
||||
account2.set_executable(!account2.executable);
|
||||
} else if pass == 2 {
|
||||
account1.set_executable(!account1.executable);
|
||||
} else if pass == 3 {
|
||||
account_expected.executable = !account_expected.executable;
|
||||
account2.executable = !account2.executable;
|
||||
}
|
||||
} else if field_index == 4 {
|
||||
if pass == 0 {
|
||||
account1.rent_epoch += 1;
|
||||
} else if pass == 1 {
|
||||
account_expected.rent_epoch += 1;
|
||||
account2.set_rent_epoch(account2.rent_epoch + 1);
|
||||
} else if pass == 2 {
|
||||
account1.set_rent_epoch(account1.rent_epoch + 1);
|
||||
} else if pass == 3 {
|
||||
account_expected.rent_epoch += 1;
|
||||
account2.rent_epoch += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let should_be_equal = pass == 1 || pass == 3;
|
||||
test_equal(should_be_equal, &account1, &account2, &account_expected);
|
||||
|
||||
// test new_ref
|
||||
if should_be_equal {
|
||||
assert!(accounts_equal(
|
||||
&Account::new_ref(
|
||||
account_expected.lamports(),
|
||||
account_expected.data().len(),
|
||||
account_expected.owner()
|
||||
)
|
||||
.borrow(),
|
||||
&AccountSharedData::new_ref(
|
||||
account_expected.lamports(),
|
||||
account_expected.data().len(),
|
||||
account_expected.owner()
|
||||
)
|
||||
.borrow()
|
||||
));
|
||||
|
||||
{
|
||||
// test new_data
|
||||
let account1_with_data = Account::new_data(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
account_expected.owner(),
|
||||
)
|
||||
.unwrap();
|
||||
let account2_with_data = AccountSharedData::new_data(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
account_expected.owner(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(accounts_equal(&account1_with_data, &account2_with_data));
|
||||
assert_eq!(
|
||||
account1_with_data.deserialize_data::<u8>().unwrap(),
|
||||
account2_with_data.deserialize_data::<u8>().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
// test new_data_with_space
|
||||
assert!(accounts_equal(
|
||||
&Account::new_data_with_space(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
1,
|
||||
account_expected.owner()
|
||||
)
|
||||
.unwrap(),
|
||||
&AccountSharedData::new_data_with_space(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
1,
|
||||
account_expected.owner()
|
||||
)
|
||||
.unwrap()
|
||||
));
|
||||
|
||||
// test new_ref_data
|
||||
assert!(accounts_equal(
|
||||
&Account::new_ref_data(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
account_expected.owner()
|
||||
)
|
||||
.unwrap()
|
||||
.borrow(),
|
||||
&AccountSharedData::new_ref_data(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
account_expected.owner()
|
||||
)
|
||||
.unwrap()
|
||||
.borrow()
|
||||
));
|
||||
|
||||
//new_ref_data_with_space
|
||||
assert!(accounts_equal(
|
||||
&Account::new_ref_data_with_space(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
1,
|
||||
account_expected.owner()
|
||||
)
|
||||
.unwrap()
|
||||
.borrow(),
|
||||
&AccountSharedData::new_ref_data_with_space(
|
||||
account_expected.lamports(),
|
||||
&account_expected.data()[0],
|
||||
1,
|
||||
account_expected.owner()
|
||||
)
|
||||
.unwrap()
|
||||
.borrow()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! useful extras for Account state
|
||||
use crate::{account::Account, instruction::InstructionError};
|
||||
use crate::{account::Account, account::AccountSharedData, instruction::InstructionError};
|
||||
use bincode::ErrorKind;
|
||||
use std::cell::Ref;
|
||||
|
||||
/// Convenience trait to covert bincode errors to instruction errors.
|
||||
pub trait StateMut<T> {
|
||||
@ -28,20 +29,49 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> StateMut<T> for AccountSharedData
|
||||
where
|
||||
T: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn state(&self) -> Result<T, InstructionError> {
|
||||
self.deserialize_data()
|
||||
.map_err(|_| InstructionError::InvalidAccountData)
|
||||
}
|
||||
fn set_state(&mut self, state: &T) -> Result<(), InstructionError> {
|
||||
self.serialize_data(state).map_err(|err| match *err {
|
||||
ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
|
||||
_ => InstructionError::GenericError,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> StateMut<T> for Ref<'_, AccountSharedData>
|
||||
where
|
||||
T: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn state(&self) -> Result<T, InstructionError> {
|
||||
self.deserialize_data()
|
||||
.map_err(|_| InstructionError::InvalidAccountData)
|
||||
}
|
||||
fn set_state(&mut self, _state: &T) -> Result<(), InstructionError> {
|
||||
panic!("illegal");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{account::Account, pubkey::Pubkey};
|
||||
use crate::{account::AccountSharedData, pubkey::Pubkey};
|
||||
|
||||
#[test]
|
||||
fn test_account_state() {
|
||||
let state = 42u64;
|
||||
|
||||
assert!(Account::default().set_state(&state).is_err());
|
||||
let res = Account::default().state() as Result<u64, InstructionError>;
|
||||
assert!(AccountSharedData::default().set_state(&state).is_err());
|
||||
let res = AccountSharedData::default().state() as Result<u64, InstructionError>;
|
||||
assert!(res.is_err());
|
||||
|
||||
let mut account = Account::new(0, std::mem::size_of::<u64>(), &Pubkey::default());
|
||||
let mut account = AccountSharedData::new(0, std::mem::size_of::<u64>(), &Pubkey::default());
|
||||
|
||||
assert!(account.set_state(&state).is_ok());
|
||||
let stored_state: u64 = account.state().unwrap();
|
||||
|
@ -1,21 +1,22 @@
|
||||
use crate::account::Account;
|
||||
use crate::account::AccountSharedData;
|
||||
use crate::account::ReadableAccount;
|
||||
pub use solana_program::feature::*;
|
||||
|
||||
pub fn from_account(account: &Account) -> Option<Feature> {
|
||||
if account.owner != id() {
|
||||
pub fn from_account<T: ReadableAccount>(account: &T) -> Option<Feature> {
|
||||
if account.owner() != &id() {
|
||||
None
|
||||
} else {
|
||||
bincode::deserialize(&account.data).ok()
|
||||
bincode::deserialize(account.data()).ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_account(feature: &Feature, account: &mut Account) -> Option<()> {
|
||||
pub fn to_account(feature: &Feature, account: &mut AccountSharedData) -> Option<()> {
|
||||
bincode::serialize_into(&mut account.data[..], feature).ok()
|
||||
}
|
||||
|
||||
pub fn create_account(feature: &Feature, lamports: u64) -> Account {
|
||||
pub fn create_account(feature: &Feature, lamports: u64) -> AccountSharedData {
|
||||
let data_len = Feature::size_of().max(bincode::serialized_size(feature).unwrap() as usize);
|
||||
let mut account = Account::new(lamports, data_len, &id());
|
||||
let mut account = AccountSharedData::new(lamports, data_len, &id());
|
||||
to_account(feature, &mut account).unwrap();
|
||||
account
|
||||
}
|
||||
@ -26,7 +27,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn feature_deserialize_none() {
|
||||
let just_initialized = Account::new(42, Feature::size_of(), &id());
|
||||
let just_initialized = AccountSharedData::new(42, Feature::size_of(), &id());
|
||||
assert_eq!(
|
||||
from_account(&just_initialized),
|
||||
Some(Feature { activated_at: None })
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
account::Account,
|
||||
account::AccountSharedData,
|
||||
clock::{UnixTimestamp, DEFAULT_TICKS_PER_SLOT},
|
||||
epoch_schedule::EpochSchedule,
|
||||
fee_calculator::FeeRateGovernor,
|
||||
@ -98,7 +99,7 @@ pub fn create_genesis_config(lamports: u64) -> (GenesisConfig, Keypair) {
|
||||
GenesisConfig::new(
|
||||
&[(
|
||||
faucet_keypair.pubkey(),
|
||||
Account::new(lamports, 0, &system_program::id()),
|
||||
AccountSharedData::new(lamports, 0, &system_program::id()),
|
||||
)],
|
||||
&[],
|
||||
),
|
||||
@ -131,13 +132,14 @@ impl Default for GenesisConfig {
|
||||
|
||||
impl GenesisConfig {
|
||||
pub fn new(
|
||||
accounts: &[(Pubkey, Account)],
|
||||
accounts: &[(Pubkey, AccountSharedData)],
|
||||
native_instruction_processors: &[(String, Pubkey)],
|
||||
) -> Self {
|
||||
Self {
|
||||
accounts: accounts
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|(key, account)| (key, Account::from(account)))
|
||||
.collect::<BTreeMap<Pubkey, Account>>(),
|
||||
native_instruction_processors: native_instruction_processors.to_vec(),
|
||||
..GenesisConfig::default()
|
||||
@ -201,8 +203,8 @@ impl GenesisConfig {
|
||||
file.write_all(&serialized)
|
||||
}
|
||||
|
||||
pub fn add_account(&mut self, pubkey: Pubkey, account: Account) {
|
||||
self.accounts.insert(pubkey, account);
|
||||
pub fn add_account(&mut self, pubkey: Pubkey, account: AccountSharedData) {
|
||||
self.accounts.insert(pubkey, Account::from(account));
|
||||
}
|
||||
|
||||
pub fn add_native_instruction_processor(&mut self, name: String, program_id: Pubkey) {
|
||||
@ -318,11 +320,11 @@ mod tests {
|
||||
let mut config = GenesisConfig::default();
|
||||
config.add_account(
|
||||
faucet_keypair.pubkey(),
|
||||
Account::new(10_000, 0, &Pubkey::default()),
|
||||
AccountSharedData::new(10_000, 0, &Pubkey::default()),
|
||||
);
|
||||
config.add_account(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
Account::new(1, 0, &Pubkey::default()),
|
||||
AccountSharedData::new(1, 0, &Pubkey::default()),
|
||||
);
|
||||
config.add_native_instruction_processor("hi".to_string(), solana_sdk::pubkey::new_rand());
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
account::{from_account, Account},
|
||||
account::{from_account, AccountSharedData},
|
||||
account_utils::{State, StateMut},
|
||||
};
|
||||
use solana_program::{clock::Epoch, instruction::InstructionError, pubkey::Pubkey, sysvar::Sysvar};
|
||||
@ -14,7 +14,7 @@ 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<Account>,
|
||||
pub account: &'a RefCell<AccountSharedData>,
|
||||
}
|
||||
|
||||
impl<'a> KeyedAccount<'a> {
|
||||
@ -58,26 +58,26 @@ impl<'a> KeyedAccount<'a> {
|
||||
Ok(self.try_borrow()?.rent_epoch)
|
||||
}
|
||||
|
||||
pub fn try_account_ref(&'a self) -> Result<Ref<Account>, InstructionError> {
|
||||
pub fn try_account_ref(&'a self) -> Result<Ref<AccountSharedData>, InstructionError> {
|
||||
self.try_borrow()
|
||||
}
|
||||
|
||||
pub fn try_account_ref_mut(&'a self) -> Result<RefMut<Account>, InstructionError> {
|
||||
pub fn try_account_ref_mut(&'a self) -> Result<RefMut<AccountSharedData>, InstructionError> {
|
||||
self.try_borrow_mut()
|
||||
}
|
||||
|
||||
fn try_borrow(&self) -> Result<Ref<Account>, InstructionError> {
|
||||
fn try_borrow(&self) -> Result<Ref<AccountSharedData>, InstructionError> {
|
||||
self.account
|
||||
.try_borrow()
|
||||
.map_err(|_| InstructionError::AccountBorrowFailed)
|
||||
}
|
||||
fn try_borrow_mut(&self) -> Result<RefMut<Account>, InstructionError> {
|
||||
fn try_borrow_mut(&self) -> Result<RefMut<AccountSharedData>, InstructionError> {
|
||||
self.account
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowFailed)
|
||||
}
|
||||
|
||||
pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<Account>) -> Self {
|
||||
pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<AccountSharedData>) -> Self {
|
||||
Self {
|
||||
is_signer,
|
||||
is_writable: true,
|
||||
@ -86,7 +86,11 @@ impl<'a> KeyedAccount<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_readonly(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<Account>) -> Self {
|
||||
pub fn new_readonly(
|
||||
key: &'a Pubkey,
|
||||
is_signer: bool,
|
||||
account: &'a RefCell<AccountSharedData>,
|
||||
) -> Self {
|
||||
Self {
|
||||
is_signer,
|
||||
is_writable: false,
|
||||
@ -102,8 +106,8 @@ impl<'a> PartialEq for KeyedAccount<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
fn from((key, account): (&'a Pubkey, &'a RefCell<Account>)) -> Self {
|
||||
impl<'a> From<(&'a Pubkey, &'a RefCell<AccountSharedData>)> for KeyedAccount<'a> {
|
||||
fn from((key, account): (&'a Pubkey, &'a RefCell<AccountSharedData>)) -> Self {
|
||||
Self {
|
||||
is_signer: false,
|
||||
is_writable: true,
|
||||
@ -113,8 +117,8 @@ impl<'a> From<(&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(&'a Pubkey, bool, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
fn from((key, is_signer, account): (&'a Pubkey, bool, &'a RefCell<Account>)) -> Self {
|
||||
impl<'a> From<(&'a Pubkey, bool, &'a RefCell<AccountSharedData>)> for KeyedAccount<'a> {
|
||||
fn from((key, is_signer, account): (&'a Pubkey, bool, &'a RefCell<AccountSharedData>)) -> Self {
|
||||
Self {
|
||||
is_signer,
|
||||
is_writable: true,
|
||||
@ -124,8 +128,8 @@ impl<'a> From<(&'a Pubkey, bool, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a (&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
fn from((key, account): &'a (&'a Pubkey, &'a RefCell<Account>)) -> Self {
|
||||
impl<'a> From<&'a (&'a Pubkey, &'a RefCell<AccountSharedData>)> for KeyedAccount<'a> {
|
||||
fn from((key, account): &'a (&'a Pubkey, &'a RefCell<AccountSharedData>)) -> Self {
|
||||
Self {
|
||||
is_signer: false,
|
||||
is_writable: true,
|
||||
@ -136,13 +140,13 @@ impl<'a> From<&'a (&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> {
|
||||
}
|
||||
|
||||
pub fn create_keyed_accounts<'a>(
|
||||
accounts: &'a [(&'a Pubkey, &'a RefCell<Account>)],
|
||||
accounts: &'a [(&'a Pubkey, &'a RefCell<AccountSharedData>)],
|
||||
) -> Vec<KeyedAccount<'a>> {
|
||||
accounts.iter().map(Into::into).collect()
|
||||
}
|
||||
|
||||
pub fn create_keyed_is_signer_accounts<'a>(
|
||||
accounts: &'a [(&'a Pubkey, bool, &'a RefCell<Account>)],
|
||||
accounts: &'a [(&'a Pubkey, bool, &'a RefCell<AccountSharedData>)],
|
||||
) -> Vec<KeyedAccount<'a>> {
|
||||
accounts
|
||||
.iter()
|
||||
@ -156,7 +160,7 @@ pub fn create_keyed_is_signer_accounts<'a>(
|
||||
}
|
||||
|
||||
pub fn create_keyed_readonly_accounts(
|
||||
accounts: &[(Pubkey, RefCell<Account>)],
|
||||
accounts: &[(Pubkey, RefCell<AccountSharedData>)],
|
||||
) -> Vec<KeyedAccount> {
|
||||
accounts
|
||||
.iter()
|
||||
@ -212,7 +216,8 @@ pub fn from_keyed_account<S: Sysvar>(
|
||||
if !S::check_id(keyed_account.unsigned_key()) {
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
from_account::<S>(&*keyed_account.try_account_ref()?).ok_or(InstructionError::InvalidArgument)
|
||||
from_account::<S, AccountSharedData>(&*keyed_account.try_account_ref()?)
|
||||
.ok_or(InstructionError::InvalidArgument)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -244,12 +249,12 @@ mod tests {
|
||||
let wrong_key = Pubkey::new_unique();
|
||||
|
||||
let account = create_account(&test_sysvar, 42);
|
||||
let test_sysvar = from_account::<TestSysvar>(&account).unwrap();
|
||||
let test_sysvar = from_account::<TestSysvar, _>(&account).unwrap();
|
||||
assert_eq!(test_sysvar, TestSysvar::default());
|
||||
|
||||
let mut account = Account::new(42, TestSysvar::size_of(), &key);
|
||||
let mut account = AccountSharedData::new(42, TestSysvar::size_of(), &key);
|
||||
to_account(&test_sysvar, &mut account).unwrap();
|
||||
let test_sysvar = from_account::<TestSysvar>(&account).unwrap();
|
||||
let test_sysvar = from_account::<TestSysvar, _>(&account).unwrap();
|
||||
assert_eq!(test_sysvar, TestSysvar::default());
|
||||
|
||||
let account = RefCell::new(account);
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::account::Account;
|
||||
use crate::account::AccountSharedData;
|
||||
|
||||
crate::declare_id!("NativeLoader1111111111111111111111111111111");
|
||||
|
||||
/// Create an executable account with the given shared object name.
|
||||
pub fn create_loadable_account(name: &str, lamports: u64) -> Account {
|
||||
Account {
|
||||
pub fn create_loadable_account(name: &str, lamports: u64) -> AccountSharedData {
|
||||
AccountSharedData {
|
||||
lamports,
|
||||
owner: id(),
|
||||
data: name.as_bytes().to_vec(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
account::Account,
|
||||
account::AccountSharedData,
|
||||
account_utils::StateMut,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
@ -7,9 +7,9 @@ use crate::{
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub fn create_account(lamports: u64) -> RefCell<Account> {
|
||||
pub fn create_account(lamports: u64) -> RefCell<AccountSharedData> {
|
||||
RefCell::new(
|
||||
Account::new_data_with_space(
|
||||
AccountSharedData::new_data_with_space(
|
||||
lamports,
|
||||
&Versions::new_current(State::Uninitialized),
|
||||
State::size(),
|
||||
@ -19,7 +19,7 @@ pub fn create_account(lamports: u64) -> RefCell<Account> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn verify_nonce_account(acc: &Account, hash: &Hash) -> bool {
|
||||
pub fn verify_nonce_account(acc: &AccountSharedData, hash: &Hash) -> bool {
|
||||
if acc.owner != crate::system_program::id() {
|
||||
return false;
|
||||
}
|
||||
@ -29,7 +29,7 @@ pub fn verify_nonce_account(acc: &Account, hash: &Hash) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fee_calculator_of(account: &Account) -> Option<FeeCalculator> {
|
||||
pub fn fee_calculator_of(account: &AccountSharedData) -> Option<FeeCalculator> {
|
||||
let state = StateMut::<Versions>::state(account)
|
||||
.ok()?
|
||||
.convert_to_current();
|
||||
@ -48,7 +48,7 @@ mod tests {
|
||||
fn test_verify_bad_account_owner_fails() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
assert_ne!(program_id, crate::system_program::id());
|
||||
let account = Account::new_data_with_space(
|
||||
let account = AccountSharedData::new_data_with_space(
|
||||
42,
|
||||
&Versions::new_current(State::Uninitialized),
|
||||
State::size(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
account::AccountSharedData,
|
||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||
keyed_account::KeyedAccount,
|
||||
message::Message,
|
||||
@ -36,7 +36,7 @@ pub trait InvokeContext {
|
||||
&mut self,
|
||||
message: &Message,
|
||||
instruction: &CompiledInstruction,
|
||||
accounts: &[Rc<RefCell<Account>>],
|
||||
accounts: &[Rc<RefCell<AccountSharedData>>],
|
||||
caller_pivileges: Option<&[bool]>,
|
||||
) -> Result<(), InstructionError>;
|
||||
/// Get the program ID of the currently executing program
|
||||
@ -59,7 +59,7 @@ pub trait InvokeContext {
|
||||
/// Get the bank's active feature set
|
||||
fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
|
||||
/// Get an account from a pre-account
|
||||
fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<Account>>;
|
||||
fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<AccountSharedData>>;
|
||||
/// Update timing
|
||||
fn update_timing(
|
||||
&mut self,
|
||||
@ -305,7 +305,7 @@ impl InvokeContext for MockInvokeContext {
|
||||
&mut self,
|
||||
_message: &Message,
|
||||
_instruction: &CompiledInstruction,
|
||||
_accounts: &[Rc<RefCell<Account>>],
|
||||
_accounts: &[Rc<RefCell<AccountSharedData>>],
|
||||
_caller_pivileges: Option<&[bool]>,
|
||||
) -> Result<(), InstructionError> {
|
||||
Ok(())
|
||||
@ -333,7 +333,7 @@ impl InvokeContext for MockInvokeContext {
|
||||
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
|
||||
true
|
||||
}
|
||||
fn get_account(&self, _pubkey: &Pubkey) -> Option<RefCell<Account>> {
|
||||
fn get_account(&self, _pubkey: &Pubkey) -> Option<RefCell<AccountSharedData>> {
|
||||
None
|
||||
}
|
||||
fn update_timing(
|
||||
|
@ -1,10 +1,13 @@
|
||||
use crate::account::{create_account, to_account, Account};
|
||||
use crate::account::{create_account_shared_data, to_account, AccountSharedData};
|
||||
use solana_program::sysvar::recent_blockhashes::{
|
||||
IntoIterSorted, IterItem, RecentBlockhashes, MAX_ENTRIES,
|
||||
};
|
||||
use std::{collections::BinaryHeap, iter::FromIterator};
|
||||
|
||||
pub fn update_account<'a, I>(account: &mut Account, recent_blockhash_iter: I) -> Option<()>
|
||||
pub fn update_account<'a, I>(
|
||||
account: &mut AccountSharedData,
|
||||
recent_blockhash_iter: I,
|
||||
) -> Option<()>
|
||||
where
|
||||
I: IntoIterator<Item = IterItem<'a>>,
|
||||
{
|
||||
@ -15,11 +18,12 @@ where
|
||||
to_account(&recent_blockhashes, account)
|
||||
}
|
||||
|
||||
pub fn create_account_with_data<'a, I>(lamports: u64, recent_blockhash_iter: I) -> Account
|
||||
pub fn create_account_with_data<'a, I>(lamports: u64, recent_blockhash_iter: I) -> AccountSharedData
|
||||
where
|
||||
I: IntoIterator<Item = IterItem<'a>>,
|
||||
{
|
||||
let mut account = create_account::<RecentBlockhashes>(&RecentBlockhashes::default(), lamports);
|
||||
let mut account =
|
||||
create_account_shared_data::<RecentBlockhashes>(&RecentBlockhashes::default(), lamports);
|
||||
update_account(&mut account, recent_blockhash_iter).unwrap();
|
||||
account
|
||||
}
|
||||
@ -38,7 +42,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_create_account_empty() {
|
||||
let account = create_account_with_data(42, vec![].into_iter());
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes>(&account).unwrap();
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes, _>(&account).unwrap();
|
||||
assert_eq!(recent_blockhashes, RecentBlockhashes::default());
|
||||
}
|
||||
|
||||
@ -50,7 +54,7 @@ mod tests {
|
||||
42,
|
||||
vec![IterItem(0u64, &def_hash, &def_fees); MAX_ENTRIES].into_iter(),
|
||||
);
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes>(&account).unwrap();
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes, _>(&account).unwrap();
|
||||
assert_eq!(recent_blockhashes.len(), MAX_ENTRIES);
|
||||
}
|
||||
|
||||
@ -62,7 +66,7 @@ mod tests {
|
||||
42,
|
||||
vec![IterItem(0u64, &def_hash, &def_fees); MAX_ENTRIES + 1].into_iter(),
|
||||
);
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes>(&account).unwrap();
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes, _>(&account).unwrap();
|
||||
assert_eq!(recent_blockhashes.len(), MAX_ENTRIES);
|
||||
}
|
||||
|
||||
@ -87,7 +91,7 @@ mod tests {
|
||||
.iter()
|
||||
.map(|(i, hash)| IterItem(*i, hash, &def_fees)),
|
||||
);
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes>(&account).unwrap();
|
||||
let recent_blockhashes = from_account::<RecentBlockhashes, _>(&account).unwrap();
|
||||
|
||||
let mut unsorted_recent_blockhashes: Vec<_> = unsorted_blocks
|
||||
.iter()
|
||||
|
Reference in New Issue
Block a user