Refactors the common code of test and bench targets into the solana_runtime::bpf_test_utils module. (#13203)

This commit is contained in:
Alexander Meißner 2020-10-29 10:04:47 +01:00 committed by GitHub
parent a9f339a3ed
commit 65ee3a6bdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 253 deletions

View File

@ -6,24 +6,22 @@ extern crate test;
extern crate solana_bpf_loader_program;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use solana_bpf_loader_program::syscalls::SyscallError;
use solana_measure::measure::Measure;
use solana_rbpf::vm::{EbpfVm, InstructionMeter};
use solana_runtime::{
bank::Bank,
bank_client::BankClient,
bpf_test_utils::MockInvokeContext,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
loader_utils::load_program,
process_instruction::{
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
},
process_instruction::{ComputeMeter, InvokeContext},
};
use solana_sdk::{
account::Account,
bpf_loader,
client::SyncClient,
entrypoint::SUCCESS,
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
instruction::{AccountMeta, Instruction},
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signer},
@ -193,7 +191,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
const BUDGET: u64 = 200_000;
let loader_id = bpf_loader::id();
let mut invoke_context = MockInvokeContext::default();
invoke_context.compute_meter.borrow_mut().remaining = BUDGET;
invoke_context.compute_meter.remaining = BUDGET;
let compute_meter = invoke_context.get_compute_meter();
let elf = load_elf("tuner").unwrap();
@ -248,80 +246,6 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
);
}
#[derive(Debug, Default)]
pub struct MockInvokeContext {
key: Pubkey,
logger: MockLogger,
compute_budget: ComputeBudget,
compute_meter: Rc<RefCell<MockComputeMeter>>,
}
impl InvokeContext for MockInvokeContext {
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
Ok(())
}
fn pop(&mut self) {}
fn verify_and_update(
&mut self,
_message: &Message,
_instruction: &CompiledInstruction,
_accounts: &[Rc<RefCell<Account>>],
) -> Result<(), InstructionError> {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_compute_budget(&self) -> &ComputeBudget {
&self.compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
self.compute_meter.clone()
}
fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc<dyn Executor>) {}
fn get_executor(&mut self, _pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
None
}
fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
}
#[derive(Debug, Default, Clone)]
pub struct MockLogger {
pub log: Rc<RefCell<Vec<String>>>,
}
impl Logger for MockLogger {
fn log_enabled(&self) -> bool {
true
}
fn log(&mut self, message: &str) {
self.log.borrow_mut().push(message.to_string());
}
}
#[derive(Debug, Default, Clone)]
pub struct MockComputeMeter {
pub remaining: u64,
}
impl ComputeMeter for MockComputeMeter {
fn consume(&mut self, amount: u64) -> Result<(), InstructionError> {
let exceeded = self.remaining < amount;
self.remaining = self.remaining.saturating_sub(amount);
if exceeded {
return Err(InstructionError::ComputationalBudgetExceeded);
}
Ok(())
}
fn get_remaining(&self) -> u64 {
self.remaining
}
}
/// Passed to the VM to enforce the compute budget
#[derive(Clone)]
struct MockInstructionMeter {

View File

@ -7,15 +7,14 @@ use solana_bpf_loader_program::{
create_vm,
serialization::{deserialize_parameters, serialize_parameters},
};
use solana_rbpf::vm::{EbpfVm, InstructionMeter};
use solana_rbpf::vm::EbpfVm;
use solana_runtime::{
bank::Bank,
bank_client::BankClient,
bpf_test_utils::MockInvokeContext,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
loader_utils::load_program,
process_instruction::{
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
},
process_instruction::ComputeBudget,
};
use solana_sdk::{
account::Account,
@ -31,7 +30,7 @@ use solana_sdk::{
sysvar::{clock, fees, rent, slot_hashes, stake_history},
transaction::{Transaction, TransactionError},
};
use std::{cell::RefCell, env, fs::File, io::Read, path::PathBuf, rc::Rc, sync::Arc};
use std::{cell::RefCell, env, fs::File, io::Read, path::PathBuf, sync::Arc};
/// BPF program file extension
const PLATFORM_FILE_EXTENSION_BPF: &str = "so";
@ -776,82 +775,6 @@ fn assert_instruction_count() {
}
}
// Mock InvokeContext
#[derive(Debug, Default)]
struct MockInvokeContext {
pub key: Pubkey,
pub logger: MockLogger,
pub compute_budget: ComputeBudget,
pub compute_meter: MockComputeMeter,
}
impl InvokeContext for MockInvokeContext {
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
Ok(())
}
fn pop(&mut self) {}
fn verify_and_update(
&mut self,
_message: &Message,
_instruction: &CompiledInstruction,
_accounts: &[Rc<RefCell<Account>>],
) -> Result<(), InstructionError> {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_compute_budget(&self) -> &ComputeBudget {
&self.compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.compute_meter.clone()))
}
fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc<dyn Executor>) {}
fn get_executor(&mut self, _pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
None
}
fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
}
#[derive(Debug, Default, Clone)]
struct MockComputeMeter {}
impl ComputeMeter for MockComputeMeter {
fn consume(&mut self, _amount: u64) -> Result<(), InstructionError> {
Ok(())
}
fn get_remaining(&self) -> u64 {
u64::MAX
}
}
#[derive(Debug, Default, Clone)]
struct MockLogger {}
impl Logger for MockLogger {
fn log_enabled(&self) -> bool {
true
}
fn log(&mut self, _message: &str) {
// println!("{}", message);
}
}
struct TestInstructionMeter {}
impl InstructionMeter for TestInstructionMeter {
fn consume(&mut self, _amount: u64) {}
fn get_remaining(&self) -> u64 {
u64::MAX
}
}
#[cfg(any(feature = "bpf_rust"))]
#[test]
fn test_program_bpf_instruction_introspection() {

View File

@ -313,102 +313,14 @@ mod tests {
use super::*;
use rand::Rng;
use solana_runtime::{
bpf_test_utils::MockInvokeContext,
feature_set::FeatureSet,
message_processor::{Executors, ThisInvokeContext},
process_instruction::{ComputeBudget, Logger, ProcessInstruction},
};
use solana_sdk::{
account::Account, instruction::CompiledInstruction, instruction::Instruction,
message::Message, rent::Rent,
process_instruction::ComputeBudget,
};
use solana_sdk::{account::Account, rent::Rent};
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
#[derive(Debug, Default, Clone)]
pub struct MockComputeMeter {
pub remaining: u64,
}
impl ComputeMeter for MockComputeMeter {
fn consume(&mut self, amount: u64) -> Result<(), InstructionError> {
let exceeded = self.remaining < amount;
self.remaining = self.remaining.saturating_sub(amount);
if exceeded {
return Err(InstructionError::ComputationalBudgetExceeded);
}
Ok(())
}
fn get_remaining(&self) -> u64 {
self.remaining
}
}
#[derive(Debug, Default, Clone)]
pub struct MockLogger {
pub log: Rc<RefCell<Vec<String>>>,
}
impl Logger for MockLogger {
fn log_enabled(&self) -> bool {
true
}
fn log(&mut self, message: &str) {
self.log.borrow_mut().push(message.to_string());
}
}
#[derive(Debug)]
pub struct MockInvokeContext {
pub key: Pubkey,
pub logger: MockLogger,
pub compute_budget: ComputeBudget,
pub compute_meter: MockComputeMeter,
}
impl Default for MockInvokeContext {
fn default() -> Self {
MockInvokeContext {
key: Pubkey::default(),
logger: MockLogger::default(),
compute_budget: ComputeBudget::default(),
compute_meter: MockComputeMeter {
remaining: std::u64::MAX,
},
}
}
}
impl InvokeContext for MockInvokeContext {
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
Ok(())
}
fn pop(&mut self) {}
fn verify_and_update(
&mut self,
_message: &Message,
_instruction: &CompiledInstruction,
_accounts: &[Rc<RefCell<Account>>],
) -> Result<(), InstructionError> {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_compute_budget(&self) -> &ComputeBudget {
&self.compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.compute_meter.clone()))
}
fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc<dyn Executor>) {}
fn get_executor(&mut self, _pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
None
}
fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
}
struct TestInstructionMeter {
remaining: u64,
}

