Skip to content

Commit

Permalink
Move decode_error/clock/hash/sanitize into program-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
mvines committed Oct 20, 2020
1 parent 3c5497e commit 8308a03
Show file tree
Hide file tree
Showing 38 changed files with 3,821 additions and 3,742 deletions.
4 changes: 0 additions & 4 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser
hex = "0.4.2"
hmac = "0.7.0"
itertools = { version = "0.9.0" }
lazy_static = "1.4.0"
log = { version = "0.4.8" }
memmap = { version = "0.7.0", optional = true }
num-derive = { version = "0.3" }
Expand All @@ -69,9 +68,6 @@ libsecp256k1 = { version = "0.3.5", optional = true }
sha3 = { version = "0.9.1", optional = true }
digest = { version = "0.9.0", optional = true }

[target.'cfg(not(target_arch = "bpf"))'.dependencies]
curve25519-dalek = { version = "2.1.0" }

[dev-dependencies]
curve25519-dalek = "2.1.0"
tiny-bip39 = "0.7.0"
Expand Down
21 changes: 21 additions & 0 deletions sdk/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,29 @@ license = "Apache-2.0"
edition = "2018"

[dependencies]
bincode = "1.3.1"
bs58 = "0.3.1"
hex = "0.4.2"
lazy_static = "1.4.0"
num-derive = { version = "0.3" }
num-traits = { version = "0.2" }
rustversion = "1.0.3"
serde = "1.0.112"
serde_bytes = "0.11"
serde_derive = "1.0.103"
sha2 = "0.8.2"
solana-sdk-macro = { path = "../macro", version = "1.5.0" }
thiserror = "1.0"

[target.'cfg(not(target_arch = "bpf"))'.dependencies]
curve25519-dalek = { version = "2.1.0" }
rand = "0.7.0"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dev-dependencies]
assert_matches = "1.3.0"
bincode = "1.3.1"
serde_json = "1.0.56"
rand = "0.7.0"
302 changes: 302 additions & 0 deletions sdk/program/src/account.rs
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()?)
}
Loading

0 comments on commit 8308a03

Please sign in to comment.