Native/builtin programs now receive an InvokeContext (bp #13286) (#13298)

* Native/builtin programs now receive an InvokeContext

(cherry picked from commit df8dab9d2b)

* Remove MessageProcessor::loaders

(cherry picked from commit 2664a1f7ef)

* Remove Entrypoint type

(cherry picked from commit 225bed11c7)

* Remove programs clone()

(cherry picked from commit 33884d847a)

* Add sol_log_compute_units syscall

(cherry picked from commit 66e51a7363)

* Add Bank::set_bpf_compute_budget()

(cherry picked from commit 7d686b72a0)

* Rebase

Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
mergify[bot]
2020-10-30 07:47:17 +00:00
committed by GitHub
parent 36b7c2ea97
commit 40a3885d3b
43 changed files with 631 additions and 477 deletions

3
Cargo.lock generated
View File

@ -3699,7 +3699,6 @@ dependencies = [
"solana-logger 1.4.4",
"solana-net-utils",
"solana-remote-wallet",
"solana-runtime",
"solana-sdk 1.4.4",
"solana-stake-program",
"solana-transaction-status",
@ -4586,6 +4585,7 @@ dependencies = [
"hex",
"hmac",
"itertools 0.9.0",
"lazy_static",
"libsecp256k1",
"log 0.4.8",
"memmap",
@ -4909,7 +4909,6 @@ dependencies = [
"solana-frozen-abi",
"solana-frozen-abi-macro",
"solana-logger 1.4.4",
"solana-runtime",
"solana-sdk 1.4.4",
]

View File

@ -86,7 +86,7 @@ fn test_exchange_bank_client() {
solana_logger::setup();
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program("exchange_program", id(), process_instruction);
bank.add_builtin("exchange_program", id(), process_instruction);
let clients = vec![BankClient::new(bank)];
let mut config = Config::default();

View File

@ -39,7 +39,6 @@ solana-logger = { path = "../logger", version = "1.4.4" }
solana-net-utils = { path = "../net-utils", version = "1.4.4" }
solana_rbpf = "=0.1.32"
solana-remote-wallet = { path = "../remote-wallet", version = "1.4.4" }
solana-runtime = { path = "../runtime", version = "1.4.4" }
solana-sdk = { path = "../sdk", version = "1.4.4" }
solana-stake-program = { path = "../programs/stake", version = "1.4.4" }
solana-transaction-status = { path = "../transaction-status", version = "1.4.4" }

View File

@ -9,12 +9,14 @@ use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*};
use solana_cli_output::{QuietDisplay, VerboseDisplay};
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_runtime::{
use solana_sdk::{
clock::Slot,
feature::{self, Feature},
feature_set::FEATURE_NAMES,
};
use solana_sdk::{
clock::Slot, message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction,
message::Message,
pubkey::Pubkey,
system_instruction,
transaction::Transaction,
};
use std::{collections::HashMap, fmt, sync::Arc};

View File

@ -1,8 +1,8 @@
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
use solana_ledger::blockstore::Blockstore;
use solana_measure::measure::Measure;
use solana_runtime::{bank::Bank, feature_set};
use solana_sdk::timing::slot_duration_from_slots_per_year;
use solana_runtime::bank::Bank;
use solana_sdk::{feature_set, timing::slot_duration_from_slots_per_year};
use std::{
collections::HashMap,
sync::{

View File

@ -52,10 +52,10 @@ use solana_perf::packet::{
};
use solana_rayon_threadlimit::get_thread_count;
use solana_runtime::bank_forks::BankForks;
use solana_runtime::feature_set::{self, FeatureSet};
use solana_sdk::hash::Hash;
use solana_sdk::{
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH},
feature_set::{self, FeatureSet},
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, Signable, Signature, Signer},
timing::timestamp,

View File

@ -1,8 +1,5 @@
use solana_runtime::{
bank::{Builtin, Builtins, Entrypoint},
feature_set,
};
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
use solana_runtime::bank::{Builtin, Builtins};
use solana_sdk::{feature_set, genesis_config::ClusterType, pubkey::Pubkey};
/// Builtin programs that are always available
fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
@ -19,7 +16,7 @@ fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
builtins
.into_iter()
.map(|b| Builtin::new(&b.0, b.1, Entrypoint::Loader(b.2)))
.map(|b| Builtin::new(&b.0, b.1, b.2))
.collect()
}
@ -32,7 +29,7 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey)> {
builtins
.into_iter()
.map(|(b, p)| (Builtin::new(&b.0, b.1, Entrypoint::Loader(b.2)), p))
.map(|(b, p)| (Builtin::new(&b.0, b.1, b.2), p))
.collect()
}

View File

@ -2211,6 +2211,7 @@ dependencies = [
"hex",
"hmac",
"itertools",
"lazy_static",
"libsecp256k1",
"log",
"memmap",

View File

@ -11,10 +11,8 @@ 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::{ComputeMeter, InvokeContext},
};
use solana_sdk::{
account::Account,
@ -23,6 +21,7 @@ use solana_sdk::{
entrypoint::SUCCESS,
instruction::{AccountMeta, Instruction},
message::Message,
process_instruction::{ComputeMeter, InvokeContext, MockInvokeContext},
pubkey::Pubkey,
signature::{Keypair, Signer},
};
@ -161,7 +160,7 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);

View File

@ -18,5 +18,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
// program, no account keys or input data are expected but real
// programs will have specific requirements so they can do their work.
sol_log_params(&params);
sol_log_compute_units();
return SUCCESS;
}

View File

@ -61,6 +61,7 @@ fn process_instruction(
panic!();
}
sol_log_compute_units();
Ok(())
}

View File

@ -11,10 +11,8 @@ 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,
};
use solana_sdk::{
account::Account,
@ -25,6 +23,7 @@ use solana_sdk::{
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount,
message::Message,
process_instruction::{BpfComputeBudget, MockInvokeContext},
pubkey::Pubkey,
signature::{Keypair, Signer},
sysvar::{clock, fees, rent, slot_hashes, stake_history},
@ -179,7 +178,7 @@ fn test_program_bpf_sanity() {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank = Arc::new(bank);
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test
@ -233,7 +232,7 @@ fn test_program_bpf_loader_deprecated() {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank_client = BankClient::new(bank);
let program_id = load_bpf_program(
@ -273,7 +272,7 @@ fn test_program_bpf_duplicate_accounts() {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
@ -358,7 +357,7 @@ fn test_program_bpf_error_handling() {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank_client = BankClient::new(bank);
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
@ -475,7 +474,7 @@ fn test_program_bpf_invoke() {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
@ -706,7 +705,7 @@ fn test_program_bpf_call_depth() {
} = create_genesis_config(50);
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank_client = BankClient::new(bank);
let program_id = load_bpf_program(
&bank_client,
@ -717,14 +716,14 @@ fn test_program_bpf_call_depth() {
let instruction = Instruction::new(
program_id,
&(ComputeBudget::default().max_call_depth - 1),
&(BpfComputeBudget::default().max_call_depth - 1),
vec![],
);
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert!(result.is_ok());
let instruction =
Instruction::new(program_id, &ComputeBudget::default().max_call_depth, vec![]);
Instruction::new(program_id, &BpfComputeBudget::default().max_call_depth, vec![]);
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
assert!(result.is_err());
}
@ -788,7 +787,7 @@ fn test_program_bpf_instruction_introspection() {
let mut bank = Bank::new(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_program!();
bank.add_builtin_loader(&name, id, entrypoint);
bank.add_builtin(&name, id, entrypoint);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);

View File

@ -16,17 +16,15 @@ use solana_rbpf::{
memory_region::MemoryRegion,
vm::{Config, EbpfVm, Executable, InstructionMeter},
};
use solana_runtime::{
feature_set::compute_budget_balancing,
process_instruction::{ComputeMeter, Executor, InvokeContext},
};
use solana_sdk::{
bpf_loader, bpf_loader_deprecated,
decode_error::DecodeError,
entrypoint::SUCCESS,
feature_set::bpf_compute_budget_balancing,
instruction::InstructionError,
keyed_account::{is_executable, next_keyed_account, KeyedAccount},
loader_instruction::LoaderInstruction,
process_instruction::{ComputeMeter, Executor, InvokeContext},
program_utils::limited_deserialize,
pubkey::Pubkey,
};
@ -101,7 +99,7 @@ pub fn create_and_cache_executor(
.map_err(|e| map_ebpf_error(invoke_context, e))?;
bpf_verifier::check(
elf_bytes,
!invoke_context.is_feature_active(&compute_budget_balancing::id()),
!invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()),
)
.map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
let executor = Arc::new(BPFExecutor { executable });
@ -116,12 +114,12 @@ pub fn create_vm<'a>(
parameter_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext,
) -> Result<(EbpfVm<'a, BPFError>, MemoryRegion), EbpfError<BPFError>> {
let compute_budget = invoke_context.get_compute_budget();
let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
let mut vm = EbpfVm::new(
executable,
Config {
max_call_depth: compute_budget.max_call_depth,
stack_frame_size: compute_budget.stack_frame_size,
max_call_depth: bpf_compute_budget.max_call_depth,
stack_frame_size: bpf_compute_budget.stack_frame_size,
},
)?;
let heap_region =
@ -312,13 +310,14 @@ impl Executor for BPFExecutor {
mod tests {
use super::*;
use rand::Rng;
use solana_runtime::{
bpf_test_utils::MockInvokeContext,
use solana_runtime::message_processor::{Executors, ThisInvokeContext};
use solana_sdk::{
account::Account,
feature_set::FeatureSet,
message_processor::{Executors, ThisInvokeContext},
process_instruction::ComputeBudget,
instruction::InstructionError,
process_instruction::{BpfComputeBudget, MockInvokeContext},
rent::Rent,
};
use solana_sdk::{account::Account, rent::Rent};
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
struct TestInstructionMeter {
@ -533,9 +532,9 @@ mod tests {
&program_id,
Rent::default(),
vec![],
vec![],
&[],
None,
ComputeBudget {
BpfComputeBudget {
max_units: 1,
log_units: 100,
log_64_units: 100,

View File

@ -7,22 +7,21 @@ use solana_rbpf::{
memory_region::{translate_addr, MemoryRegion},
vm::{EbpfVm, SyscallObject},
};
use solana_runtime::{
feature_set::{
pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled,
},
message_processor::MessageProcessor,
process_instruction::{ComputeMeter, InvokeContext, Logger},
};
use solana_runtime::message_processor::MessageProcessor;
use solana_sdk::{
account::Account,
account_info::AccountInfo,
bpf_loader, bpf_loader_deprecated,
bpf_loader_deprecated,
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
feature_set::{
pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled,
sol_log_compute_units_syscall,
},
hash::{Hasher, HASH_BYTES},
instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::KeyedAccount,
message::Message,
process_instruction::{ComputeMeter, InvokeContext, Logger},
program_error::ProgramError,
pubkey::{Pubkey, PubkeyError},
};
@ -98,7 +97,7 @@ pub fn register_syscalls<'a>(
callers_keyed_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext,
) -> Result<MemoryRegion, EbpfError<BPFError>> {
let compute_budget = invoke_context.get_compute_budget();
let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
// Syscall functions common across languages
@ -107,7 +106,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex(
"sol_log_",
Box::new(SyscallLog {
cost: compute_budget.log_units,
cost: bpf_compute_budget.log_units,
compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(),
loader_id,
@ -116,17 +115,27 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex(
"sol_log_64_",
Box::new(SyscallLogU64 {
cost: compute_budget.log_64_units,
cost: bpf_compute_budget.log_64_units,
compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(),
}),
)?;
if invoke_context.is_feature_active(&sol_log_compute_units_syscall::id()) {
vm.register_syscall_with_context_ex(
"sol_log_compute_units_",
Box::new(SyscallLogBpfComputeUnits {
cost: 0,
compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(),
}),
)?;
}
if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) {
vm.register_syscall_with_context_ex(
"sol_log_pubkey",
Box::new(SyscallLogPubkey {
cost: compute_budget.log_pubkey_units,
cost: bpf_compute_budget.log_pubkey_units,
compute_meter: invoke_context.get_compute_meter(),
logger: invoke_context.get_logger(),
loader_id,
@ -138,8 +147,8 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex(
"sol_sha256",
Box::new(SyscallSha256 {
sha256_base_cost: compute_budget.sha256_base_cost,
sha256_byte_cost: compute_budget.sha256_byte_cost,
sha256_base_cost: bpf_compute_budget.sha256_base_cost,
sha256_byte_cost: bpf_compute_budget.sha256_byte_cost,
compute_meter: invoke_context.get_compute_meter(),
loader_id,
}),
@ -160,7 +169,7 @@ pub fn register_syscalls<'a>(
vm.register_syscall_with_context_ex(
"sol_create_program_address",
Box::new(SyscallCreateProgramAddress {
cost: compute_budget.create_program_address_units,
cost: bpf_compute_budget.create_program_address_units,
compute_meter: invoke_context.get_compute_meter(),
loader_id,
}),
@ -414,6 +423,38 @@ impl SyscallObject<BPFError> for SyscallLogU64 {
}
}
/// Log current compute consumption
pub struct SyscallLogBpfComputeUnits {
cost: u64,
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
logger: Rc<RefCell<dyn Logger>>,
}
impl SyscallObject<BPFError> for SyscallLogBpfComputeUnits {
fn call(
&mut self,
_arg1: u64,
_arg2: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
_ro_regions: &[MemoryRegion],
_rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> {
self.compute_meter.consume(self.cost)?;
let mut logger = self
.logger
.try_borrow_mut()
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
if logger.log_enabled() {
logger.log(&format!(
"Program consumption: {} units remaining",
self.compute_meter.borrow().get_remaining()
));
}
Ok(0)
}
}
/// Log 5 64-bit values
pub struct SyscallLogPubkey<'a> {
cost: u64,
@ -1147,7 +1188,7 @@ fn call<'a>(
let mut invoke_context = syscall.get_context_mut()?;
invoke_context
.get_compute_meter()
.consume(invoke_context.get_compute_budget().invoke_units)?;
.consume(invoke_context.get_bpf_compute_budget().invoke_units)?;
// Translate data passed from the VM
@ -1185,8 +1226,6 @@ fn call<'a>(
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
message_processor.add_program(*program_id, *process_instruction);
}
message_processor.add_loader(bpf_loader::id(), crate::process_instruction);
message_processor.add_loader(bpf_loader_deprecated::id(), crate::process_instruction);
#[allow(clippy::deref_addrof)]
match message_processor.process_cross_program_instruction(
@ -1237,8 +1276,11 @@ fn call<'a>(
#[cfg(test)]
mod tests {
use super::*;
use solana_runtime::bpf_test_utils::{MockComputeMeter, MockLogger};
use solana_sdk::hash::hashv;
use solana_sdk::{
bpf_loader,
hash::hashv,
process_instruction::{MockComputeMeter, MockLogger},
};
use std::str::FromStr;
macro_rules! assert_access_violation {

View File

@ -10,6 +10,7 @@ use solana_sdk::{
hash::hash,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
};
@ -116,6 +117,7 @@ pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter();
let instruction = limited_deserialize(data)?;
@ -238,7 +240,7 @@ mod tests {
fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program("budget_program", id(), process_instruction);
bank.add_builtin("budget_program", id(), process_instruction);
(bank, mint_keypair)
}

View File

@ -3,15 +3,19 @@
use crate::ConfigKeys;
use bincode::deserialize;
use log::*;
use solana_sdk::instruction::InstructionError;
use solana_sdk::keyed_account::{next_keyed_account, KeyedAccount};
use solana_sdk::program_utils::limited_deserialize;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
};
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let key_list: ConfigKeys = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter();
@ -109,6 +113,7 @@ mod tests {
use solana_sdk::{
account::Account,
keyed_account::create_keyed_is_signer_accounts,
process_instruction::MockInvokeContext,
signature::{Keypair, Signer},
system_instruction::SystemInstruction,
};
@ -162,7 +167,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instructions[1].data),
process_instruction(
&id(),
&keyed_accounts,
&instructions[1].data,
&mut MockInvokeContext::default()
),
Ok(())
);
@ -192,7 +202,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(())
);
assert_eq!(
@ -214,7 +229,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidInstructionData)
);
}
@ -232,7 +252,12 @@ mod tests {
let accounts = vec![(&config_pubkey, false, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature)
);
}
@ -262,7 +287,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(())
);
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
@ -288,7 +318,12 @@ mod tests {
let accounts = vec![(&signer0_pubkey, true, &signer0_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidAccountData)
);
}
@ -314,7 +349,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature)
);
@ -325,7 +365,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature)
);
}
@ -357,7 +402,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(())
);
@ -372,7 +422,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(())
);
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
@ -392,7 +447,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature)
);
@ -410,7 +470,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature)
);
}
@ -443,7 +508,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(())
);
@ -457,7 +527,12 @@ mod tests {
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Ok(())
);
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
@ -473,7 +548,12 @@ mod tests {
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instruction.data),
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
),
Err(InstructionError::MissingRequiredSignature)
);
}
@ -487,7 +567,12 @@ mod tests {
let accounts = vec![];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
assert_eq!(
process_instruction(&id(), &keyed_accounts, &instructions[1].data),
process_instruction(
&id(),
&keyed_accounts,
&instructions[1].data,
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys)
);
}

View File

@ -9,7 +9,7 @@ use serde_derive::Serialize;
use solana_metrics::inc_new_counter_info;
use solana_sdk::{
decode_error::DecodeError, instruction::InstructionError, keyed_account::KeyedAccount,
program_utils::limited_deserialize, pubkey::Pubkey,
process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey,
};
use std::cmp;
use thiserror::Error;
@ -464,6 +464,7 @@ pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
solana_logger::setup();
@ -578,7 +579,7 @@ mod test {
fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program("exchange_program", id(), process_instruction);
bank.add_builtin("exchange_program", id(), process_instruction);
(bank, mint_keypair)
}

View File

@ -1,6 +1,7 @@
use solana_sdk::instruction::InstructionError;
use solana_sdk::keyed_account::KeyedAccount;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
pubkey::Pubkey,
};
solana_sdk::declare_program!(
"FaiLure111111111111111111111111111111111111",
@ -12,6 +13,7 @@ fn process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
Err(InstructionError::Custom(0))
}

View File

@ -1,7 +1,8 @@
use log::*;
use solana_sdk::instruction::InstructionError;
use solana_sdk::keyed_account::KeyedAccount;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
pubkey::Pubkey,
};
solana_sdk::declare_program!(
"Noop111111111111111111111111111111111111111",
@ -13,6 +14,7 @@ fn process_instruction(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
solana_logger::setup();
trace!("noop: program_id: {:?}", program_id);

View File

@ -5,6 +5,7 @@ use bincode::serialize_into;
use solana_sdk::{
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
};
@ -30,6 +31,7 @@ pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let new_owner_pubkey: Pubkey = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter();
@ -71,7 +73,7 @@ mod tests {
fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program("ownable_program", crate::id(), process_instruction);
bank.add_builtin("ownable_program", crate::id(), process_instruction);
(bank, mint_keypair)
}

View File

@ -1,24 +1,20 @@
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{
instruction::{Instruction, InstructionError},
keyed_account::KeyedAccount,
process_instruction::InvokeContext,
pubkey::Pubkey,
};
pub fn process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
// Should be already checked by now.
Ok(())
}
solana_sdk::declare_program!(
solana_sdk::secp256k1_program::ID,
solana_keccak_secp256k1_program,
process_instruction
);
pub fn new_secp256k1_instruction(
priv_key: &secp256k1::SecretKey,
message_arr: &[u8],

View File

@ -10,6 +10,7 @@ use solana_sdk::{
decode_error::DecodeError,
instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
system_instruction,
@ -446,6 +447,7 @@ pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts);
@ -525,6 +527,7 @@ mod tests {
use bincode::serialize;
use solana_sdk::{
account::{self, Account},
process_instruction::MockInvokeContext,
rent::Rent,
sysvar::stake_history::StakeHistory,
};
@ -562,7 +565,12 @@ mod tests {
.zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect();
super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data)
super::process_instruction(
&Pubkey::default(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default(),
)
}
}
@ -661,6 +669,7 @@ mod tests {
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);
@ -679,6 +688,7 @@ mod tests {
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);
@ -696,6 +706,7 @@ mod tests {
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidArgument),
);
@ -717,6 +728,7 @@ mod tests {
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidAccountData),
);
@ -731,6 +743,7 @@ mod tests {
&create_default_account()
),],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);
@ -745,6 +758,7 @@ mod tests {
&create_default_account()
)],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);
@ -776,6 +790,7 @@ mod tests {
),
],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidAccountData),
);
@ -802,6 +817,7 @@ mod tests {
),
],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidArgument),
);
@ -816,6 +832,7 @@ mod tests {
&create_default_account()
)],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);
@ -836,6 +853,7 @@ mod tests {
),
],
&serialize(&StakeInstruction::Deactivate).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::InvalidArgument),
);
@ -846,6 +864,7 @@ mod tests {
&Pubkey::default(),
&[],
&serialize(&StakeInstruction::Deactivate).unwrap(),
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);

