Add sysvar support (#5838)

This commit is contained in:
Jack May 2019-09-09 10:55:35 -07:00 committed by GitHub
parent ee0c570d54
commit a317e9513f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 156 additions and 110 deletions

View File

@ -70,6 +70,7 @@ fn main() {
let rust_programs = [ let rust_programs = [
"128bit", "128bit",
"alloc", "alloc",
"clock",
"dep_crate", "dep_crate",
"iter", "iter",
"many_args", "many_args",
@ -77,7 +78,6 @@ fn main() {
"noop", "noop",
"panic", "panic",
"param_passing", "param_passing",
"tick_height",
]; ];
for program in rust_programs.iter() { for program in rust_programs.iter() {
println!( println!(

View File

@ -2,9 +2,9 @@
# Note: This crate must be built using build.sh # Note: This crate must be built using build.sh
[package] [package]
name = "solana-bpf-rust-tick-height" name = "solana-bpf-rust-clock"
version = "0.19.0-pre0" version = "0.19.0-pre0"
description = "Solana BPF noop program written in Rust" description = "Solana BPF clock sysvar test"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
@ -12,7 +12,6 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
byteorder = { version = "1", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.19.0-pre0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.19.0-pre0", default-features = false }
[features] [features]
@ -24,4 +23,4 @@ members = []
[lib] [lib]
crate-type = ["cdylib"] crate-type = ["cdylib"]
name = "solana_bpf_rust_tick_height" name = "solana_bpf_rust_clock"

View File

@ -0,0 +1,28 @@
//! @brief Example Rust-based BPF program that prints out the parameters passed to it
extern crate solana_sdk;
use solana_sdk::{
account_info::AccountInfo, entrypoint, entrypoint::SUCCESS, info, pubkey::Pubkey,
sysvar::clock::Clock,
};
entrypoint!(process_instruction);
fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], _data: &[u8]) -> u32 {
match Clock::from(&accounts[2]) {
Some(clock) => {
info!("slot, segment, epoch, stakers_epoch");
info!(
clock.slot,
clock.segment, clock.epoch, clock.stakers_epoch, 0
);
assert_eq!(clock.slot, 42);
}
None => {
info!("Failed to get clock from account 2");
panic!();
}
}
info!("Success");
SUCCESS
}

View File

@ -1,16 +0,0 @@
//! @brief Example Rust-based BPF program that prints out the parameters passed to it
extern crate solana_sdk;
use byteorder::{ByteOrder, LittleEndian};
use solana_sdk::{
account_info::AccountInfo, entrypoint, entrypoint::SUCCESS, info, pubkey::Pubkey,
};
entrypoint!(process_instruction);
fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], _data: &[u8]) -> u32 {
let tick_height = LittleEndian::read_u64(accounts[2].data);
assert_eq!(10u64, tick_height);
info!("Success");
SUCCESS
}

View File

@ -79,10 +79,12 @@ mod bpf {
use super::*; use super::*;
use solana_sdk::bpf_loader; use solana_sdk::bpf_loader;
use solana_sdk::client::SyncClient; use solana_sdk::client::SyncClient;
use solana_sdk::hash;
use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::sysvar::clock;
use std::io::Read; use std::io::Read;
use std::sync::Arc;
#[test] #[test]
fn test_program_bpf_rust() { fn test_program_bpf_rust() {
@ -91,10 +93,11 @@ mod bpf {
let programs = [ let programs = [
("solana_bpf_rust_128bit", true), ("solana_bpf_rust_128bit", true),
("solana_bpf_rust_alloc", true), ("solana_bpf_rust_alloc", true),
("solana_bpf_rust_clock", true),
("solana_bpf_rust_dep_crate", true), ("solana_bpf_rust_dep_crate", true),
("solana_bpf_rust_external_spend", false),
("solana_bpf_rust_iter", true), ("solana_bpf_rust_iter", true),
("solana_bpf_rust_many_args", true), ("solana_bpf_rust_many_args", true),
("solana_bpf_rust_external_spend", false),
("solana_bpf_rust_noop", true), ("solana_bpf_rust_noop", true),
("solana_bpf_rust_panic", false), ("solana_bpf_rust_panic", false),
("solana_bpf_rust_param_passing", true), ("solana_bpf_rust_param_passing", true),
@ -111,12 +114,9 @@ mod bpf {
mint_keypair, mint_keypair,
.. ..
} = create_genesis_block(50); } = create_genesis_block(50);
let bank = Bank::new(&genesis_block); let bank = Arc::new(Bank::new(&genesis_block));
// Create bank with specific slot, used by solana_bpf_rust_clock test
// register some ticks, used by solana_bpf_rust_tick_height let bank = Bank::new_from_parent(&bank, &Pubkey::default(), 42);
for i in 0..10 {
bank.register_tick(&hash::hash(format!("hashing {}", i).as_bytes()));
}
let bank_client = BankClient::new(bank); let bank_client = BankClient::new(bank);
// Call user program // Call user program
@ -124,6 +124,7 @@ mod bpf {
let account_metas = vec![ let account_metas = vec![
AccountMeta::new(mint_keypair.pubkey(), true), AccountMeta::new(mint_keypair.pubkey(), true),
AccountMeta::new(Keypair::new().pubkey(), false), AccountMeta::new(Keypair::new().pubkey(), false),
AccountMeta::new(clock::id(), false),
]; ];
let instruction = Instruction::new(program_id, &1u8, account_metas); let instruction = Instruction::new(program_id, &1u8, account_metas);
let result = bank_client.send_instruction(&mint_keypair, instruction); let result = bank_client.send_instruction(&mint_keypair, instruction);

View File

@ -179,7 +179,7 @@ pub fn process_instruction(
me.delegate_stake( me.delegate_stake(
vote, vote,
stake, stake,
&sysvar::clock::from_keyed_account(&rest[1])?, &sysvar::clock_account::from_keyed_account(&rest[1])?,
&config::from_keyed_account(&rest[2])?, &config::from_keyed_account(&rest[2])?,
) )
} }
@ -209,7 +209,7 @@ pub fn process_instruction(
me.withdraw( me.withdraw(
lamports, lamports,
&mut to, &mut to,
&sysvar::clock::from_keyed_account(&sysvar[0])?, &sysvar::clock_account::from_keyed_account(&sysvar[0])?,
&sysvar::stake_history::from_keyed_account(&sysvar[1])?, &sysvar::stake_history::from_keyed_account(&sysvar[1])?,
) )
} }
@ -221,7 +221,7 @@ pub fn process_instruction(
let vote = &mut vote[0]; let vote = &mut vote[0];
let clock = &rest[0]; let clock = &rest[0];
me.deactivate_stake(vote, &sysvar::clock::from_keyed_account(&clock)?) me.deactivate_stake(vote, &sysvar::clock_account::from_keyed_account(&clock)?)
} }
} }
} }
@ -238,7 +238,7 @@ mod tests {
.iter() .iter()
.map(|meta| { .map(|meta| {
if sysvar::clock::check_id(&meta.pubkey) { if sysvar::clock::check_id(&meta.pubkey) {
sysvar::clock::create_account(1, 0, 0, 0, 0) sysvar::clock_account::new(1, 0, 0, 0, 0)
} else if sysvar::rewards::check_id(&meta.pubkey) { } else if sysvar::rewards::check_id(&meta.pubkey) {
sysvar::rewards::create_account(1, 0.0, 0.0) sysvar::rewards::create_account(1, 0.0, 0.0)
} else if sysvar::stake_history::check_id(&meta.pubkey) { } else if sysvar::stake_history::check_id(&meta.pubkey) {
@ -336,7 +336,7 @@ mod tests {
KeyedAccount::new( KeyedAccount::new(
&sysvar::clock::id(), &sysvar::clock::id(),
false, false,
&mut sysvar::clock::create_account(1, 0, 0, 0, 0) &mut sysvar::clock_account::new(1, 0, 0, 0, 0)
), ),
KeyedAccount::new( KeyedAccount::new(
&config::id(), &config::id(),

View File

@ -42,7 +42,7 @@ pub fn process_instruction(
// This instruction must be signed by `me` // This instruction must be signed by `me`
Err(InstructionError::InvalidArgument)?; Err(InstructionError::InvalidArgument)?;
} }
let clock = sysvar::clock::from_keyed_account(&rest[0])?; let clock = sysvar::clock_account::from_keyed_account(&rest[0])?;
storage_account.submit_mining_proof( storage_account.submit_mining_proof(
sha_state, sha_state,
segment_index, segment_index,
@ -56,7 +56,7 @@ pub fn process_instruction(
// This instruction must be signed by `me` // This instruction must be signed by `me`
Err(InstructionError::InvalidArgument)?; Err(InstructionError::InvalidArgument)?;
} }
let clock = sysvar::clock::from_keyed_account(&rest[0])?; let clock = sysvar::clock_account::from_keyed_account(&rest[0])?;
storage_account.advertise_storage_recent_blockhash(hash, segment, clock) storage_account.advertise_storage_recent_blockhash(hash, segment, clock)
} }
StorageInstruction::ClaimStorageReward => { StorageInstruction::ClaimStorageReward => {
@ -68,7 +68,7 @@ pub fn process_instruction(
let (rewards_pools, owner) = rest.split_at_mut(1); let (rewards_pools, owner) = rest.split_at_mut(1);
let rewards = sysvar::rewards::from_keyed_account(&rewards[0])?; let rewards = sysvar::rewards::from_keyed_account(&rewards[0])?;
let clock = sysvar::clock::from_keyed_account(&clock[0])?; let clock = sysvar::clock_account::from_keyed_account(&clock[0])?;
let mut owner = StorageAccount::new(*owner[0].unsigned_key(), &mut owner[0].account); let mut owner = StorageAccount::new(*owner[0].unsigned_key(), &mut owner[0].account);
storage_account.claim_storage_reward(&mut rewards_pools[0], clock, rewards, &mut owner) storage_account.claim_storage_reward(&mut rewards_pools[0], clock, rewards, &mut owner)
@ -84,7 +84,7 @@ pub fn process_instruction(
Err(InstructionError::InvalidArgument)?; Err(InstructionError::InvalidArgument)?;
} }
let me_id = storage_account.id; let me_id = storage_account.id;
let clock = sysvar::clock::from_keyed_account(&clock[0])?; let clock = sysvar::clock_account::from_keyed_account(&clock[0])?;
let mut rest: Vec<_> = rest let mut rest: Vec<_> = rest
.iter_mut() .iter_mut()
.map(|keyed_account| { .map(|keyed_account| {

View File

@ -14,9 +14,9 @@ use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
use solana_sdk::system_instruction; use solana_sdk::system_instruction;
use solana_sdk::sysvar::clock::Clock; use solana_sdk::sysvar::clock::{self, Clock};
use solana_sdk::sysvar::rewards::Rewards; use solana_sdk::sysvar::rewards::Rewards;
use solana_sdk::sysvar::{clock, rewards}; use solana_sdk::sysvar::{clock_account, rewards};
use solana_storage_api::id; use solana_storage_api::id;
use solana_storage_api::storage_contract::StorageAccount; use solana_storage_api::storage_contract::StorageAccount;
use solana_storage_api::storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE}; use solana_storage_api::storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE};
@ -124,7 +124,7 @@ fn test_proof_bounds() {
Hash::default(), Hash::default(),
); );
// the proof is for segment 0, need to move the slot into segment 2 // the proof is for segment 0, need to move the slot into segment 2
let mut clock_account = clock::create_account(1, 0, 0, 0, 0); let mut clock_account = clock_account::new(1, 0, 0, 0, 0);
Clock::to( Clock::to(
&Clock { &Clock {
slot: DEFAULT_SLOTS_PER_SEGMENT * 2, slot: DEFAULT_SLOTS_PER_SEGMENT * 2,
@ -152,7 +152,7 @@ fn test_serialize_overflow() {
let clock_id = clock::id(); let clock_id = clock::id();
let mut keyed_accounts = Vec::new(); let mut keyed_accounts = Vec::new();
let mut user_account = Account::default(); let mut user_account = Account::default();
let mut clock_account = clock::create_account(1, 0, 0, 0, 0); let mut clock_account = clock_account::new(1, 0, 0, 0, 0);
keyed_accounts.push(KeyedAccount::new(&pubkey, true, &mut user_account)); keyed_accounts.push(KeyedAccount::new(&pubkey, true, &mut user_account));
keyed_accounts.push(KeyedAccount::new(&clock_id, false, &mut clock_account)); keyed_accounts.push(KeyedAccount::new(&clock_id, false, &mut clock_account));
@ -177,7 +177,7 @@ fn test_invalid_accounts_len() {
Hash::default(), Hash::default(),
); );
// move tick height into segment 1 // move tick height into segment 1
let mut clock_account = clock::create_account(1, 0, 0, 0, 0); let mut clock_account = clock_account::new(1, 0, 0, 0, 0);
Clock::to( Clock::to(
&Clock { &Clock {
slot: 16, slot: 16,
@ -237,7 +237,7 @@ fn test_submit_mining_ok() {
Hash::default(), Hash::default(),
); );
// move slot into segment 1 // move slot into segment 1
let mut clock_account = clock::create_account(1, 0, 0, 0, 0); let mut clock_account = clock_account::new(1, 0, 0, 0, 0);
Clock::to( Clock::to(
&Clock { &Clock {
slot: DEFAULT_SLOTS_PER_SEGMENT, slot: DEFAULT_SLOTS_PER_SEGMENT,

View File

@ -154,7 +154,7 @@ pub fn process_instruction(
vote_state::process_vote( vote_state::process_vote(
me, me,
&sysvar::slot_hashes::from_keyed_account(&slot_hashes_and_clock[0])?, &sysvar::slot_hashes::from_keyed_account(&slot_hashes_and_clock[0])?,
&sysvar::clock::from_keyed_account(&slot_hashes_and_clock[1])?, &sysvar::clock_account::from_keyed_account(&slot_hashes_and_clock[1])?,
other_signers, other_signers,
&vote, &vote,
) )
@ -188,7 +188,7 @@ mod tests {
.iter() .iter()
.map(|meta| { .map(|meta| {
if sysvar::clock::check_id(&meta.pubkey) { if sysvar::clock::check_id(&meta.pubkey) {
sysvar::clock::create_account(1, 0, 0, 0, 0) sysvar::clock_account::new(1, 0, 0, 0, 0)
} else if sysvar::slot_hashes::check_id(&meta.pubkey) { } else if sysvar::slot_hashes::check_id(&meta.pubkey) {
sysvar::slot_hashes::create_account(1, &[]) sysvar::slot_hashes::create_account(1, &[])
} else { } else {

View File

@ -41,7 +41,7 @@ use solana_sdk::{
signature::{Keypair, Signature}, signature::{Keypair, Signature},
system_transaction, system_transaction,
sysvar::{ sysvar::{
clock, fees, rewards, clock, clock_account, fees, rewards,
slot_hashes::{self, SlotHashes}, slot_hashes::{self, SlotHashes},
stake_history, stake_history,
}, },
@ -400,7 +400,7 @@ impl Bank {
fn update_clock(&self) { fn update_clock(&self) {
self.store_account( self.store_account(
&clock::id(), &clock::id(),
&clock::create_account( &clock_account::new(
1, 1,
self.slot, self.slot,
get_segment_from_slot(self.slot, self.slots_per_segment), get_segment_from_slot(self.slot, self.slots_per_segment),

View File

@ -1,5 +1,6 @@
pub mod clock; pub mod clock;
pub mod pubkey; pub mod pubkey;
pub mod sysvar;
// On-chain program modules // On-chain program modules
#[cfg(feature = "program")] #[cfg(feature = "program")]
@ -57,8 +58,6 @@ pub mod system_program;
#[cfg(feature = "kitchen_sink")] #[cfg(feature = "kitchen_sink")]
pub mod system_transaction; pub mod system_transaction;
#[cfg(feature = "kitchen_sink")] #[cfg(feature = "kitchen_sink")]
pub mod sysvar;
#[cfg(feature = "kitchen_sink")]
pub mod timing; pub mod timing;
#[cfg(feature = "kitchen_sink")] #[cfg(feature = "kitchen_sink")]
pub mod transaction; pub mod transaction;

View File

@ -1,10 +1,7 @@
//! This account contains the clock slot, epoch, and stakers_epoch //! This account contains the clock slot, epoch, and stakers_epoch
//! //!
use crate::account::Account;
use crate::sysvar;
use bincode::serialized_size;
pub use crate::clock::{Epoch, Slot}; pub use crate::clock::{Epoch, Segment, Slot};
const ID: [u8; 32] = [ const ID: [u8; 32] = [
6, 167, 213, 23, 24, 199, 116, 201, 40, 86, 99, 152, 105, 29, 94, 182, 139, 94, 184, 163, 155, 6, 167, 213, 23, 24, 199, 116, 201, 40, 86, 99, 152, 105, 29, 94, 182, 139, 94, 184, 163, 155,
@ -21,59 +18,3 @@ pub struct Clock {
pub epoch: Epoch, pub epoch: Epoch,
pub stakers_epoch: Epoch, pub stakers_epoch: Epoch,
} }
impl Clock {
pub fn from(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&Self::default()).unwrap() as usize
}
}
pub fn create_account(
lamports: u64,
slot: Slot,
segment: Segment,
epoch: Epoch,
stakers_epoch: Epoch,
) -> Account {
Account::new_data(
lamports,
&Clock {
slot,
segment,
epoch,
stakers_epoch,
},
&sysvar::id(),
)
.unwrap()
}
use crate::account::KeyedAccount;
use crate::clock::Segment;
use crate::instruction::InstructionError;
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Clock, InstructionError> {
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
Clock::from(account.account).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_account() {
let account = create_account(1, 0, 0, 0, 0);
let clock = Clock::from(&account).unwrap();
assert_eq!(clock, Clock::default());
}
}

View File

@ -0,0 +1,64 @@
//! Serialize clock support for Account
//!
use crate::account::Account;
use crate::sysvar;
use crate::sysvar::clock::{check_id, Clock};
use bincode::serialized_size;
pub use crate::clock::{Epoch, Slot};
impl Clock {
pub fn from(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&Self::default()).unwrap() as usize
}
}
pub fn new(
lamports: u64,
slot: Slot,
segment: Segment,
epoch: Epoch,
stakers_epoch: Epoch,
) -> Account {
Account::new_data(
lamports,
&Clock {
slot,
segment,
epoch,
stakers_epoch,
},
&sysvar::id(),
)
.unwrap()
}
use crate::account::KeyedAccount;
use crate::clock::Segment;
use crate::instruction::InstructionError;
pub fn from_keyed_account(account: &KeyedAccount) -> Result<Clock, InstructionError> {
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
Clock::from(account.account).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_account() {
let account = new(1, 0, 0, 0, 0);
let clock = Clock::from(&account).unwrap();
assert_eq!(clock, Clock::default());
}
}

View File

@ -0,0 +1,18 @@
//! Serialize clock support for AccountInfo
//!
use crate::account_info::AccountInfo;
use crate::sysvar::clock::Clock;
use bincode::serialized_size;
impl Clock {
pub fn from(account: &AccountInfo) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut AccountInfo) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&Self::default()).unwrap() as usize
}
}

View File

@ -1,13 +1,25 @@
//! named accounts for synthesized data accounts for bank state, etc. //! named accounts for synthesized data accounts for bank state, etc.
//! //!
#[cfg(feature = "kitchen_sink")]
use crate::pubkey::Pubkey; use crate::pubkey::Pubkey;
pub mod clock; pub mod clock;
#[cfg(feature = "program")]
pub mod clock_account_info;
#[cfg(feature = "kitchen_sink")]
pub mod clock_account;
#[cfg(feature = "kitchen_sink")]
pub mod fees; pub mod fees;
#[cfg(feature = "kitchen_sink")]
pub mod rewards; pub mod rewards;
#[cfg(feature = "kitchen_sink")]
pub mod slot_hashes; pub mod slot_hashes;
#[cfg(feature = "kitchen_sink")]
pub mod stake_history; pub mod stake_history;
#[cfg(feature = "kitchen_sink")]
pub fn is_sysvar_id(id: &Pubkey) -> bool { pub fn is_sysvar_id(id: &Pubkey) -> bool {
clock::check_id(id) || fees::check_id(id) || rewards::check_id(id) || slot_hashes::check_id(id) clock::check_id(id) || fees::check_id(id) || rewards::check_id(id) || slot_hashes::check_id(id)
} }