diff --git a/programs/bpf/build.rs b/programs/bpf/build.rs index bf923c22b..8ba4b5470 100644 --- a/programs/bpf/build.rs +++ b/programs/bpf/build.rs @@ -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!( diff --git a/programs/bpf/rust/tick_height/.gitignore b/programs/bpf/rust/clock/.gitignore similarity index 100% rename from programs/bpf/rust/tick_height/.gitignore rename to programs/bpf/rust/clock/.gitignore diff --git a/programs/bpf/rust/tick_height/Cargo.toml b/programs/bpf/rust/clock/Cargo.toml similarity index 72% rename from programs/bpf/rust/tick_height/Cargo.toml rename to programs/bpf/rust/clock/Cargo.toml index 6ced659b3..67351af4f 100644 --- a/programs/bpf/rust/tick_height/Cargo.toml +++ b/programs/bpf/rust/clock/Cargo.toml @@ -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 "] 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" diff --git a/programs/bpf/rust/tick_height/Xargo.toml b/programs/bpf/rust/clock/Xargo.toml similarity index 100% rename from programs/bpf/rust/tick_height/Xargo.toml rename to programs/bpf/rust/clock/Xargo.toml diff --git a/programs/bpf/rust/clock/src/lib.rs b/programs/bpf/rust/clock/src/lib.rs new file mode 100644 index 000000000..5b7d373d5 --- /dev/null +++ b/programs/bpf/rust/clock/src/lib.rs @@ -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 +} diff --git a/programs/bpf/rust/tick_height/src/lib.rs b/programs/bpf/rust/tick_height/src/lib.rs deleted file mode 100644 index c7f1cbc38..000000000 --- a/programs/bpf/rust/tick_height/src/lib.rs +++ /dev/null @@ -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 -} diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 68d4d9ab7..84480ae90 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -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); diff --git a/programs/stake_api/src/stake_instruction.rs b/programs/stake_api/src/stake_instruction.rs index 7993ea549..bc9552b21 100644 --- a/programs/stake_api/src/stake_instruction.rs +++ b/programs/stake_api/src/stake_instruction.rs @@ -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(), diff --git a/programs/storage_api/src/storage_processor.rs b/programs/storage_api/src/storage_processor.rs index 2c4c46f4e..55976469e 100644 --- a/programs/storage_api/src/storage_processor.rs +++ b/programs/storage_api/src/storage_processor.rs @@ -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| { diff --git a/programs/storage_program/tests/storage_processor.rs b/programs/storage_program/tests/storage_processor.rs index a37a39167..ec7b63e64 100644 --- a/programs/storage_program/tests/storage_processor.rs +++ b/programs/storage_program/tests/storage_processor.rs @@ -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, diff --git a/programs/vote_api/src/vote_instruction.rs b/programs/vote_api/src/vote_instruction.rs index 7af75c85a..a0524f957 100644 --- a/programs/vote_api/src/vote_instruction.rs +++ b/programs/vote_api/src/vote_instruction.rs @@ -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 { diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index b1a5ff940..cc238c4b8 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -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), diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index c0dc26e6d..b09d43142 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -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; diff --git a/sdk/src/sysvar/clock.rs b/sdk/src/sysvar/clock.rs index 9b3748200..a735cd2c0 100644 --- a/sdk/src/sysvar/clock.rs +++ b/sdk/src/sysvar/clock.rs @@ -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 { - 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 { - 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()); - } -} diff --git a/sdk/src/sysvar/clock_account.rs b/sdk/src/sysvar/clock_account.rs new file mode 100644 index 000000000..1c0710a9a --- /dev/null +++ b/sdk/src/sysvar/clock_account.rs @@ -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 { + 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 { + 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()); + } +} diff --git a/sdk/src/sysvar/clock_account_info.rs b/sdk/src/sysvar/clock_account_info.rs new file mode 100644 index 000000000..cbec33ff0 --- /dev/null +++ b/sdk/src/sysvar/clock_account_info.rs @@ -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 { + 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 + } +} diff --git a/sdk/src/sysvar/mod.rs b/sdk/src/sysvar/mod.rs index 4a955e116..ba581acbe 100644 --- a/sdk/src/sysvar/mod.rs +++ b/sdk/src/sysvar/mod.rs @@ -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) }