View File

@ -10,6 +10,7 @@ use solana_sdk::{
account::Account,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
};
@ -59,6 +60,7 @@ pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter();
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?;
@ -162,7 +164,7 @@ mod tests {
fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program("vest_program", id(), process_instruction);
bank.add_builtin("vest_program", id(), process_instruction);
(bank, mint_keypair)
}

View File

@ -14,6 +14,7 @@ use solana_sdk::{
hash::Hash,
instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
system_instruction,
@ -277,6 +278,7 @@ pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts);
@ -333,6 +335,7 @@ mod tests {
use super::*;
use solana_sdk::{
account::{self, Account},
process_instruction::MockInvokeContext,
rent::Rent,
};
use std::cell::RefCell;
@ -341,7 +344,12 @@ mod tests {
#[test]
fn test_vote_process_instruction_decode_bail() {
assert_eq!(
super::process_instruction(&Pubkey::default(), &[], &[],),
super::process_instruction(
&Pubkey::default(),
&[],
&[],
&mut MockInvokeContext::default()
),
Err(InstructionError::NotEnoughAccountKeys),
);
}
@ -374,7 +382,12 @@ mod tests {
.zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect();
super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data)
super::process_instruction(
&Pubkey::default(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default(),
)
}
}

View File

@ -12,6 +12,7 @@ use solana_sdk::{
instruction::InstructionError,
keyed_account::KeyedAccount,
message::Message,
process_instruction::InvokeContext,
pubkey::Pubkey,
signature::{Keypair, Signer},
transaction::Transaction,
@ -33,6 +34,7 @@ fn process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
Ok(())
}
@ -123,7 +125,7 @@ fn do_bench_transactions(
let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000);
genesis_config.ticks_per_slot = 100;
let mut bank = Bank::new(&genesis_config);
bank.add_builtin_program(
bank.add_builtin(
"builtin_program",
Pubkey::new(&BUILTIN_PROGRAM_ID),
process_instruction,

View File

@ -17,10 +17,6 @@ use crate::{
instruction_recorder::InstructionRecorder,
log_collector::LogCollector,
message_processor::{Executors, MessageProcessor},
process_instruction::{
ErasedProcessInstruction, ErasedProcessInstructionWithContext, Executor,
ProcessInstruction, ProcessInstructionWithContext,
},
rent_collector::RentCollector,
stakes::Stakes,
status_cache::{SlotDelta, StatusCache},
@ -55,6 +51,7 @@ use solana_sdk::{
native_loader,
native_token::sol_to_lamports,
nonce, nonce_account,
process_instruction::{BpfComputeBudget, Executor, ProcessInstructionWithContext},
program_utils::limited_deserialize,
pubkey::Pubkey,
recent_blockhashes_account,
@ -138,52 +135,33 @@ type RentCollectionCycleParams = (
type EpochCount = u64;
#[derive(Copy, Clone)]
pub enum Entrypoint {
Program(ProcessInstruction),
Loader(ProcessInstructionWithContext),
}
impl fmt::Debug for Entrypoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[derive(Debug)]
enum EntrypointForDebug {
Program(String),
Loader(String),
}
// rustc doesn't compile due to bug without this work around
// https://github.com/rust-lang/rust/issues/50280
// https://users.rust-lang.org/t/display-function-pointer/17073/2
let entrypoint = match self {
Entrypoint::Program(instruction) => EntrypointForDebug::Program(format!(
"{:p}",
*instruction as ErasedProcessInstruction
)),
Entrypoint::Loader(instruction) => EntrypointForDebug::Loader(format!(
"{:p}",
*instruction as ErasedProcessInstructionWithContext
)),
};
write!(f, "{:?}", entrypoint)
}
}
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct Builtin {
pub name: String,
pub id: Pubkey,
pub entrypoint: Entrypoint,
pub process_instruction_with_context: ProcessInstructionWithContext,
}
impl Builtin {
pub fn new(name: &str, id: Pubkey, entrypoint: Entrypoint) -> Self {
pub fn new(
name: &str,
id: Pubkey,
process_instruction_with_context: ProcessInstructionWithContext,
) -> Self {
Self {
name: name.to_string(),
id,
entrypoint,
process_instruction_with_context,
}
}
}
impl fmt::Debug for Builtin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Builtin [name={}, id={}]", self.name, self.id)
}
}
/// Copy-on-write holder of CachedExecutors
#[derive(AbiExample, Debug, Default)]
struct CowCachedExecutors {
@ -224,7 +202,7 @@ impl AbiExample for Builtin {
Self {
name: String::default(),
id: Pubkey::default(),
entrypoint: Entrypoint::Program(|_, _, _| Ok(())),
process_instruction_with_context: |_, _, _, _| Ok(()),
}
}
}
@ -693,6 +671,8 @@ pub struct Bank {
/// The Message processor
message_processor: MessageProcessor,
bpf_compute_budget: Option<BpfComputeBudget>,
/// Builtin programs activated dynamically by feature
feature_builtins: Arc<Vec<(Builtin, Pubkey)>>,
@ -829,6 +809,7 @@ impl Bank {
tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
signature_count: AtomicU64::new(0),
message_processor: parent.message_processor.clone(),
bpf_compute_budget: parent.bpf_compute_budget,
feature_builtins: parent.feature_builtins.clone(),
hard_forks: parent.hard_forks.clone(),
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
@ -934,6 +915,7 @@ impl Bank {
epoch_stakes: fields.epoch_stakes,
is_delta: AtomicBool::new(fields.is_delta),
message_processor: new(),
bpf_compute_budget: None,
feature_builtins: new(),
last_vote_sync: new(),
rewards: new(),
@ -2375,6 +2357,9 @@ impl Bank {
let mut inner_instructions: Vec<Option<InnerInstructionsList>> =
Vec::with_capacity(txs.len());
let mut transaction_logs: Vec<TransactionLogMessages> = Vec::with_capacity(txs.len());
let bpf_compute_budget = self
.bpf_compute_budget
.unwrap_or_else(|| BpfComputeBudget::new(&self.feature_set));
let executed: Vec<TransactionProcessResult> = loaded_accounts
.iter_mut()
@ -2413,6 +2398,7 @@ impl Bank {
executors.clone(),
instruction_recorders.as_deref(),
self.feature_set.clone(),
bpf_compute_budget,
);
if enable_log_recording {
@ -3365,7 +3351,11 @@ impl Bank {
.extend_from_slice(&additional_builtins.feature_builtins);
}
for builtin in builtins.genesis_builtins {
self.add_builtin(&builtin.name, builtin.id, builtin.entrypoint);
self.add_builtin(
&builtin.name,
builtin.id,
builtin.process_instruction_with_context,
);
}
self.feature_builtins = Arc::new(builtins.feature_builtins);
@ -3376,6 +3366,10 @@ impl Bank {
*self.inflation.write().unwrap() = inflation;
}
pub fn set_bpf_compute_budget(&mut self, bpf_compute_budget: Option<BpfComputeBudget>) {
self.bpf_compute_budget = bpf_compute_budget;
}
pub fn hard_forks(&self) -> Arc<RwLock<HardForks>> {
self.hard_forks.clone()
}
@ -3823,43 +3817,17 @@ impl Bank {
!self.is_delta.load(Relaxed)
}
pub fn add_builtin_program(
&mut self,
name: &str,
program_id: Pubkey,
process_instruction: ProcessInstruction,
) {
self.add_builtin(name, program_id, Entrypoint::Program(process_instruction));
}
pub fn add_builtin_loader(
/// Add an instruction processor to intercept instructions before the dynamic loader.
pub fn add_builtin(
&mut self,
name: &str,
program_id: Pubkey,
process_instruction_with_context: ProcessInstructionWithContext,
) {
self.add_builtin(
name,
program_id,
Entrypoint::Loader(process_instruction_with_context),
);
}
/// Add an instruction processor to intercept instructions before the dynamic loader.
pub fn add_builtin(&mut self, name: &str, program_id: Pubkey, entrypoint: Entrypoint) {
debug!("Added program {} under {:?}", name, program_id);
self.add_native_program(name, &program_id);
match entrypoint {
Entrypoint::Program(process_instruction) => {
self.message_processor
.add_program(program_id, process_instruction);
debug!("Added builtin program {} under {:?}", name, program_id);
}
Entrypoint::Loader(process_instruction_with_context) => {
self.message_processor
.add_loader(program_id, process_instruction_with_context);
debug!("Added builtin loader {} under {:?}", name, program_id);
}
}
self.message_processor
.add_program(program_id, process_instruction_with_context);
}
pub fn clean_accounts(&self, skip_last: bool) {
@ -3995,7 +3963,11 @@ impl Bank {
let should_populate = init_or_warp && self.feature_set.is_active(&feature)
|| !init_or_warp && new_feature_activations.contains(&feature);
if should_populate {
self.add_builtin(&builtin.name, builtin.id, builtin.entrypoint);
self.add_builtin(
&builtin.name,
builtin.id,
builtin.process_instruction_with_context,
);
}
}
}
@ -4125,7 +4097,6 @@ mod tests {
BOOTSTRAP_VALIDATOR_LAMPORTS,
},
native_loader::NativeLoaderError,
process_instruction::InvokeContext,
status_cache::MAX_CACHE_ENTRIES,
};
use solana_sdk::{
@ -4138,6 +4109,7 @@ mod tests {
message::{Message, MessageHeader},
nonce,
poh_config::PohConfig,
process_instruction::InvokeContext,
rent::Rent,
signature::{Keypair, Signer},
system_instruction::{self, SystemError},
@ -4428,6 +4400,7 @@ mod tests {
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
if let Ok(instruction) = bincode::deserialize(data) {
match instruction {
@ -4577,7 +4550,7 @@ mod tests {
) as u64,
);
bank.rent_collector.slots_per_year = 421_812.0;
bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction);
bank.add_builtin("mock_program", mock_program_id, mock_process_instruction);
bank
}
@ -7713,7 +7686,7 @@ mod tests {
}
#[test]
fn test_add_builtin_program() {
fn test_add_builtin() {
let (genesis_config, mint_keypair) = create_genesis_config(500);
let mut bank = Bank::new(&genesis_config);
@ -7724,6 +7697,7 @@ mod tests {
program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
if mock_vote_program_id() != *program_id {
return Err(InstructionError::IncorrectProgramId);
@ -7732,7 +7706,7 @@ mod tests {
}
assert!(bank.get_account(&mock_vote_program_id()).is_none());
bank.add_builtin_program(
bank.add_builtin(
"mock_vote_program",
mock_vote_program_id(),
mock_vote_processor,
@ -7781,6 +7755,7 @@ mod tests {
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
Err(InstructionError::Custom(42))
}
@ -7805,7 +7780,7 @@ mod tests {
);
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
bank.add_builtin_program(
bank.add_builtin(
"solana_vote_program",
solana_vote_program::id(),
mock_vote_processor,
@ -7831,6 +7806,7 @@ mod tests {
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
Err(InstructionError::Custom(42))
}
@ -7850,15 +7826,15 @@ mod tests {
assert!(!bank.stakes.read().unwrap().stake_delegations().is_empty());
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor);
bank.add_builtin_program("mock_program2", stake_id, mock_ix_processor);
bank.add_builtin("mock_program1", vote_id, mock_ix_processor);
bank.add_builtin("mock_program2", stake_id, mock_ix_processor);
assert!(bank.stakes.read().unwrap().vote_accounts().is_empty());
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
// Re-adding builtin programs should be no-op
bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor);
bank.add_builtin_program("mock_program2", stake_id, mock_ix_processor);
bank.add_builtin("mock_program1", vote_id, mock_ix_processor);
bank.add_builtin("mock_program2", stake_id, mock_ix_processor);
assert!(bank.stakes.read().unwrap().vote_accounts().is_empty());
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
@ -8499,6 +8475,7 @@ mod tests {
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
let lamports = data[0] as u64;
{
@ -8513,7 +8490,7 @@ mod tests {
}
let mock_program_id = Pubkey::new(&[2u8; 32]);
bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction);
bank.add_builtin("mock_program", mock_program_id, mock_process_instruction);
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
@ -8551,12 +8528,13 @@ mod tests {
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
Ok(())
}
let mock_program_id = Pubkey::new(&[2u8; 32]);
bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction);
bank.add_builtin("mock_program", mock_program_id, mock_process_instruction);
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
@ -8608,7 +8586,7 @@ mod tests {
tx.message.account_keys.push(solana_sdk::pubkey::new_rand());
bank.add_builtin_program(
bank.add_builtin(
"mock_vote",
solana_vote_program::id(),
mock_ok_vote_processor,
@ -8662,7 +8640,7 @@ mod tests {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin_program(
bank.add_builtin(
"mock_vote",
solana_vote_program::id(),
mock_ok_vote_processor,
@ -8695,7 +8673,7 @@ mod tests {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin_program(
bank.add_builtin(
"mock_vote",
solana_vote_program::id(),
mock_ok_vote_processor,
@ -8733,6 +8711,7 @@ mod tests {
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
Ok(())
}
@ -8750,7 +8729,7 @@ mod tests {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin_program(
bank.add_builtin(
"mock_vote",
solana_vote_program::id(),
mock_ok_vote_processor,
@ -8786,7 +8765,7 @@ mod tests {
.map(|i| {
let key = solana_sdk::pubkey::new_rand();
let name = format!("program{:?}", i);
bank.add_builtin_program(&name, key, mock_ok_vote_processor);
bank.add_builtin(&name, key, mock_ok_vote_processor);
(key, name.as_bytes().to_vec())
})
.collect();
@ -8981,6 +8960,7 @@ mod tests {
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
assert_eq!(42, keyed_accounts[0].lamports().unwrap());
let mut account = keyed_accounts[0].try_account_ref_mut()?;
@ -8993,7 +8973,7 @@ mod tests {
// Add a new program
let program1_pubkey = solana_sdk::pubkey::new_rand();
bank.add_builtin_program("program", program1_pubkey, nested_processor);
bank.add_builtin("program", program1_pubkey, nested_processor);
// Add a new program owned by the first
let program2_pubkey = solana_sdk::pubkey::new_rand();
@ -9155,13 +9135,14 @@ mod tests {
}
#[test]
fn test_add_builtin_program_no_overwrite() {
fn test_add_builtin_no_overwrite() {
let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
fn mock_ix_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
Ok(())
}
@ -9176,19 +9157,15 @@ mod tests {
));
assert_eq!(bank.get_account_modified_slot(&program_id), None);
Arc::get_mut(&mut bank).unwrap().add_builtin_program(
"mock_program",
program_id,
mock_ix_processor,
);
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", program_id, mock_ix_processor);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
let mut bank = Arc::new(new_from_parent(&bank));
Arc::get_mut(&mut bank).unwrap().add_builtin_program(
"mock_program",
program_id,
mock_ix_processor,
);
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", program_id, mock_ix_processor);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
}
@ -9215,19 +9192,15 @@ mod tests {
));
assert_eq!(bank.get_account_modified_slot(&loader_id), None);
Arc::get_mut(&mut bank).unwrap().add_builtin_loader(
"mock_program",
loader_id,
mock_ix_processor,
);
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", loader_id, mock_ix_processor);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
let mut bank = Arc::new(new_from_parent(&bank));
Arc::get_mut(&mut bank).unwrap().add_builtin_loader(
"mock_program",
loader_id,
mock_ix_processor,
);
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", loader_id, mock_ix_processor);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
}
@ -10061,25 +10034,4 @@ mod tests {
let debug = format!("{:#?}", bank);
assert!(!debug.is_empty());
}
#[test]
fn test_debug_entrypoint() {
fn mock_process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
) -> std::result::Result<(), InstructionError> {
Ok(())
}
fn mock_ix_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
Ok(())
}
assert!(!format!("{:?}", Entrypoint::Program(mock_process_instruction)).is_empty());
assert!(!format!("{:?}", Entrypoint::Loader(mock_ix_processor)).is_empty());
}
}

View File

@ -1,96 +0,0 @@
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

@ -1,5 +1,5 @@
use crate::{
bank::{Builtin, Builtins, Entrypoint},
bank::{Builtin, Builtins},
feature_set, system_instruction_processor,
};
use solana_sdk::{pubkey::Pubkey, system_program};
@ -10,22 +10,22 @@ fn genesis_builtins() -> Vec<Builtin> {
Builtin::new(
"system_program",
system_program::id(),
Entrypoint::Program(system_instruction_processor::process_instruction),
system_instruction_processor::process_instruction,
),
Builtin::new(
"vote_program",
solana_vote_program::id(),
Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction),
solana_vote_program::vote_instruction::process_instruction,
),
Builtin::new(
"stake_program",
solana_stake_program::id(),
Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction),
solana_stake_program::stake_instruction::process_instruction,
),
Builtin::new(
"config_program",
solana_config_program::id(),
Entrypoint::Program(solana_config_program::config_processor::process_instruction),
solana_config_program::config_processor::process_instruction,
),
]
}
@ -36,7 +36,7 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey)> {
Builtin::new(
"secp256k1_program",
solana_sdk::secp256k1_program::id(),
Entrypoint::Program(solana_secp256k1_program::process_instruction),
solana_secp256k1_program::process_instruction,
),
feature_set::secp256k1_program_enabled::id(),
)]

View File

@ -10,12 +10,9 @@ 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;
pub mod feature;
pub mod feature_set;
pub mod genesis_utils;
pub mod hardened_unpack;
pub mod instruction_recorder;
@ -23,7 +20,6 @@ pub mod loader_utils;
pub mod log_collector;
pub mod message_processor;
mod native_loader;
pub mod process_instruction;
pub mod rent_collector;
pub mod serde_snapshot;
pub mod snapshot_package;
@ -35,6 +31,10 @@ pub mod transaction_batch;
pub mod transaction_utils;
pub mod vote_sender_types;
// TODO: Refactor all feature users to reference the solana_sdk definitions directly and remove the
// next line
use solana_sdk::{feature, feature_set};
extern crate solana_config_program;
extern crate solana_stake_program;
extern crate solana_vote_program;

View File

@ -3,10 +3,6 @@ use crate::{
instruction_recorder::InstructionRecorder,
log_collector::LogCollector,
native_loader::NativeLoader,
process_instruction::{
ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext,
Executor, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext,
},
rent_collector::RentCollector,
};
use log::*;
@ -18,6 +14,10 @@ use solana_sdk::{
keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
message::Message,
native_loader,
process_instruction::{
BpfComputeBudget, ComputeMeter, Executor, InvokeContext, Logger,
ProcessInstructionWithContext,
},
pubkey::Pubkey,
rent::Rent,
system_program,
@ -201,31 +201,31 @@ impl ComputeMeter for ThisComputeMeter {
self.remaining
}
}
pub struct ThisInvokeContext {
pub struct ThisInvokeContext<'a> {
program_ids: Vec<Pubkey>,
rent: Rent,
pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>,
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
logger: Rc<RefCell<dyn Logger>>,
compute_budget: ComputeBudget,
bpf_compute_budget: BpfComputeBudget,
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>,
feature_set: Arc<FeatureSet>,
}
impl ThisInvokeContext {
impl<'a> ThisInvokeContext<'a> {
pub fn new(
program_id: &Pubkey,
rent: Rent,
pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>,
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
log_collector: Option<Rc<LogCollector>>,
compute_budget: ComputeBudget,
bpf_compute_budget: BpfComputeBudget,
executors: Rc<RefCell<Executors>>,
instruction_recorder: Option<InstructionRecorder>,
feature_set: Arc<FeatureSet>,
) -> Self {
let mut program_ids = Vec::with_capacity(compute_budget.max_invoke_depth);
let mut program_ids = Vec::with_capacity(bpf_compute_budget.max_invoke_depth);
program_ids.push(*program_id);
Self {
program_ids,
@ -233,9 +233,9 @@ impl ThisInvokeContext {
pre_accounts,
programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
compute_budget,
bpf_compute_budget,
compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
remaining: compute_budget.max_units,
remaining: bpf_compute_budget.max_units,
})),
executors,
instruction_recorder,
@ -243,9 +243,9 @@ impl ThisInvokeContext {
}
}
}
impl InvokeContext for ThisInvokeContext {
impl<'a> InvokeContext for ThisInvokeContext<'a> {
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
if self.program_ids.len() > self.compute_budget.max_invoke_depth {
if self.program_ids.len() > self.bpf_compute_budget.max_invoke_depth {
return Err(InstructionError::CallDepth);
}
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
@ -281,14 +281,14 @@ impl InvokeContext for ThisInvokeContext {
.last()
.ok_or(InstructionError::GenericError)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&self.programs
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
self.programs
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
self.logger.clone()
}
fn get_compute_budget(&self) -> &ComputeBudget {
&self.compute_budget
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
&self.bpf_compute_budget
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
self.compute_meter.clone()
@ -326,9 +326,7 @@ impl Logger for ThisLogger {
#[derive(Deserialize, Serialize)]
pub struct MessageProcessor {
#[serde(skip)]
programs: Vec<(Pubkey, ProcessInstruction)>,
#[serde(skip)]
loaders: Vec<(Pubkey, ProcessInstructionWithContext)>,
programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
#[serde(skip)]
native_loader: NativeLoader,
}
@ -338,9 +336,17 @@ impl std::fmt::Debug for MessageProcessor {
#[derive(Debug)]
struct MessageProcessor<'a> {
programs: Vec<String>,
loaders: Vec<String>,
native_loader: &'a NativeLoader,
}
// These are just type aliases for work around of Debug-ing above pointers
type ErasedProcessInstructionWithContext = fn(
&'static Pubkey,
&'static [KeyedAccount<'static>],
&'static [u8],
&'static mut dyn InvokeContext,
) -> Result<(), InstructionError>;
// rustc doesn't compile due to bug without this work around
// https://github.com/rust-lang/rust/issues/50280
// https://users.rust-lang.org/t/display-function-pointer/17073/2
@ -348,14 +354,6 @@ impl std::fmt::Debug for MessageProcessor {
programs: self
.programs
.iter()
.map(|(pubkey, instruction)| {
let erased_instruction: ErasedProcessInstruction = *instruction;
format!("{}: {:p}", pubkey, erased_instruction)
})
.collect::<Vec<_>>(),
loaders: self
.loaders
.iter()
.map(|(pubkey, instruction)| {
let erased_instruction: ErasedProcessInstructionWithContext = *instruction;
format!("{}: {:p}", pubkey, erased_instruction)
@ -372,7 +370,6 @@ impl Default for MessageProcessor {
fn default() -> Self {
Self {
programs: vec![],
loaders: vec![],
native_loader: NativeLoader::default(),
}
}
@ -381,7 +378,6 @@ impl Clone for MessageProcessor {
fn clone(&self) -> Self {
MessageProcessor {
programs: self.programs.clone(),
loaders: self.loaders.clone(),
native_loader: NativeLoader::default(),
}
}
@ -398,7 +394,11 @@ impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor {
impl MessageProcessor {
/// Add a static entrypoint to intercept instructions before the dynamic loader.
pub fn add_program(&mut self, program_id: Pubkey, process_instruction: ProcessInstruction) {
pub fn add_program(
&mut self,
program_id: Pubkey,
process_instruction: ProcessInstructionWithContext,
) {
match self.programs.iter_mut().find(|(key, _)| program_id == *key) {
Some((_, processor)) => *processor = process_instruction,
None => self.programs.push((program_id, process_instruction)),
@ -410,14 +410,7 @@ impl MessageProcessor {
program_id: Pubkey,
process_instruction: ProcessInstructionWithContext,
) {
match self.loaders.iter_mut().find(|(key, _)| program_id == *key) {
Some((_, processor)) => *processor = process_instruction,
None => self.loaders.push((program_id, process_instruction)),
}
}
fn get_compute_budget(feature_set: &FeatureSet) -> ComputeBudget {
ComputeBudget::new(feature_set)
self.add_program(program_id, process_instruction);
}
/// Create the KeyedAccounts that will be passed to the program
@ -458,17 +451,6 @@ impl MessageProcessor {
if let Some(root_account) = keyed_accounts.iter().next() {
if native_loader::check_id(&root_account.owner()?) {
let root_id = root_account.unsigned_key();
for (id, process_instruction) in &self.loaders {
if id == root_id {
// Call the program via a builtin loader
return process_instruction(
&root_id,
&keyed_accounts[1..],
instruction_data,
invoke_context,
);
}
}
for (id, process_instruction) in &self.programs {
if id == root_id {
// Call the builtin program
@ -476,6 +458,7 @@ impl MessageProcessor {
&root_id,
&keyed_accounts[1..],
instruction_data,
invoke_context,
);
}
}
@ -488,7 +471,7 @@ impl MessageProcessor {
);
} else {
let owner_id = &root_account.owner()?;
for (id, process_instruction) in &self.loaders {
for (id, process_instruction) in &self.programs {
if id == owner_id {
// Call the program via a builtin loader
return process_instruction(
@ -667,6 +650,7 @@ impl MessageProcessor {
instruction_recorder: Option<InstructionRecorder>,
instruction_index: usize,
feature_set: Arc<FeatureSet>,
bpf_compute_budget: BpfComputeBudget,
) -> Result<(), InstructionError> {
// Fixup the special instructions key if present
// before the account pre-values are taken care of
@ -688,9 +672,9 @@ impl MessageProcessor {
instruction.program_id(&message.account_keys),
rent_collector.rent,
pre_accounts,
self.programs.clone(), // get rid of clone
&self.programs,
log_collector,
Self::get_compute_budget(&feature_set),
bpf_compute_budget,
executors,
instruction_recorder,
feature_set,
@ -723,6 +707,7 @@ impl MessageProcessor {
executors: Rc<RefCell<Executors>>,
instruction_recorders: Option<&[InstructionRecorder]>,
feature_set: Arc<FeatureSet>,
bpf_compute_budget: BpfComputeBudget,
) -> Result<(), TransactionError> {
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
let instruction_recorder = instruction_recorders
@ -739,6 +724,7 @@ impl MessageProcessor {
instruction_recorder,
instruction_index,
feature_set.clone(),
bpf_compute_budget,
)
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
}
@ -781,9 +767,9 @@ mod tests {
&program_ids[0],
Rent::default(),
pre_accounts,
vec![],
&[],
None,
ComputeBudget::default(),
BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())),
None,
Arc::new(FeatureSet::all_enabled()),
@ -1266,6 +1252,7 @@ mod tests {
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
if let Ok(instruction) = bincode::deserialize(data) {
match instruction {
@ -1327,6 +1314,7 @@ mod tests {
executors.clone(),
None,
Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
);
assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports, 100);
@ -1350,6 +1338,7 @@ mod tests {
executors.clone(),
None,
Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
);
assert_eq!(
result,
@ -1377,6 +1366,7 @@ mod tests {
executors,
None,
Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
);
assert_eq!(
result,
@ -1400,6 +1390,7 @@ mod tests {
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
if let Ok(instruction) = bincode::deserialize(data) {
match instruction {
@ -1487,6 +1478,7 @@ mod tests {
executors.clone(),
None,
Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
);
assert_eq!(
result,
@ -1514,6 +1506,7 @@ mod tests {
executors.clone(),
None,
Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
);
assert_eq!(result, Ok(()));
@ -1538,6 +1531,7 @@ mod tests {
executors,
None,
Arc::new(FeatureSet::all_enabled()),
BpfComputeBudget::new(&FeatureSet::all_enabled()),
);
assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports, 80);
@ -1559,6 +1553,7 @@ mod tests {
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
assert_eq!(*program_id, keyed_accounts[0].owner()?);
assert_ne!(
@ -1609,9 +1604,9 @@ mod tests {
&caller_program_id,
Rent::default(),
vec![owned_preaccount, not_owned_preaccount],
vec![],
&[],
None,
ComputeBudget::default(),
BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())),
None,
Arc::new(FeatureSet::all_enabled()),
@ -1675,6 +1670,7 @@ mod tests {
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
Ok(())
}

View File

@ -1,5 +1,4 @@
//! Native loader
use crate::process_instruction::{InvokeContext, LoaderEntrypoint};
#[cfg(unix)]
use libloading::os::unix::*;
#[cfg(windows)]
@ -11,6 +10,7 @@ use solana_sdk::{
entrypoint_native::ProgramEntrypoint,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
process_instruction::{InvokeContext, LoaderEntrypoint},
pubkey::Pubkey,
};
use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock};

View File

@ -6,6 +6,7 @@ use solana_sdk::{
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
nonce,
nonce_keyed_account::NonceKeyedAccount,
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH},
@ -213,6 +214,7 @@ pub fn process_instruction(
_owner: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let instruction = limited_deserialize(instruction_data)?;
@ -363,7 +365,9 @@ mod tests {
hash::{hash, Hash},
instruction::{AccountMeta, Instruction, InstructionError},
message::Message,
nonce, nonce_account, recent_blockhashes_account,
nonce, nonce_account,
process_instruction::MockInvokeContext,
recent_blockhashes_account,
signature::{Keypair, Signer},
system_instruction, system_program, sysvar,
sysvar::recent_blockhashes::IterItem,
@ -381,6 +385,19 @@ mod tests {
}
}
fn process_instruction(
owner: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
) -> Result<(), InstructionError> {
super::process_instruction(
owner,
keyed_accounts,
instruction_data,
&mut MockInvokeContext::default(),
)
}
fn create_default_account() -> RefCell<Account> {
RefCell::new(Account::default())
}
@ -1194,7 +1211,7 @@ mod tests {
.zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect();
super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data)
process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data)
}
}
@ -1212,7 +1229,7 @@ mod tests {
#[test]
fn test_process_nonce_ix_no_keyed_accs_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[],
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap()
@ -1224,7 +1241,7 @@ mod tests {
#[test]
fn test_process_nonce_ix_only_nonce_acc_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
@ -1240,7 +1257,7 @@ mod tests {
#[test]
fn test_process_nonce_ix_bad_recent_blockhash_state_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
@ -1259,7 +1276,7 @@ mod tests {
#[test]
fn test_process_nonce_ix_ok() {
let nonce_acc = nonce_account::create_account(1_000_000);
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
@ -1288,7 +1305,7 @@ mod tests {
),
);
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),
@ -1320,7 +1337,7 @@ mod tests {
#[test]
fn test_process_withdraw_ix_no_keyed_accs_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[],
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
@ -1332,7 +1349,7 @@ mod tests {
#[test]
fn test_process_withdraw_ix_only_nonce_acc_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
@ -1348,7 +1365,7 @@ mod tests {
#[test]
fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
@ -1368,7 +1385,7 @@ mod tests {
#[test]
fn test_process_withdraw_ix_bad_rent_state_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(
@ -1393,7 +1410,7 @@ mod tests {
#[test]
fn test_process_withdraw_ix_ok() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(
@ -1418,7 +1435,7 @@ mod tests {
#[test]
fn test_process_initialize_ix_no_keyed_accs_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[],
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
@ -1430,7 +1447,7 @@ mod tests {
#[test]
fn test_process_initialize_ix_only_nonce_acc_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
@ -1446,7 +1463,7 @@ mod tests {
#[test]
fn test_process_initialize_bad_recent_blockhash_state_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(
@ -1469,7 +1486,7 @@ mod tests {
#[test]
fn test_process_initialize_ix_bad_rent_state_fail() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(
@ -1493,7 +1510,7 @@ mod tests {
#[test]
fn test_process_initialize_ix_ok() {
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(
@ -1517,7 +1534,7 @@ mod tests {
#[test]
fn test_process_authorize_ix_ok() {
let nonce_acc = nonce_account::create_account(1_000_000);
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
@ -1532,7 +1549,7 @@ mod tests {
)
.unwrap();
assert_eq!(
super::process_instruction(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),],
&serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(),

View File

@ -46,6 +46,7 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser
hex = "0.4.2"
hmac = "0.7.0"
itertools = "0.9.0"
lazy_static = "1.4.0"
log = "0.4.8"
memmap = { version = "0.7.0", optional = true }
num-derive = "0.3"

View File

@ -133,6 +133,12 @@ void sol_log_(const char *, uint64_t);
void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
#define sol_log_64 sol_log_64_
/**
* Prints the current compute unit consumption to stdout
*/
void sol_log_compute_units_();
#define sol_log_compute_units() sol_log_compute_units_()
/**
* Size of Public key in bytes
*/

View File

@ -96,3 +96,19 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
info!("Instruction data");
sol_log_slice(data);
}
/// Logs the current compute unit consumption
#[inline]
pub fn sol_log_compute_units() {
#[cfg(target_arch = "bpf")]
unsafe {
sol_log_compute_units_();
}
#[cfg(not(target_arch = "bpf"))]
crate::program_stubs::sol_log_compute_units();
}
#[cfg(target_arch = "bpf")]
extern "C" {
fn sol_log_compute_units_();
}

View File

@ -19,6 +19,9 @@ pub trait SyscallStubs: Sync + Send {
fn sol_log(&self, message: &str) {
println!("{}", message);
}
fn sol_log_compute_units(&self) {
sol_log("SyscallStubs: sol_log_compute_units() not available");
}
fn sol_invoke_signed(
&self,
_instruction: &Instruction,
@ -41,6 +44,10 @@ pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64)
sol_log(&format!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5));
}
pub(crate) fn sol_log_compute_units() {
SYSCALL_STUBS.read().unwrap().sol_log_compute_units();
}
pub(crate) fn sol_invoke_signed(
instruction: &Instruction,
account_infos: &[AccountInfo],

View File

@ -86,15 +86,19 @@ macro_rules! declare_name {
/// # // wrapper is used so that the macro invocation occurs in the item position
/// # // rather than in the statement position which isn't allowed.
/// # mod item_wrapper {
/// use solana_sdk::keyed_account::KeyedAccount;
/// use solana_sdk::instruction::InstructionError;
/// use solana_sdk::pubkey::Pubkey;
/// use solana_sdk::declare_program;
/// use solana_sdk::{
/// declare_program,
/// instruction::InstructionError,
/// keyed_account::KeyedAccount,
/// process_instruction::InvokeContext,
/// pubkey::Pubkey,
/// };
///
/// fn my_process_instruction(
/// program_id: &Pubkey,
/// keyed_accounts: &[KeyedAccount],
/// instruction_data: &[u8],
/// invoke_context: &mut dyn InvokeContext,
/// ) -> Result<(), InstructionError> {
/// // Process an instruction
/// Ok(())
@ -117,15 +121,19 @@ macro_rules! declare_name {
/// # // wrapper is used so that the macro invocation occurs in the item position
/// # // rather than in the statement position which isn't allowed.
/// # mod item_wrapper {
/// use solana_sdk::keyed_account::KeyedAccount;
/// use solana_sdk::instruction::InstructionError;
/// use solana_sdk::pubkey::Pubkey;
/// use solana_sdk::declare_program;
/// use solana_sdk::{
/// declare_program,
/// instruction::InstructionError,
/// keyed_account::KeyedAccount,
/// process_instruction::InvokeContext,
/// pubkey::Pubkey,
/// };
///
/// fn my_process_instruction(
/// program_id: &Pubkey,
/// keyed_accounts: &[KeyedAccount],
/// instruction_data: &[u8],
/// invoke_context: &mut dyn InvokeContext,
/// ) -> Result<(), InstructionError> {
/// // Process an instruction
/// Ok(())
@ -152,8 +160,9 @@ macro_rules! declare_program(
program_id: &$crate::pubkey::Pubkey,
keyed_accounts: &[$crate::keyed_account::KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn $crate::process_instruction::InvokeContext,
) -> Result<(), $crate::instruction::InstructionError> {
$entrypoint(program_id, keyed_accounts, instruction_data)
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
}
)
);

View File

@ -34,7 +34,7 @@ pub mod bpf_loader2_program {
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
}
pub mod compute_budget_balancing {
pub mod bpf_compute_budget_balancing {
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
}
@ -66,6 +66,10 @@ pub mod cumulative_rent_related_fixes {
solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5");
}
pub mod sol_log_compute_units_syscall {
solana_sdk::declare_id!("BHuZqHAj7JdZc68wVgZZcy51jZykvgrx4zptR44RyChe");
}
pub mod pubkey_log_syscall_enabled {
solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN");
}
@ -84,7 +88,7 @@ lazy_static! {
(inflation_kill_switch::id(), "inflation kill switch"),
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
(bpf_loader2_program::id(), "bpf_loader2 program"),
(compute_budget_balancing::id(), "compute budget balancing"),
(bpf_compute_budget_balancing::id(), "compute budget balancing"),
(sha256_syscall_enabled::id(), "sha256 syscall"),
(no_overflow_rent_distribution::id(), "no overflow rent distribution"),
(ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"),
@ -92,6 +96,7 @@ lazy_static! {
(max_program_call_depth_64::id(), "max program call depth 64"),
(timestamp_correction::id(), "correct bank timestamps"),
(cumulative_rent_related_fixes::id(), "rent fixes (#10206, #10468, #11342)"),
(sol_log_compute_units_syscall::id(), "sol_log_compute_units syscall (#13243)"),
(pubkey_log_syscall_enabled::id(), "pubkey log syscall"),
(pull_request_ping_pong_check::id(), "ping-pong packet check #12794"),
/*************** ADD NEW FEATURES HERE ***************/

View File

@ -16,6 +16,8 @@ pub mod entrypoint;
pub mod entrypoint_deprecated;
pub mod entrypoint_native;
pub mod epoch_info;
pub mod feature;
pub mod feature_set;
pub mod genesis_config;
pub mod hard_forks;
pub mod hash;
@ -27,6 +29,7 @@ pub mod nonce_account;
pub mod nonce_keyed_account;
pub mod packet;
pub mod poh_config;
pub mod process_instruction;
pub mod program_utils;
pub mod pubkey;
pub mod recent_blockhashes_account;

View File

@ -1,9 +1,9 @@
use crate::feature_set::{
compute_budget_balancing, max_invoke_depth_4, max_program_call_depth_64,
pubkey_log_syscall_enabled, FeatureSet,
};
use solana_sdk::{
account::Account,
feature_set::{
bpf_compute_budget_balancing, max_invoke_depth_4, max_program_call_depth_64,
pubkey_log_syscall_enabled, FeatureSet,
},
instruction::{CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount,
message::Message,
@ -24,24 +24,9 @@ pub type LoaderEntrypoint = unsafe extern "C" fn(
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>;
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
pub type ProcessInstructionWithContext =
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
// These are just type aliases for work around of Debug-ing above function pointers
pub type ErasedProcessInstructionWithContext = fn(
&'static Pubkey,
&'static [KeyedAccount<'static>],
&'static [u8],
&'static mut dyn InvokeContext,
) -> Result<(), InstructionError>;
pub type ErasedProcessInstruction = fn(
&'static Pubkey,
&'static [KeyedAccount<'static>],
&'static [u8],
) -> Result<(), InstructionError>;
/// Invocation context passed to loaders
pub trait InvokeContext {
/// Push a program ID on to the invocation stack
@ -58,11 +43,11 @@ pub trait InvokeContext {
/// Get the program ID of the currently executing program
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
/// Get a list of built-in programs
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)];
/// Get this invocation's logger
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
/// Get this invocation's compute budget
fn get_compute_budget(&self) -> &ComputeBudget;
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget;
/// Get this invocation's compute meter
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
/// Loaders may need to do work in order to execute a program. Cache
@ -76,8 +61,8 @@ pub trait InvokeContext {
fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
}
#[derive(Clone, Copy, Debug)]
pub struct ComputeBudget {
#[derive(Clone, Copy, Debug, AbiExample)]
pub struct BpfComputeBudget {
/// Number of compute units that an instruction is allowed. Compute units
/// are consumed by program execution, resources they use, etc...
pub max_units: u64,
@ -103,16 +88,16 @@ pub struct ComputeBudget {
/// Number of compute units consumed by logging a `Pubkey`
pub log_pubkey_units: u64,
}
impl Default for ComputeBudget {
impl Default for BpfComputeBudget {
fn default() -> Self {
Self::new(&FeatureSet::all_enabled())
}
}
impl ComputeBudget {
impl BpfComputeBudget {
pub fn new(feature_set: &FeatureSet) -> Self {
let mut compute_budget =
let mut bpf_compute_budget =
// Original
ComputeBudget {
BpfComputeBudget {
max_units: 100_000,
log_units: 0,
log_64_units: 0,
@ -126,36 +111,36 @@ impl ComputeBudget {
log_pubkey_units: 0,
};
if feature_set.is_active(&compute_budget_balancing::id()) {
compute_budget = ComputeBudget {
if feature_set.is_active(&bpf_compute_budget_balancing::id()) {
bpf_compute_budget = BpfComputeBudget {
max_units: 200_000,
log_units: 100,
log_64_units: 100,
create_program_address_units: 1500,
invoke_units: 1000,
..compute_budget
..bpf_compute_budget
};
}
if feature_set.is_active(&max_invoke_depth_4::id()) {
compute_budget = ComputeBudget {
bpf_compute_budget = BpfComputeBudget {
max_invoke_depth: 4,
..compute_budget
..bpf_compute_budget
};
}
if feature_set.is_active(&max_program_call_depth_64::id()) {
compute_budget = ComputeBudget {
bpf_compute_budget = BpfComputeBudget {
max_call_depth: 64,
..compute_budget
..bpf_compute_budget
};
}
if feature_set.is_active(&pubkey_log_syscall_enabled::id()) {
compute_budget = ComputeBudget {
bpf_compute_budget = BpfComputeBudget {
log_pubkey_units: 100,
..compute_budget
..bpf_compute_budget
};
}
compute_budget
bpf_compute_budget
}
}
@ -185,3 +170,91 @@ pub trait Executor: Debug + Send + Sync {
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError>;
}
#[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 bpf_compute_budget: BpfComputeBudget,
pub compute_meter: MockComputeMeter,
}
impl Default for MockInvokeContext {
fn default() -> Self {
MockInvokeContext {
key: Pubkey::default(),
logger: MockLogger::default(),
bpf_compute_budget: BpfComputeBudget::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, ProcessInstructionWithContext)] {
&[]
}
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
Rc::new(RefCell::new(self.logger.clone()))
}
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
&self.bpf_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

@ -16,7 +16,6 @@ solana-frozen-abi = { path = "../frozen-abi", version = "1.4.4" }
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "1.4.4" }
solana-logger = { path = "../logger", version = "1.4.4" }
solana-sdk = { path = "../sdk", version = "1.4.4" }
solana-runtime = { path = "../runtime", version = "1.4.4" }
[lib]
name = "solana_version"

View File

@ -51,7 +51,7 @@ fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
impl Default for Version {
fn default() -> Self {
let feature_set = u32::from_le_bytes(
solana_runtime::feature_set::ID.as_ref()[..4]
solana_sdk::feature_set::ID.as_ref()[..4]
.try_into()
.unwrap(),
);