-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move decode_error/clock/hash/sanitize into program-sdk
- Loading branch information
Showing
38 changed files
with
3,821 additions
and
3,742 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
use crate::{clock::Epoch, instruction::InstructionError, pubkey::Pubkey}; | ||
use std::{ | ||
cell::{Ref, RefCell, RefMut}, | ||
cmp, fmt, | ||
iter::FromIterator, | ||
rc::Rc, | ||
}; | ||
|
||
/// An Account with data that is stored on chain | ||
#[repr(C)] | ||
#[frozen_abi(digest = "By9FhuLAM947tkLxbTVQru9ZKTrRQuvCR5W387nPSLNu")] | ||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Default, AbiExample)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Account { | ||
/// lamports in the account | ||
pub lamports: u64, | ||
/// data held in this account | ||
#[serde(with = "serde_bytes")] | ||
pub data: 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, | ||
} | ||
|
||
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, | ||
) | ||
} | ||
} | ||
|
||
impl Account { | ||
pub fn new(lamports: u64, space: usize, owner: &Pubkey) -> Self { | ||
Self { | ||
lamports, | ||
data: vec![0u8; space], | ||
owner: *owner, | ||
..Self::default() | ||
} | ||
} | ||
pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> { | ||
Rc::new(RefCell::new(Self::new(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() | ||
}) | ||
} | ||
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)?)) | ||
} | ||
|
||
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) | ||
} | ||
pub fn new_ref_data_with_space<T: serde::Serialize>( | ||
lamports: u64, | ||
state: &T, | ||
space: usize, | ||
owner: &Pubkey, | ||
) -> Result<RefCell<Self>, bincode::Error> { | ||
Ok(RefCell::new(Self::new_data_with_space( | ||
lamports, state, space, owner, | ||
)?)) | ||
} | ||
|
||
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> { | ||
bincode::deserialize(&self.data) | ||
} | ||
|
||
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) | ||
} | ||
} | ||
|
||
#[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<Account>, | ||
} | ||
|
||
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<u64, InstructionError> { | ||
Ok(self.try_borrow()?.lamports) | ||
} | ||
|
||
pub fn data_len(&self) -> Result<usize, InstructionError> { | ||
Ok(self.try_borrow()?.data.len()) | ||
} | ||
|
||
pub fn data_is_empty(&self) -> Result<bool, InstructionError> { | ||
Ok(self.try_borrow()?.data.is_empty()) | ||
} | ||
|
||
pub fn owner(&self) -> Result<Pubkey, InstructionError> { | ||
Ok(self.try_borrow()?.owner) | ||
} | ||
|
||
pub fn executable(&self) -> Result<bool, InstructionError> { | ||
Ok(self.try_borrow()?.executable) | ||
} | ||
|
||
pub fn rent_epoch(&self) -> Result<Epoch, InstructionError> { | ||
Ok(self.try_borrow()?.rent_epoch) | ||
} | ||
|
||
pub fn try_account_ref(&'a self) -> Result<Ref<Account>, InstructionError> { | ||
self.try_borrow() | ||
} | ||
|
||
pub fn try_account_ref_mut(&'a self) -> Result<RefMut<Account>, InstructionError> { | ||
self.try_borrow_mut() | ||
} | ||
|
||
fn try_borrow(&self) -> Result<Ref<Account>, InstructionError> { | ||
self.account | ||
.try_borrow() | ||
.map_err(|_| InstructionError::AccountBorrowFailed) | ||
} | ||
fn try_borrow_mut(&self) -> Result<RefMut<Account>, InstructionError> { | ||
self.account | ||
.try_borrow_mut() | ||
.map_err(|_| InstructionError::AccountBorrowFailed) | ||
} | ||
|
||
pub fn new(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<Account>) -> Self { | ||
Self { | ||
is_signer, | ||
is_writable: true, | ||
key, | ||
account, | ||
} | ||
} | ||
|
||
pub fn new_readonly(key: &'a Pubkey, is_signer: bool, account: &'a RefCell<Account>) -> 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<Account>)> for KeyedAccount<'a> { | ||
fn from((key, account): (&'a Pubkey, &'a RefCell<Account>)) -> Self { | ||
Self { | ||
is_signer: false, | ||
is_writable: true, | ||
key, | ||
account, | ||
} | ||
} | ||
} | ||
|
||
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 { | ||
Self { | ||
is_signer, | ||
is_writable: true, | ||
key, | ||
account, | ||
} | ||
} | ||
} | ||
|
||
impl<'a> From<&'a (&'a Pubkey, &'a RefCell<Account>)> for KeyedAccount<'a> { | ||
fn from((key, account): &'a (&'a Pubkey, &'a RefCell<Account>)) -> Self { | ||
Self { | ||
is_signer: false, | ||
is_writable: true, | ||
key, | ||
account, | ||
} | ||
} | ||
} | ||
|
||
pub fn create_keyed_accounts<'a>( | ||
accounts: &'a [(&'a Pubkey, &'a RefCell<Account>)], | ||
) -> 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>)], | ||
) -> Vec<KeyedAccount<'a>> { | ||
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<Account>)], | ||
) -> Vec<KeyedAccount> { | ||
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<A>(keyed_accounts: &[KeyedAccount]) -> A | ||
where | ||
A: FromIterator<Pubkey>, | ||
{ | ||
keyed_accounts | ||
.iter() | ||
.filter_map(|keyed_account| keyed_account.signer_key()) | ||
.cloned() | ||
.collect::<A>() | ||
} | ||
|
||
/// Return the next KeyedAccount or a NotEnoughAccountKeys error | ||
pub fn next_keyed_account<'a, 'b, I: Iterator<Item = &'a KeyedAccount<'b>>>( | ||
iter: &mut I, | ||
) -> Result<I::Item, InstructionError> { | ||
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<bool, InstructionError> { | ||
Ok(!keyed_accounts.is_empty() && keyed_accounts[0].executable()?) | ||
} |
Oops, something went wrong.