Add support for SDK sysvar types (#5876)

This commit is contained in:
Jack May 2019-09-10 18:53:02 -07:00 committed by GitHub
parent 772ee4b29d
commit 1853771930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 124 additions and 75 deletions

8
Cargo.lock generated
View File

@ -2893,7 +2893,7 @@ dependencies = [
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.19.0-pre0",
"solana-sdk 0.19.0-pre0",
"solana_rbpf 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"solana_rbpf 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2917,7 +2917,7 @@ dependencies = [
"solana-logger 0.19.0-pre0",
"solana-runtime 0.19.0-pre0",
"solana-sdk 0.19.0-pre0",
"solana_rbpf 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"solana_rbpf 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -4141,7 +4141,7 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.1.15"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -5365,7 +5365,7 @@ dependencies = [
"checksum solana_libra_vm_cache_map 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f0abd2cc72c7d76ca9e0764e3f1fa01a01f49b9014a193f2a3fe735a034bf96"
"checksum solana_libra_vm_genesis 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4dadfcf5fabfd28d09770d698c618a48d75819f6915bd8bdfa04b93b6e492530"
"checksum solana_libra_vm_runtime 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "055a5de29d1b8a2b9f9e20293e07998b8e188164bbe6ac8a09260043f99379aa"
"checksum solana_rbpf 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "31bb26b38c7f84afa1fa266e8fd46ae93bec1ea7253f09a3288dfd118a0086e3"
"checksum solana_rbpf 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7b5902653b9c19efe7821e1058836554786668438bf2ba048fbce04fb633e0c0"
"checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"

View File

@ -227,7 +227,7 @@ pub(crate) mod tests {
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, next_stakers_epoch);
result.sort();
let stake_history =
StakeHistory::from(&bank.get_account(&stake_history::id()).unwrap()).unwrap();
StakeHistory::from_account(&bank.get_account(&stake_history::id()).unwrap()).unwrap();
let mut expected = vec![
(leader_stake.stake(bank.epoch(), Some(&stake_history)), None),
(other_stake.stake(bank.epoch(), Some(&stake_history)), None),

View File

@ -26,7 +26,7 @@ solana-bpf-loader-api = { path = "../bpf_loader_api", version = "0.19.0-pre0" }
solana-logger = { path = "../../logger", version = "0.19.0-pre0" }
solana-runtime = { path = "../../runtime", version = "0.19.0-pre0" }
solana-sdk = { path = "../../sdk", version = "0.19.0-pre0" }
solana_rbpf = "=0.1.15"
solana_rbpf = "=0.1.16"
[[bench]]
name = "bpf_loader"

View File

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

View File

@ -1,28 +0,0 @@
//! @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_account_info(&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

@ -2,9 +2,9 @@
# Note: This crate must be built using build.sh
[package]
name = "solana-bpf-rust-clock"
name = "solana-bpf-rust-sysval"
version = "0.19.0-pre0"
description = "Solana BPF clock sysvar test"
description = "Solana BPF sysvar test"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
@ -23,4 +23,4 @@ members = []
[lib]
crate-type = ["cdylib"]
name = "solana_bpf_rust_clock"
name = "solana_bpf_rust_sysval"

View File

@ -0,0 +1,43 @@
//! @brief Example Rust-based BPF program that tests sysval use
extern crate solana_sdk;
use solana_sdk::{
account_info::AccountInfo,
clock::{get_segment_from_slot, DEFAULT_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT},
entrypoint,
entrypoint::SUCCESS,
pubkey::Pubkey,
sysvar::{
clock::Clock, fees::Fees, rewards::Rewards, slot_hashes::SlotHashes,
stake_history::StakeHistory,
},
};
entrypoint!(process_instruction);
fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], _data: &[u8]) -> u32 {
// Clock
let clock = Clock::from_account_info(&accounts[2]).unwrap();
assert_eq!(clock.slot, DEFAULT_SLOTS_PER_EPOCH + 1);
assert_eq!(
clock.segment,
get_segment_from_slot(clock.slot, DEFAULT_SLOTS_PER_SEGMENT)
);
// Fees
let fees = Fees::from_account_info(&accounts[3]).unwrap();
let burn = fees.fee_calculator.burn(42);
assert_eq!(burn, (21, 21));
// Rewards
let _ = Rewards::from_account_info(&accounts[4]).unwrap();
// Slot Hashes
let slot_hashes = SlotHashes::from_account_info(&accounts[5]).unwrap();
assert_eq!(slot_hashes.len(), 1);
// Stake History
let stake_history = StakeHistory::from_account_info(&accounts[6]).unwrap();
assert_eq!(stake_history.len(), 1);
SUCCESS
}

View File

@ -79,10 +79,11 @@ mod bpf {
use super::*;
use solana_sdk::bpf_loader;
use solana_sdk::client::SyncClient;
use solana_sdk::clock::DEFAULT_SLOTS_PER_EPOCH;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::sysvar::clock;
use solana_sdk::sysvar::{clock, fees, rewards, slot_hashes, stake_history};
use std::io::Read;
use std::sync::Arc;
@ -93,7 +94,6 @@ 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),
@ -101,6 +101,7 @@ mod bpf {
("solana_bpf_rust_noop", true),
("solana_bpf_rust_panic", false),
("solana_bpf_rust_param_passing", true),
("solana_bpf_rust_sysval", true),
];
for program in programs.iter() {
let filename = create_bpf_path(program.0);
@ -110,13 +111,15 @@ mod bpf {
file.read_to_end(&mut elf).unwrap();
let GenesisBlockInfo {
genesis_block,
mut genesis_block,
mint_keypair,
..
} = create_genesis_block(50);
genesis_block.epoch_warmup = false;
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);
// Create bank with specific slot, used by solana_bpf_rust_sysvar test
let bank =
Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
let bank_client = BankClient::new(bank);
// Call user program
@ -125,6 +128,10 @@ mod bpf {
AccountMeta::new(mint_keypair.pubkey(), true),
AccountMeta::new(Keypair::new().pubkey(), false),
AccountMeta::new(clock::id(), false),
AccountMeta::new(fees::id(), false),
AccountMeta::new(rewards::id(), false),
AccountMeta::new(slot_hashes::id(), false),
AccountMeta::new(stake_history::id(), false),
];
let instruction = Instruction::new(program_id, &1u8, account_metas);
let result = bank_client.send_instruction(&mint_keypair, instruction);

View File

@ -16,7 +16,7 @@ log = "0.4.8"
serde = "1.0.100"
solana-logger = { path = "../../logger", version = "0.19.0-pre0" }
solana-sdk = { path = "../../sdk", version = "0.19.0-pre0" }
solana_rbpf = "=0.1.15"
solana_rbpf = "=0.1.16"
[lib]
crate-type = ["lib"]

View File

@ -147,7 +147,7 @@ fn test_stake_account_delegate() {
let rewards_account = bank
.get_account(&sysvar::rewards::id())
.expect("account not found");
assert_matches!(Rewards::from(&rewards_account), Some(_));
assert_matches!(Rewards::from_account(&rewards_account), Some(_));
// Redeem the credit
let bank_client = BankClient::new_shared(&bank);

View File

@ -401,7 +401,7 @@ fn test_validate_mining() {
let rewards = bank
.get_account(&rewards::id())
.map(|account| Rewards::from(&account).unwrap())
.map(|account| Rewards::from_account(&account).unwrap())
.unwrap();
let message = Message::new_with_payer(
vec![storage_instruction::claim_reward(

View File

@ -415,9 +415,9 @@ impl Bank {
.get_account(&slot_hashes::id())
.unwrap_or_else(|| slot_hashes::create_account(1, &[]));
let mut slot_hashes = SlotHashes::from(&account).unwrap();
let mut slot_hashes = SlotHashes::from_account(&account).unwrap();
slot_hashes.add(self.slot(), self.hash());
slot_hashes.to(&mut account).unwrap();
slot_hashes.to_account(&mut account).unwrap();
self.store_account(&slot_hashes::id(), &account);
}
@ -484,7 +484,7 @@ impl Bank {
mut validator_point_value: f64,
mut storage_point_value: f64,
) -> (f64, f64) {
let rewards = rewards::Rewards::from(
let rewards = rewards::Rewards::from_account(
&self
.get_account(&rewards::id())
.unwrap_or_else(|| rewards::create_account(1, 0.0, 0.0)),
@ -1620,7 +1620,7 @@ mod tests {
let rewards = bank1
.get_account(&rewards::id())
.map(|account| Rewards::from(&account).unwrap())
.map(|account| Rewards::from_account(&account).unwrap())
.unwrap();
assert!(
@ -2755,7 +2755,7 @@ mod tests {
let bank = Arc::new(Bank::new(&genesis_block));
let fees_account = bank.get_account(&fees::id()).unwrap();
let fees = Fees::from(&fees_account).unwrap();
let fees = Fees::from_account(&fees_account).unwrap();
assert_eq!(
bank.fee_calculator.lamports_per_signature,
fees.fee_calculator.lamports_per_signature

View File

@ -60,7 +60,7 @@ pub fn sol_log_slice(slice: &[u8]) {
/// Prints the hexadecimal representation of the program's input parameters
///
/// @param ka - A pointer to an array of `SolKeyedAccounts` to print
/// @param ka - A pointer to an array of `AccountInfo` to print
/// @param data - A pointer to the instruction data to print
#[allow(dead_code)]
pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
@ -73,8 +73,8 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
account.key.log();
sol_log("- Lamports");
sol_log_64(0, 0, 0, 0, *account.lamports);
sol_log("- AccountData");
sol_log_slice(account.data);
sol_log("- Account data length");
sol_log_64(0, 0, 0, 0, account.data.len() as u64);
sol_log("- Owner");
account.owner.log();
}

View File

@ -1,6 +1,7 @@
//! This account contains the current cluster fees
//!
use crate::account::Account;
use crate::account_info::AccountInfo;
use crate::fee_calculator::FeeCalculator;
use crate::sysvar;
use bincode::serialized_size;
@ -20,13 +21,18 @@ pub struct Fees {
}
impl Fees {
pub fn from(account: &Account) -> Option<Self> {
pub fn from_account(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut Account) -> Option<()> {
pub fn to_account(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn from_account_info(account: &AccountInfo) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to_account_info(&self, account: &mut AccountInfo) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&Fees::default()).unwrap() as usize
}
@ -51,7 +57,7 @@ mod tests {
fn test_fees_create_account() {
let lamports = 42;
let account = create_account(lamports, &FeeCalculator::default());
let fees = Fees::from(&account).unwrap();
let fees = Fees::from_account(&account).unwrap();
assert_eq!(fees.fee_calculator, FeeCalculator::default());
}
}

View File

@ -1,6 +1,7 @@
//! This account contains the current cluster rewards point values
//!
use crate::account::Account;
use crate::account_info::AccountInfo;
use crate::sysvar;
use bincode::serialized_size;
@ -20,10 +21,16 @@ pub struct Rewards {
}
impl Rewards {
pub fn from(account: &Account) -> Option<Self> {
pub fn from_account(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut Account) -> Option<()> {
pub fn to_account(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn from_account_info(account: &AccountInfo) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to_account_info(&self, account: &mut AccountInfo) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
@ -54,7 +61,7 @@ pub fn from_keyed_account(account: &KeyedAccount) -> Result<Rewards, Instruction
dbg!(account.unsigned_key());
return Err(InstructionError::InvalidArgument);
}
Rewards::from(account.account).ok_or(InstructionError::InvalidAccountData)
Rewards::from_account(account.account).ok_or(InstructionError::InvalidAccountData)
}
#[cfg(test)]
@ -64,7 +71,7 @@ mod tests {
#[test]
fn test_create_account() {
let account = create_account(1, 0.0, 0.0);
let rewards = Rewards::from(&account).unwrap();
let rewards = Rewards::from_account(&account).unwrap();
assert_eq!(rewards, Rewards::default());
}
}

View File

@ -3,6 +3,7 @@
//! this account carries the Bank's most recent blockhashes for some N parents
//!
use crate::account::Account;
use crate::account_info::AccountInfo;
use crate::hash::Hash;
use crate::sysvar;
use bincode::serialized_size;
@ -25,13 +26,18 @@ pub type SlotHash = (Slot, Hash);
pub struct SlotHashes(Vec<SlotHash>);
impl SlotHashes {
pub fn from(account: &Account) -> Option<Self> {
pub fn from_account(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut Account) -> Option<()> {
pub fn to_account(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn from_account_info(account: &AccountInfo) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to_account_info(&self, account: &mut AccountInfo) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&SlotHashes(vec![(0, Hash::default()); MAX_SLOT_HASHES])).unwrap() as usize
}
@ -62,7 +68,9 @@ impl Deref for SlotHashes {
pub fn create_account(lamports: u64, slot_hashes: &[SlotHash]) -> Account {
let mut account = Account::new(lamports, SlotHashes::size_of(), &sysvar::id());
SlotHashes::new(slot_hashes).to(&mut account).unwrap();
SlotHashes::new(slot_hashes)
.to_account(&mut account)
.unwrap();
account
}
@ -72,7 +80,7 @@ pub fn from_keyed_account(account: &KeyedAccount) -> Result<SlotHashes, Instruct
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
SlotHashes::from(account.account).ok_or(InstructionError::InvalidArgument)
SlotHashes::from_account(account.account).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)]
@ -85,7 +93,7 @@ mod tests {
let lamports = 42;
let account = create_account(lamports, &[]);
assert_eq!(account.data.len(), SlotHashes::size_of());
let slot_hashes = SlotHashes::from(&account);
let slot_hashes = SlotHashes::from_account(&account);
assert_eq!(slot_hashes, Some(SlotHashes(vec![])));
let mut slot_hashes = slot_hashes.unwrap();
for i in 0..MAX_SLOT_HASHES + 1 {

View File

@ -2,6 +2,7 @@
//!
//! this account carries history about stake activations and de-activations
//!
use crate::account_info::AccountInfo;
pub use crate::clock::Epoch;
use crate::{account::Account, sysvar};
use bincode::serialized_size;
@ -27,13 +28,18 @@ pub struct StakeHistoryEntry {
pub struct StakeHistory(Vec<(Epoch, StakeHistoryEntry)>);
impl StakeHistory {
pub fn from(account: &Account) -> Option<Self> {
pub fn from_account(account: &Account) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to(&self, account: &mut Account) -> Option<()> {
pub fn to_account(&self, account: &mut Account) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn from_account_info(account: &AccountInfo) -> Option<Self> {
account.deserialize_data().ok()
}
pub fn to_account_info(&self, account: &mut AccountInfo) -> Option<()> {
account.serialize_data(self).ok()
}
pub fn size_of() -> usize {
serialized_size(&StakeHistory(vec![
(0, StakeHistoryEntry::default());
@ -67,7 +73,7 @@ impl Deref for StakeHistory {
pub fn create_account(lamports: u64, stake_history: &StakeHistory) -> Account {
let mut account = Account::new(lamports, StakeHistory::size_of(), &sysvar::id());
stake_history.to(&mut account).unwrap();
stake_history.to_account(&mut account).unwrap();
account
}
@ -77,7 +83,7 @@ pub fn from_keyed_account(account: &KeyedAccount) -> Result<StakeHistory, Instru
if !check_id(account.unsigned_key()) {
return Err(InstructionError::InvalidArgument);
}
StakeHistory::from(account.account).ok_or(InstructionError::InvalidArgument)
StakeHistory::from_account(account.account).ok_or(InstructionError::InvalidArgument)
}
#[cfg(test)]
@ -90,7 +96,7 @@ mod tests {
let account = create_account(lamports, &StakeHistory::default());
assert_eq!(account.data.len(), StakeHistory::size_of());
let stake_history = StakeHistory::from(&account);
let stake_history = StakeHistory::from_account(&account);
assert_eq!(stake_history, Some(StakeHistory::default()));
let mut stake_history = stake_history.unwrap();
@ -115,7 +121,7 @@ mod tests {
);
// verify the account can hold a full instance
assert_eq!(
StakeHistory::from(&create_account(lamports, &stake_history)),
StakeHistory::from_account(&create_account(lamports, &stake_history)),
Some(stake_history)
);
}