From 58295b825dc90aac845327e702d81da0ea10c1ff Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Tue, 21 May 2019 15:19:41 -0700 Subject: [PATCH] introduce syscalls (#4373) --- programs/stake_api/src/stake_state.rs | 2 +- programs/storage_api/src/storage_contract.rs | 2 +- programs/vote_api/src/vote_state.rs | 2 +- sdk/src/account_utils.rs | 61 ++++++++++++++++++++ sdk/src/instruction_processor_utils.rs | 37 +----------- sdk/src/lib.rs | 2 + sdk/src/syscall/mod.rs | 30 ++++++++++ sdk/src/syscall/slothashes.rs | 54 +++++++++++++++++ wallet/src/wallet.rs | 3 +- 9 files changed, 153 insertions(+), 40 deletions(-) create mode 100644 sdk/src/account_utils.rs create mode 100644 sdk/src/syscall/mod.rs create mode 100644 sdk/src/syscall/slothashes.rs diff --git a/programs/stake_api/src/stake_state.rs b/programs/stake_api/src/stake_state.rs index a8dff7630f..8974ac6782 100644 --- a/programs/stake_api/src/stake_state.rs +++ b/programs/stake_api/src/stake_state.rs @@ -6,8 +6,8 @@ use crate::id; use serde_derive::{Deserialize, Serialize}; use solana_sdk::account::{Account, KeyedAccount}; +use solana_sdk::account_utils::State; use solana_sdk::instruction::InstructionError; -use solana_sdk::instruction_processor_utils::State; use solana_sdk::pubkey::Pubkey; use solana_vote_api::vote_state::VoteState; diff --git a/programs/storage_api/src/storage_contract.rs b/programs/storage_api/src/storage_contract.rs index 9750e85bd8..17bced40f7 100644 --- a/programs/storage_api/src/storage_contract.rs +++ b/programs/storage_api/src/storage_contract.rs @@ -2,9 +2,9 @@ use crate::get_segment_from_slot; use log::*; use serde_derive::{Deserialize, Serialize}; use solana_sdk::account::Account; +use solana_sdk::account_utils::State; use solana_sdk::hash::Hash; use solana_sdk::instruction::InstructionError; -use solana_sdk::instruction_processor_utils::State; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Signature; use std::collections::HashMap; diff --git a/programs/vote_api/src/vote_state.rs b/programs/vote_api/src/vote_state.rs index 6980c7c71e..201fcfb829 100644 --- a/programs/vote_api/src/vote_state.rs +++ b/programs/vote_api/src/vote_state.rs @@ -4,8 +4,8 @@ use crate::id; use bincode::{deserialize, serialize_into, serialized_size, ErrorKind}; use serde_derive::{Deserialize, Serialize}; use solana_sdk::account::{Account, KeyedAccount}; +use solana_sdk::account_utils::State; use solana_sdk::instruction::InstructionError; -use solana_sdk::instruction_processor_utils::State; use solana_sdk::pubkey::Pubkey; use std::collections::VecDeque; diff --git a/sdk/src/account_utils.rs b/sdk/src/account_utils.rs new file mode 100644 index 0000000000..2befc48512 --- /dev/null +++ b/sdk/src/account_utils.rs @@ -0,0 +1,61 @@ +//! useful extras for Account state +use crate::account::{Account, KeyedAccount}; +use crate::instruction::InstructionError; +use bincode::ErrorKind; + +/// Conveinence trait to covert bincode errors to instruction errors. +pub trait State { + fn state(&self) -> Result; + fn set_state(&mut self, state: &T) -> Result<(), InstructionError>; +} + +impl State for Account +where + T: serde::Serialize + serde::de::DeserializeOwned, +{ + fn state(&self) -> Result { + 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<'a, T> State for KeyedAccount<'a> +where + T: serde::Serialize + serde::de::DeserializeOwned, +{ + fn state(&self) -> Result { + self.account.state() + } + fn set_state(&mut self, state: &T) -> Result<(), InstructionError> { + self.account.set_state(state) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::account::Account; + use crate::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; + assert!(res.is_err()); + + let mut account = Account::new(0, std::mem::size_of::(), &Pubkey::default()); + + assert!(account.set_state(&state).is_ok()); + let stored_state: u64 = account.state().unwrap(); + assert_eq!(stored_state, state); + } + +} diff --git a/sdk/src/instruction_processor_utils.rs b/sdk/src/instruction_processor_utils.rs index d6a34c6f4f..1545db9381 100644 --- a/sdk/src/instruction_processor_utils.rs +++ b/sdk/src/instruction_processor_utils.rs @@ -1,7 +1,6 @@ -use crate::account::{Account, KeyedAccount}; +use crate::account::KeyedAccount; use crate::instruction::InstructionError; use crate::pubkey::Pubkey; -use bincode::ErrorKind; use num_traits::FromPrimitive; // All native programs export a symbol named process() @@ -52,40 +51,6 @@ macro_rules! solana_program_id( ) ); -/// Conveinence trait to covert bincode errors to instruction errors. -pub trait State { - fn state(&self) -> Result; - fn set_state(&mut self, state: &T) -> Result<(), InstructionError>; -} - -impl State for Account -where - T: serde::Serialize + serde::de::DeserializeOwned, -{ - fn state(&self) -> Result { - 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<'a, T> State for KeyedAccount<'a> -where - T: serde::Serialize + serde::de::DeserializeOwned, -{ - fn state(&self) -> Result { - self.account.state() - } - fn set_state(&mut self, state: &T) -> Result<(), InstructionError> { - self.account.set_state(state) - } -} - pub trait DecodeError { fn decode_custom_error_to_enum(int: u32) -> Option where diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 8ccc5c9473..aa4c18549c 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -1,4 +1,5 @@ pub mod account; +pub mod account_utils; pub mod bpf_loader; pub mod client; pub mod fee_calculator; @@ -15,6 +16,7 @@ pub mod pubkey; pub mod rpc_port; pub mod short_vec; pub mod signature; +pub mod syscall; pub mod system_instruction; pub mod system_program; pub mod system_transaction; diff --git a/sdk/src/syscall/mod.rs b/sdk/src/syscall/mod.rs new file mode 100644 index 0000000000..929c150d07 --- /dev/null +++ b/sdk/src/syscall/mod.rs @@ -0,0 +1,30 @@ +//! named accounts for synthesized data accounts for bank state, etc. +//! +use crate::pubkey::Pubkey; + +pub mod slothashes; + +/// "Sysca11111111111111111111111111111111111111" +/// owner pubkey for syscall accounts +const SYSCALL_PROGRAM_ID: [u8; 32] = [ + 6, 167, 211, 138, 69, 216, 137, 185, 198, 189, 33, 204, 111, 12, 217, 220, 229, 201, 34, 52, + 253, 202, 87, 144, 232, 16, 195, 192, 0, 0, 0, 0, +]; + +pub fn id() -> Pubkey { + Pubkey::new(&SYSCALL_PROGRAM_ID) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_syscall_ids() { + let ids = [("Sysca11111111111111111111111111111111111111", id())]; + // to get the bytes above: + // ids.iter().for_each(|(name, _)| { + // dbg!((name, bs58::decode(name).into_vec().unwrap())); + // }); + assert!(ids.iter().all(|(name, id)| *name == id.to_string())); + } +} diff --git a/sdk/src/syscall/slothashes.rs b/sdk/src/syscall/slothashes.rs new file mode 100644 index 0000000000..5f3447f2e9 --- /dev/null +++ b/sdk/src/syscall/slothashes.rs @@ -0,0 +1,54 @@ +//! named accounts for synthesized data accounts for bank state, etc. +//! +//! this account carries the Bank's most recent blockhashes for some N parents +//! +use crate::account::Account; +use crate::hash::Hash; +use crate::pubkey::Pubkey; + +/// "Sysca11SlotHashes11111111111111111111111111" +/// slot hashes account pubkey +const SYSCALL_SLOT_HASHES_ID: [u8; 32] = [ + 6, 167, 211, 138, 69, 219, 186, 157, 48, 170, 46, 66, 2, 146, 193, 59, 39, 59, 245, 188, 30, + 60, 130, 78, 86, 27, 113, 191, 208, 0, 0, 0, +]; + +pub fn id() -> Pubkey { + Pubkey::new(&SYSCALL_SLOT_HASHES_ID) +} + +use crate::account_utils::State; +use std::ops::{Deref, DerefMut}; +#[derive(Serialize, Deserialize)] +pub struct SlotHashes(Vec<(u64, Hash)>); + +impl SlotHashes { + pub fn from(account: &Account) -> Option { + account.state().ok() + } +} +impl Deref for SlotHashes { + type Target = Vec<(u64, Hash)>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SlotHashes { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_syscall_ids() { + let ids = [("Sysca11S1otHashes11111111111111111111111111", id())]; + // to get the bytes above: + // ids.iter().for_each(|(name, _)| { + // dbg!((name, bs58::decode(name).into_vec().unwrap())); + // }); + assert!(ids.iter().all(|(name, id)| *name == id.to_string())); + } +} diff --git a/wallet/src/wallet.rs b/wallet/src/wallet.rs index de2c5f609f..39fc9e1775 100644 --- a/wallet/src/wallet.rs +++ b/wallet/src/wallet.rs @@ -14,10 +14,11 @@ use solana_drone::drone::request_airdrop_transaction; use solana_drone::drone::DRONE_PORT; #[cfg(test)] use solana_drone::drone_mock::request_airdrop_transaction; +use solana_sdk::account_utils::State; use solana_sdk::bpf_loader; use solana_sdk::hash::Hash; use solana_sdk::instruction::InstructionError; -use solana_sdk::instruction_processor_utils::{DecodeError, State}; +use solana_sdk::instruction_processor_utils::DecodeError; use solana_sdk::loader_instruction; use solana_sdk::message::Message; use solana_sdk::pubkey::Pubkey;