View File

@ -1237,7 +1237,7 @@ fn call<'a>(
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::{MockComputeMeter, MockLogger};
use solana_runtime::bpf_test_utils::{MockComputeMeter, MockLogger};
use solana_sdk::hash::hashv;
use std::str::FromStr;

View File

@ -0,0 +1,96 @@
use crate::process_instruction::{
ComputeBudget, ComputeMeter, Executor, InvokeContext, Logger, ProcessInstruction,
};
use solana_sdk::{
account::Account, instruction::CompiledInstruction, instruction::Instruction,
instruction::InstructionError, message::Message, pubkey::Pubkey,
};
use std::{cell::RefCell, rc::Rc, sync::Arc};
#[derive(Debug, Default, Clone)]
pub struct MockComputeMeter {
pub remaining: u64,
}
impl ComputeMeter for MockComputeMeter {
fn consume(&mut self, amount: u64) -> Result<(), InstructionError> {
let exceeded = self.remaining < amount;
self.remaining = self.remaining.saturating_sub(amount);
if exceeded {
return Err(InstructionError::ComputationalBudgetExceeded);
}
Ok(())
}
fn get_remaining(&self) -> u64 {
self.remaining
}
}
#[derive(Debug, Default, Clone)]
pub struct MockLogger {
pub log: Rc<RefCell<Vec<String>>>,
}
impl Logger for MockLogger {
fn log_enabled(&self) -> bool {
true
}
fn log(&mut self, message: &str) {
self.log.borrow_mut().push(message.to_string());
}
}
#[derive(Debug)]
pub struct MockInvokeContext {
pub key: Pubkey,
pub logger: MockLogger,
pub compute_budget: ComputeBudget,
pub compute_meter: MockComputeMeter,
}
impl Default for MockInvokeContext {
fn default() -> Self {
MockInvokeContext {
key: Pubkey::default(),
logger: MockLogger::default(),
compute_budget: ComputeBudget::default(),
compute_meter: MockComputeMeter {
remaining: std::i64::MAX as u64,
},
}
}
}
impl InvokeContext for MockInvokeContext {
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
Ok(())
}
fn pop(&mut self) {}
fn verify_and_update(
&mut self,
_message: &Message,
_instruction: &CompiledInstruction,
_accounts: &[Rc<RefCell<Account>>],
) -> Result<(), InstructionError> {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_compute_budget(&self) -> &ComputeBudget {
&self.compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.compute_meter.clone()))
}
fn add_executor(&mut self, _pubkey: &Pubkey, _executor: Arc<dyn Executor>) {}
fn get_executor(&mut self, _pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
None
}
fn record_instruction(&self, _instruction: &Instruction) {}
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true
}
}

View File

@ -10,6 +10,7 @@ pub mod bank_forks;
pub mod bank_utils;
mod blockhash_queue;
pub mod bloom;
pub mod bpf_test_utils;
pub mod builtins;
pub mod commitment;
pub mod epoch_stakes;