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

View File

@ -2,9 +2,9 @@
# Note: This crate must be built using build.sh
[package]
name = "solana-bpf-rust-tick-height"
name = "solana-bpf-rust-clock"
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>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
@ -12,7 +12,6 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
byteorder = { version = "1", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.19.0-pre0", default-features = false }
[features]
@ -24,4 +23,4 @@ members = []
[lib]
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 solana_sdk::bpf_loader;
use solana_sdk::client::SyncClient;
use solana_sdk::hash;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::sysvar::clock;
use std::io::Read;
use std::sync::Arc;
#[test]
fn test_program_bpf_rust() {
@ -91,10 +93,11 @@ mod bpf {
let programs = [
("solana_bpf_rust_128bit", true),
("solana_bpf_rust_alloc", true),
("solana_bpf_rust_clock", true),
("solana_bpf_rust_dep_crate", true),
("solana_bpf_rust_external_spend", false),
("solana_bpf_rust_iter", true),
("solana_bpf_rust_many_args", true),
("solana_bpf_rust_external_spend", false),
("solana_bpf_rust_noop", true),
("solana_bpf_rust_panic", false),
("solana_bpf_rust_param_passing", true),
@ -111,12 +114,9 @@ mod bpf {
mint_keypair,
..
} = create_genesis_block(50);
let bank = Bank::new(&genesis_block);
// register some ticks, used by solana_bpf_rust_tick_height
for i in 0..10 {
bank.register_tick(&hash::hash(format!("hashing {}", i).as_bytes()));
}
let bank = Arc::new(Bank::new(&genesis_block));
// Create bank with specific slot, used by solana_bpf_rust_clock test
let bank = Bank::new_from_parent(&bank, &Pubkey::default(), 42);
let bank_client = BankClient::new(bank);
// Call user program
@ -124,6 +124,7 @@ mod bpf {
let account_metas = vec![
AccountMeta::new(mint_keypair.pubkey(), true),
AccountMeta::new(Keypair::new().pubkey(), false),
AccountMeta::new(clock::id(), false),
];
let instruction = Instruction::new(program_id, &1u8, account_metas);
let result = bank_client.send_instruction(&mint_keypair, instruction);

View File

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

View File

@ -42,7 +42,7 @@ pub fn process_instruction(
// This instruction must be signed by `me`
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(
sha_state,
segment_index,
@ -56,7 +56,7 @@ pub fn process_instruction(
// This instruction must be signed by `me`
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)
}
StorageInstruction::ClaimStorageReward => {
@ -68,7 +68,7 @@ pub fn process_instruction(
let (rewards_pools, owner) = rest.split_at_mut(1);
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);
storage_account.claim_storage_reward(&mut rewards_pools[0], clock, rewards, &mut owner)
@ -84,7 +84,7 @@ pub fn process_instruction(
Err(InstructionError::InvalidArgument)?;
}
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
.iter_mut()
.map(|keyed_account| {

View File

@ -14,9 +14,9 @@ use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
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::{clock, rewards};
use solana_sdk::sysvar::{clock_account, rewards};
use solana_storage_api::id;
use solana_storage_api::storage_contract::StorageAccount;
use solana_storage_api::storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE};
@ -124,7 +124,7 @@ fn test_proof_bounds() {
Hash::default(),
);
// 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 {
slot: DEFAULT_SLOTS_PER_SEGMENT * 2,
@ -152,7 +152,7 @@ fn test_serialize_overflow() {
let clock_id = clock::id();
let mut keyed_accounts = Vec::new();
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(&clock_id, false, &mut clock_account));
@ -177,7 +177,7 @@ fn test_invalid_accounts_len() {
Hash::default(),
);
// 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 {
slot: 16,
@ -237,7 +237,7 @@ fn test_submit_mining_ok() {
Hash::default(),
);
// 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 {
slot: DEFAULT_SLOTS_PER_SEGMENT,

View File

@ -154,7 +154,7 @@ pub fn process_instruction(
vote_state::process_vote(
me,
&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,
&vote,
)
@ -188,7 +188,7 @@ mod tests {
.iter()
.map(|meta| {
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) {
sysvar::slot_hashes::create_account(1, &[])
} else {

View File

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

View File

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

View File

@ -1,10 +1,7 @@
//! 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] = [
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 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.
//!
#[cfg(feature = "kitchen_sink")]
use crate::pubkey::Pubkey;
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;
#[cfg(feature = "kitchen_sink")]
pub mod rewards;
#[cfg(feature = "kitchen_sink")]
pub mod slot_hashes;
#[cfg(feature = "kitchen_sink")]
pub mod stake_history;
#[cfg(feature = "kitchen_sink")]
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)
}