* Native/builtin programs now receive an InvokeContext (cherry picked from commitdf8dab9d2b
) * Remove MessageProcessor::loaders (cherry picked from commit2664a1f7ef
) * Remove Entrypoint type (cherry picked from commit225bed11c7
) * Remove programs clone() (cherry picked from commit33884d847a
) * Add sol_log_compute_units syscall (cherry picked from commit66e51a7363
) * Add Bank::set_bpf_compute_budget() (cherry picked from commit7d686b72a0
) * Rebase Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -3699,7 +3699,6 @@ dependencies = [
|
|||||||
"solana-logger 1.4.4",
|
"solana-logger 1.4.4",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-remote-wallet",
|
"solana-remote-wallet",
|
||||||
"solana-runtime",
|
|
||||||
"solana-sdk 1.4.4",
|
"solana-sdk 1.4.4",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-transaction-status",
|
"solana-transaction-status",
|
||||||
@ -4586,6 +4585,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"itertools 0.9.0",
|
"itertools 0.9.0",
|
||||||
|
"lazy_static",
|
||||||
"libsecp256k1",
|
"libsecp256k1",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"memmap",
|
"memmap",
|
||||||
@ -4909,7 +4909,6 @@ dependencies = [
|
|||||||
"solana-frozen-abi",
|
"solana-frozen-abi",
|
||||||
"solana-frozen-abi-macro",
|
"solana-frozen-abi-macro",
|
||||||
"solana-logger 1.4.4",
|
"solana-logger 1.4.4",
|
||||||
"solana-runtime",
|
|
||||||
"solana-sdk 1.4.4",
|
"solana-sdk 1.4.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ fn test_exchange_bank_client() {
|
|||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
|
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
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 clients = vec![BankClient::new(bank)];
|
||||||
|
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
|
@ -39,7 +39,6 @@ solana-logger = { path = "../logger", version = "1.4.4" }
|
|||||||
solana-net-utils = { path = "../net-utils", version = "1.4.4" }
|
solana-net-utils = { path = "../net-utils", version = "1.4.4" }
|
||||||
solana_rbpf = "=0.1.32"
|
solana_rbpf = "=0.1.32"
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.4.4" }
|
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-sdk = { path = "../sdk", version = "1.4.4" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.4.4" }
|
solana-stake-program = { path = "../programs/stake", version = "1.4.4" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.4.4" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.4.4" }
|
||||||
|
@ -9,12 +9,14 @@ use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*};
|
|||||||
use solana_cli_output::{QuietDisplay, VerboseDisplay};
|
use solana_cli_output::{QuietDisplay, VerboseDisplay};
|
||||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_runtime::{
|
use solana_sdk::{
|
||||||
|
clock::Slot,
|
||||||
feature::{self, Feature},
|
feature::{self, Feature},
|
||||||
feature_set::FEATURE_NAMES,
|
feature_set::FEATURE_NAMES,
|
||||||
};
|
message::Message,
|
||||||
use solana_sdk::{
|
pubkey::Pubkey,
|
||||||
clock::Slot, message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction,
|
system_instruction,
|
||||||
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, fmt, sync::Arc};
|
use std::{collections::HashMap, fmt, sync::Arc};
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
|
||||||
use solana_ledger::blockstore::Blockstore;
|
use solana_ledger::blockstore::Blockstore;
|
||||||
use solana_measure::measure::Measure;
|
use solana_measure::measure::Measure;
|
||||||
use solana_runtime::{bank::Bank, feature_set};
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::timing::slot_duration_from_slots_per_year;
|
use solana_sdk::{feature_set, timing::slot_duration_from_slots_per_year};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -52,10 +52,10 @@ use solana_perf::packet::{
|
|||||||
};
|
};
|
||||||
use solana_rayon_threadlimit::get_thread_count;
|
use solana_rayon_threadlimit::get_thread_count;
|
||||||
use solana_runtime::bank_forks::BankForks;
|
use solana_runtime::bank_forks::BankForks;
|
||||||
use solana_runtime::feature_set::{self, FeatureSet};
|
|
||||||
use solana_sdk::hash::Hash;
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH},
|
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH},
|
||||||
|
feature_set::{self, FeatureSet},
|
||||||
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signable, Signature, Signer},
|
signature::{Keypair, Signable, Signature, Signer},
|
||||||
timing::timestamp,
|
timing::timestamp,
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
use solana_runtime::{
|
use solana_runtime::bank::{Builtin, Builtins};
|
||||||
bank::{Builtin, Builtins, Entrypoint},
|
use solana_sdk::{feature_set, genesis_config::ClusterType, pubkey::Pubkey};
|
||||||
feature_set,
|
|
||||||
};
|
|
||||||
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
|
|
||||||
|
|
||||||
/// Builtin programs that are always available
|
/// Builtin programs that are always available
|
||||||
fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
|
fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
|
||||||
@ -19,7 +16,7 @@ fn genesis_builtins(cluster_type: ClusterType) -> Vec<Builtin> {
|
|||||||
|
|
||||||
builtins
|
builtins
|
||||||
.into_iter()
|
.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()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +29,7 @@ fn feature_builtins() -> Vec<(Builtin, Pubkey)> {
|
|||||||
|
|
||||||
builtins
|
builtins
|
||||||
.into_iter()
|
.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()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
programs/bpf/Cargo.lock
generated
1
programs/bpf/Cargo.lock
generated
@ -2211,6 +2211,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"libsecp256k1",
|
"libsecp256k1",
|
||||||
"log",
|
"log",
|
||||||
"memmap",
|
"memmap",
|
||||||
|
@ -11,10 +11,8 @@ use solana_rbpf::vm::{EbpfVm, InstructionMeter};
|
|||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::Bank,
|
bank::Bank,
|
||||||
bank_client::BankClient,
|
bank_client::BankClient,
|
||||||
bpf_test_utils::MockInvokeContext,
|
|
||||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
loader_utils::load_program,
|
loader_utils::load_program,
|
||||||
process_instruction::{ComputeMeter, InvokeContext},
|
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
@ -23,6 +21,7 @@ use solana_sdk::{
|
|||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
instruction::{AccountMeta, Instruction},
|
instruction::{AccountMeta, Instruction},
|
||||||
message::Message,
|
message::Message,
|
||||||
|
process_instruction::{ComputeMeter, InvokeContext, MockInvokeContext},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
};
|
};
|
||||||
@ -161,7 +160,7 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
|
|||||||
} = create_genesis_config(50);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 = Arc::new(bank);
|
||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
|
@ -18,5 +18,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
// program, no account keys or input data are expected but real
|
// program, no account keys or input data are expected but real
|
||||||
// programs will have specific requirements so they can do their work.
|
// programs will have specific requirements so they can do their work.
|
||||||
sol_log_params(¶ms);
|
sol_log_params(¶ms);
|
||||||
|
|
||||||
|
sol_log_compute_units();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ fn process_instruction(
|
|||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sol_log_compute_units();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,8 @@ use solana_rbpf::vm::EbpfVm;
|
|||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::Bank,
|
bank::Bank,
|
||||||
bank_client::BankClient,
|
bank_client::BankClient,
|
||||||
bpf_test_utils::MockInvokeContext,
|
|
||||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
loader_utils::load_program,
|
loader_utils::load_program,
|
||||||
process_instruction::ComputeBudget,
|
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
@ -25,6 +23,7 @@ use solana_sdk::{
|
|||||||
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
message::Message,
|
message::Message,
|
||||||
|
process_instruction::{BpfComputeBudget, MockInvokeContext},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
sysvar::{clock, fees, rent, slot_hashes, stake_history},
|
sysvar::{clock, fees, rent, slot_hashes, stake_history},
|
||||||
@ -179,7 +178,7 @@ fn test_program_bpf_sanity() {
|
|||||||
} = create_genesis_config(50);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 = Arc::new(bank);
|
||||||
|
|
||||||
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test
|
// 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);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!();
|
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 bank_client = BankClient::new(bank);
|
||||||
|
|
||||||
let program_id = load_bpf_program(
|
let program_id = load_bpf_program(
|
||||||
@ -273,7 +272,7 @@ fn test_program_bpf_duplicate_accounts() {
|
|||||||
} = create_genesis_config(50);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 = Arc::new(bank);
|
||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
|
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);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 bank_client = BankClient::new(bank);
|
||||||
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
|
let program_id = load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program);
|
||||||
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
|
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
|
||||||
@ -475,7 +474,7 @@ fn test_program_bpf_invoke() {
|
|||||||
} = create_genesis_config(50);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 = Arc::new(bank);
|
||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
@ -706,7 +705,7 @@ fn test_program_bpf_call_depth() {
|
|||||||
} = create_genesis_config(50);
|
} = create_genesis_config(50);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 bank_client = BankClient::new(bank);
|
||||||
let program_id = load_bpf_program(
|
let program_id = load_bpf_program(
|
||||||
&bank_client,
|
&bank_client,
|
||||||
@ -717,14 +716,14 @@ fn test_program_bpf_call_depth() {
|
|||||||
|
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
program_id,
|
program_id,
|
||||||
&(ComputeBudget::default().max_call_depth - 1),
|
&(BpfComputeBudget::default().max_call_depth - 1),
|
||||||
vec![],
|
vec![],
|
||||||
);
|
);
|
||||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
let instruction =
|
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);
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
@ -788,7 +787,7 @@ fn test_program_bpf_instruction_introspection() {
|
|||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
|
|
||||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
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 = Arc::new(bank);
|
||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
|
@ -16,17 +16,15 @@ use solana_rbpf::{
|
|||||||
memory_region::MemoryRegion,
|
memory_region::MemoryRegion,
|
||||||
vm::{Config, EbpfVm, Executable, InstructionMeter},
|
vm::{Config, EbpfVm, Executable, InstructionMeter},
|
||||||
};
|
};
|
||||||
use solana_runtime::{
|
|
||||||
feature_set::compute_budget_balancing,
|
|
||||||
process_instruction::{ComputeMeter, Executor, InvokeContext},
|
|
||||||
};
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader, bpf_loader_deprecated,
|
||||||
decode_error::DecodeError,
|
decode_error::DecodeError,
|
||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
|
feature_set::bpf_compute_budget_balancing,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::{is_executable, next_keyed_account, KeyedAccount},
|
keyed_account::{is_executable, next_keyed_account, KeyedAccount},
|
||||||
loader_instruction::LoaderInstruction,
|
loader_instruction::LoaderInstruction,
|
||||||
|
process_instruction::{ComputeMeter, Executor, InvokeContext},
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
@ -101,7 +99,7 @@ pub fn create_and_cache_executor(
|
|||||||
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
||||||
bpf_verifier::check(
|
bpf_verifier::check(
|
||||||
elf_bytes,
|
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)))?;
|
.map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
|
||||||
let executor = Arc::new(BPFExecutor { executable });
|
let executor = Arc::new(BPFExecutor { executable });
|
||||||
@ -116,12 +114,12 @@ pub fn create_vm<'a>(
|
|||||||
parameter_accounts: &'a [KeyedAccount<'a>],
|
parameter_accounts: &'a [KeyedAccount<'a>],
|
||||||
invoke_context: &'a mut dyn InvokeContext,
|
invoke_context: &'a mut dyn InvokeContext,
|
||||||
) -> Result<(EbpfVm<'a, BPFError>, MemoryRegion), EbpfError<BPFError>> {
|
) -> 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(
|
let mut vm = EbpfVm::new(
|
||||||
executable,
|
executable,
|
||||||
Config {
|
Config {
|
||||||
max_call_depth: compute_budget.max_call_depth,
|
max_call_depth: bpf_compute_budget.max_call_depth,
|
||||||
stack_frame_size: compute_budget.stack_frame_size,
|
stack_frame_size: bpf_compute_budget.stack_frame_size,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let heap_region =
|
let heap_region =
|
||||||
@ -312,13 +310,14 @@ impl Executor for BPFExecutor {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use solana_runtime::{
|
use solana_runtime::message_processor::{Executors, ThisInvokeContext};
|
||||||
bpf_test_utils::MockInvokeContext,
|
use solana_sdk::{
|
||||||
|
account::Account,
|
||||||
feature_set::FeatureSet,
|
feature_set::FeatureSet,
|
||||||
message_processor::{Executors, ThisInvokeContext},
|
instruction::InstructionError,
|
||||||
process_instruction::ComputeBudget,
|
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};
|
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
|
||||||
|
|
||||||
struct TestInstructionMeter {
|
struct TestInstructionMeter {
|
||||||
@ -533,9 +532,9 @@ mod tests {
|
|||||||
&program_id,
|
&program_id,
|
||||||
Rent::default(),
|
Rent::default(),
|
||||||
vec![],
|
vec![],
|
||||||
vec![],
|
&[],
|
||||||
None,
|
None,
|
||||||
ComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: 1,
|
max_units: 1,
|
||||||
log_units: 100,
|
log_units: 100,
|
||||||
log_64_units: 100,
|
log_64_units: 100,
|
||||||
|
@ -7,22 +7,21 @@ use solana_rbpf::{
|
|||||||
memory_region::{translate_addr, MemoryRegion},
|
memory_region::{translate_addr, MemoryRegion},
|
||||||
vm::{EbpfVm, SyscallObject},
|
vm::{EbpfVm, SyscallObject},
|
||||||
};
|
};
|
||||||
use solana_runtime::{
|
use solana_runtime::message_processor::MessageProcessor;
|
||||||
feature_set::{
|
|
||||||
pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled,
|
|
||||||
},
|
|
||||||
message_processor::MessageProcessor,
|
|
||||||
process_instruction::{ComputeMeter, InvokeContext, Logger},
|
|
||||||
};
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
account_info::AccountInfo,
|
account_info::AccountInfo,
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader_deprecated,
|
||||||
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
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},
|
hash::{Hasher, HASH_BYTES},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
message::Message,
|
message::Message,
|
||||||
|
process_instruction::{ComputeMeter, InvokeContext, Logger},
|
||||||
program_error::ProgramError,
|
program_error::ProgramError,
|
||||||
pubkey::{Pubkey, PubkeyError},
|
pubkey::{Pubkey, PubkeyError},
|
||||||
};
|
};
|
||||||
@ -98,7 +97,7 @@ pub fn register_syscalls<'a>(
|
|||||||
callers_keyed_accounts: &'a [KeyedAccount<'a>],
|
callers_keyed_accounts: &'a [KeyedAccount<'a>],
|
||||||
invoke_context: &'a mut dyn InvokeContext,
|
invoke_context: &'a mut dyn InvokeContext,
|
||||||
) -> Result<MemoryRegion, EbpfError<BPFError>> {
|
) -> 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
|
// Syscall functions common across languages
|
||||||
|
|
||||||
@ -107,7 +106,7 @@ pub fn register_syscalls<'a>(
|
|||||||
vm.register_syscall_with_context_ex(
|
vm.register_syscall_with_context_ex(
|
||||||
"sol_log_",
|
"sol_log_",
|
||||||
Box::new(SyscallLog {
|
Box::new(SyscallLog {
|
||||||
cost: compute_budget.log_units,
|
cost: bpf_compute_budget.log_units,
|
||||||
compute_meter: invoke_context.get_compute_meter(),
|
compute_meter: invoke_context.get_compute_meter(),
|
||||||
logger: invoke_context.get_logger(),
|
logger: invoke_context.get_logger(),
|
||||||
loader_id,
|
loader_id,
|
||||||
@ -116,17 +115,27 @@ pub fn register_syscalls<'a>(
|
|||||||
vm.register_syscall_with_context_ex(
|
vm.register_syscall_with_context_ex(
|
||||||
"sol_log_64_",
|
"sol_log_64_",
|
||||||
Box::new(SyscallLogU64 {
|
Box::new(SyscallLogU64 {
|
||||||
cost: compute_budget.log_64_units,
|
cost: bpf_compute_budget.log_64_units,
|
||||||
compute_meter: invoke_context.get_compute_meter(),
|
compute_meter: invoke_context.get_compute_meter(),
|
||||||
logger: invoke_context.get_logger(),
|
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()) {
|
if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) {
|
||||||
vm.register_syscall_with_context_ex(
|
vm.register_syscall_with_context_ex(
|
||||||
"sol_log_pubkey",
|
"sol_log_pubkey",
|
||||||
Box::new(SyscallLogPubkey {
|
Box::new(SyscallLogPubkey {
|
||||||
cost: compute_budget.log_pubkey_units,
|
cost: bpf_compute_budget.log_pubkey_units,
|
||||||
compute_meter: invoke_context.get_compute_meter(),
|
compute_meter: invoke_context.get_compute_meter(),
|
||||||
logger: invoke_context.get_logger(),
|
logger: invoke_context.get_logger(),
|
||||||
loader_id,
|
loader_id,
|
||||||
@ -138,8 +147,8 @@ pub fn register_syscalls<'a>(
|
|||||||
vm.register_syscall_with_context_ex(
|
vm.register_syscall_with_context_ex(
|
||||||
"sol_sha256",
|
"sol_sha256",
|
||||||
Box::new(SyscallSha256 {
|
Box::new(SyscallSha256 {
|
||||||
sha256_base_cost: compute_budget.sha256_base_cost,
|
sha256_base_cost: bpf_compute_budget.sha256_base_cost,
|
||||||
sha256_byte_cost: compute_budget.sha256_byte_cost,
|
sha256_byte_cost: bpf_compute_budget.sha256_byte_cost,
|
||||||
compute_meter: invoke_context.get_compute_meter(),
|
compute_meter: invoke_context.get_compute_meter(),
|
||||||
loader_id,
|
loader_id,
|
||||||
}),
|
}),
|
||||||
@ -160,7 +169,7 @@ pub fn register_syscalls<'a>(
|
|||||||
vm.register_syscall_with_context_ex(
|
vm.register_syscall_with_context_ex(
|
||||||
"sol_create_program_address",
|
"sol_create_program_address",
|
||||||
Box::new(SyscallCreateProgramAddress {
|
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(),
|
compute_meter: invoke_context.get_compute_meter(),
|
||||||
loader_id,
|
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
|
/// Log 5 64-bit values
|
||||||
pub struct SyscallLogPubkey<'a> {
|
pub struct SyscallLogPubkey<'a> {
|
||||||
cost: u64,
|
cost: u64,
|
||||||
@ -1147,7 +1188,7 @@ fn call<'a>(
|
|||||||
let mut invoke_context = syscall.get_context_mut()?;
|
let mut invoke_context = syscall.get_context_mut()?;
|
||||||
invoke_context
|
invoke_context
|
||||||
.get_compute_meter()
|
.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
|
// Translate data passed from the VM
|
||||||
|
|
||||||
@ -1185,8 +1226,6 @@ fn call<'a>(
|
|||||||
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
|
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
|
||||||
message_processor.add_program(*program_id, *process_instruction);
|
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)]
|
#[allow(clippy::deref_addrof)]
|
||||||
match message_processor.process_cross_program_instruction(
|
match message_processor.process_cross_program_instruction(
|
||||||
@ -1237,8 +1276,11 @@ fn call<'a>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_runtime::bpf_test_utils::{MockComputeMeter, MockLogger};
|
use solana_sdk::{
|
||||||
use solana_sdk::hash::hashv;
|
bpf_loader,
|
||||||
|
hash::hashv,
|
||||||
|
process_instruction::{MockComputeMeter, MockLogger},
|
||||||
|
};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
macro_rules! assert_access_violation {
|
macro_rules! assert_access_violation {
|
||||||
|
@ -10,6 +10,7 @@ use solana_sdk::{
|
|||||||
hash::hash,
|
hash::hash,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::{next_keyed_account, KeyedAccount},
|
keyed_account::{next_keyed_account, KeyedAccount},
|
||||||
|
process_instruction::InvokeContext,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
@ -116,6 +117,7 @@ pub fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
||||||
let instruction = limited_deserialize(data)?;
|
let instruction = limited_deserialize(data)?;
|
||||||
@ -238,7 +240,7 @@ mod tests {
|
|||||||
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
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)
|
(bank, mint_keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,15 +3,19 @@
|
|||||||
use crate::ConfigKeys;
|
use crate::ConfigKeys;
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use log::*;
|
use log::*;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::{
|
||||||
use solana_sdk::keyed_account::{next_keyed_account, KeyedAccount};
|
instruction::InstructionError,
|
||||||
use solana_sdk::program_utils::limited_deserialize;
|
keyed_account::{next_keyed_account, KeyedAccount},
|
||||||
use solana_sdk::pubkey::Pubkey;
|
process_instruction::InvokeContext,
|
||||||
|
program_utils::limited_deserialize,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let key_list: ConfigKeys = limited_deserialize(data)?;
|
let key_list: ConfigKeys = limited_deserialize(data)?;
|
||||||
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
||||||
@ -109,6 +113,7 @@ mod tests {
|
|||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
keyed_account::create_keyed_is_signer_accounts,
|
keyed_account::create_keyed_is_signer_accounts,
|
||||||
|
process_instruction::MockInvokeContext,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
system_instruction::SystemInstruction,
|
system_instruction::SystemInstruction,
|
||||||
};
|
};
|
||||||
@ -162,7 +167,12 @@ mod tests {
|
|||||||
let accounts = vec![(&config_pubkey, true, &config_account)];
|
let accounts = vec![(&config_pubkey, true, &config_account)];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instructions[1].data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instructions[1].data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -192,7 +202,12 @@ mod tests {
|
|||||||
let accounts = vec![(&config_pubkey, true, &config_account)];
|
let accounts = vec![(&config_pubkey, true, &config_account)];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -214,7 +229,12 @@ mod tests {
|
|||||||
let accounts = vec![(&config_pubkey, true, &config_account)];
|
let accounts = vec![(&config_pubkey, true, &config_account)];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(InstructionError::InvalidInstructionData)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -232,7 +252,12 @@ mod tests {
|
|||||||
let accounts = vec![(&config_pubkey, false, &config_account)];
|
let accounts = vec![(&config_pubkey, false, &config_account)];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -262,7 +287,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
|
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 accounts = vec![(&signer0_pubkey, true, &signer0_account)];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -314,7 +349,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -325,7 +365,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -357,7 +402,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -372,7 +422,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
|
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);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -410,7 +470,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -443,7 +508,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -457,7 +527,12 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
let meta_data: ConfigKeys = deserialize(&config_account.borrow().data).unwrap();
|
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 accounts = vec![(&config_pubkey, true, &config_account)];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instruction.data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::MissingRequiredSignature)
|
Err(InstructionError::MissingRequiredSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -487,7 +567,12 @@ mod tests {
|
|||||||
let accounts = vec![];
|
let accounts = vec![];
|
||||||
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&id(), &keyed_accounts, &instructions[1].data),
|
process_instruction(
|
||||||
|
&id(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instructions[1].data,
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys)
|
Err(InstructionError::NotEnoughAccountKeys)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use serde_derive::Serialize;
|
|||||||
use solana_metrics::inc_new_counter_info;
|
use solana_metrics::inc_new_counter_info;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
decode_error::DecodeError, instruction::InstructionError, keyed_account::KeyedAccount,
|
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 std::cmp;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -464,6 +464,7 @@ pub fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
@ -578,7 +579,7 @@ mod test {
|
|||||||
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
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)
|
(bank, mint_keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::{
|
||||||
use solana_sdk::keyed_account::KeyedAccount;
|
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
|
||||||
use solana_sdk::pubkey::Pubkey;
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
|
||||||
solana_sdk::declare_program!(
|
solana_sdk::declare_program!(
|
||||||
"FaiLure111111111111111111111111111111111111",
|
"FaiLure111111111111111111111111111111111111",
|
||||||
@ -12,6 +13,7 @@ fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
_keyed_accounts: &[KeyedAccount],
|
_keyed_accounts: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
Err(InstructionError::Custom(0))
|
Err(InstructionError::Custom(0))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use log::*;
|
use log::*;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::{
|
||||||
use solana_sdk::keyed_account::KeyedAccount;
|
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
|
||||||
use solana_sdk::pubkey::Pubkey;
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
|
||||||
solana_sdk::declare_program!(
|
solana_sdk::declare_program!(
|
||||||
"Noop111111111111111111111111111111111111111",
|
"Noop111111111111111111111111111111111111111",
|
||||||
@ -13,6 +14,7 @@ fn process_instruction(
|
|||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
trace!("noop: program_id: {:?}", program_id);
|
trace!("noop: program_id: {:?}", program_id);
|
||||||
|
@ -5,6 +5,7 @@ use bincode::serialize_into;
|
|||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::{next_keyed_account, KeyedAccount},
|
keyed_account::{next_keyed_account, KeyedAccount},
|
||||||
|
process_instruction::InvokeContext,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
@ -30,6 +31,7 @@ pub fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let new_owner_pubkey: Pubkey = limited_deserialize(data)?;
|
let new_owner_pubkey: Pubkey = limited_deserialize(data)?;
|
||||||
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
||||||
@ -71,7 +73,7 @@ mod tests {
|
|||||||
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
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)
|
(bank, mint_keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
use solana_sdk::pubkey::Pubkey;
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
instruction::{Instruction, InstructionError},
|
instruction::{Instruction, InstructionError},
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
|
process_instruction::InvokeContext,
|
||||||
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
_keyed_accounts: &[KeyedAccount],
|
_keyed_accounts: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
// Should be already checked by now.
|
// Should be already checked by now.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
solana_sdk::declare_program!(
|
|
||||||
solana_sdk::secp256k1_program::ID,
|
|
||||||
solana_keccak_secp256k1_program,
|
|
||||||
process_instruction
|
|
||||||
);
|
|
||||||
|
|
||||||
pub fn new_secp256k1_instruction(
|
pub fn new_secp256k1_instruction(
|
||||||
priv_key: &secp256k1::SecretKey,
|
priv_key: &secp256k1::SecretKey,
|
||||||
message_arr: &[u8],
|
message_arr: &[u8],
|
||||||
|
@ -10,6 +10,7 @@ use solana_sdk::{
|
|||||||
decode_error::DecodeError,
|
decode_error::DecodeError,
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
|
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
|
||||||
|
process_instruction::InvokeContext,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction,
|
system_instruction,
|
||||||
@ -446,6 +447,7 @@ pub fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
trace!("keyed_accounts: {:?}", keyed_accounts);
|
trace!("keyed_accounts: {:?}", keyed_accounts);
|
||||||
@ -525,6 +527,7 @@ mod tests {
|
|||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{self, Account},
|
account::{self, Account},
|
||||||
|
process_instruction::MockInvokeContext,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
sysvar::stake_history::StakeHistory,
|
sysvar::stake_history::StakeHistory,
|
||||||
};
|
};
|
||||||
@ -562,7 +565,12 @@ mod tests {
|
|||||||
.zip(accounts.iter())
|
.zip(accounts.iter())
|
||||||
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
|
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
|
||||||
.collect();
|
.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()
|
Lockup::default()
|
||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
@ -679,6 +688,7 @@ mod tests {
|
|||||||
Lockup::default()
|
Lockup::default()
|
||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
@ -696,6 +706,7 @@ mod tests {
|
|||||||
Lockup::default()
|
Lockup::default()
|
||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidArgument),
|
Err(InstructionError::InvalidArgument),
|
||||||
);
|
);
|
||||||
@ -717,6 +728,7 @@ mod tests {
|
|||||||
Lockup::default()
|
Lockup::default()
|
||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
@ -731,6 +743,7 @@ mod tests {
|
|||||||
&create_default_account()
|
&create_default_account()
|
||||||
),],
|
),],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
@ -745,6 +758,7 @@ mod tests {
|
|||||||
&create_default_account()
|
&create_default_account()
|
||||||
)],
|
)],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
@ -776,6 +790,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
&serialize(&StakeInstruction::DelegateStake).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
@ -802,6 +817,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
|
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidArgument),
|
Err(InstructionError::InvalidArgument),
|
||||||
);
|
);
|
||||||
@ -816,6 +832,7 @@ mod tests {
|
|||||||
&create_default_account()
|
&create_default_account()
|
||||||
)],
|
)],
|
||||||
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
|
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
@ -836,6 +853,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
&serialize(&StakeInstruction::Deactivate).unwrap(),
|
&serialize(&StakeInstruction::Deactivate).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::InvalidArgument),
|
Err(InstructionError::InvalidArgument),
|
||||||
);
|
);
|
||||||
@ -846,6 +864,7 @@ mod tests {
|
|||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[],
|
&[],
|
||||||
&serialize(&StakeInstruction::Deactivate).unwrap(),
|
&serialize(&StakeInstruction::Deactivate).unwrap(),
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
),
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
|
@ -10,6 +10,7 @@ use solana_sdk::{
|
|||||||
account::Account,
|
account::Account,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::{next_keyed_account, KeyedAccount},
|
keyed_account::{next_keyed_account, KeyedAccount},
|
||||||
|
process_instruction::InvokeContext,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
@ -59,6 +60,7 @@ pub fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
let keyed_accounts_iter = &mut keyed_accounts.iter();
|
||||||
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?;
|
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) {
|
fn create_bank(lamports: u64) -> (Bank, Keypair) {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
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)
|
(bank, mint_keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ use solana_sdk::{
|
|||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
|
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
|
||||||
|
process_instruction::InvokeContext,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction,
|
system_instruction,
|
||||||
@ -277,6 +278,7 @@ pub fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
trace!("process_instruction: {:?}", data);
|
trace!("process_instruction: {:?}", data);
|
||||||
trace!("keyed_accounts: {:?}", keyed_accounts);
|
trace!("keyed_accounts: {:?}", keyed_accounts);
|
||||||
@ -333,6 +335,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{self, Account},
|
account::{self, Account},
|
||||||
|
process_instruction::MockInvokeContext,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -341,7 +344,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_vote_process_instruction_decode_bail() {
|
fn test_vote_process_instruction_decode_bail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(&Pubkey::default(), &[], &[],),
|
super::process_instruction(
|
||||||
|
&Pubkey::default(),
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&mut MockInvokeContext::default()
|
||||||
|
),
|
||||||
Err(InstructionError::NotEnoughAccountKeys),
|
Err(InstructionError::NotEnoughAccountKeys),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -374,7 +382,12 @@ mod tests {
|
|||||||
.zip(accounts.iter())
|
.zip(accounts.iter())
|
||||||
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
|
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
|
||||||
.collect();
|
.collect();
|
||||||
super::process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data)
|
super::process_instruction(
|
||||||
|
&Pubkey::default(),
|
||||||
|
&keyed_accounts,
|
||||||
|
&instruction.data,
|
||||||
|
&mut MockInvokeContext::default(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ use solana_sdk::{
|
|||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
message::Message,
|
message::Message,
|
||||||
|
process_instruction::InvokeContext,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
@ -33,6 +34,7 @@ fn process_instruction(
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
_keyed_accounts: &[KeyedAccount],
|
_keyed_accounts: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -123,7 +125,7 @@ fn do_bench_transactions(
|
|||||||
let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000);
|
let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000);
|
||||||
genesis_config.ticks_per_slot = 100;
|
genesis_config.ticks_per_slot = 100;
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
bank.add_builtin_program(
|
bank.add_builtin(
|
||||||
"builtin_program",
|
"builtin_program",
|
||||||
Pubkey::new(&BUILTIN_PROGRAM_ID),
|
Pubkey::new(&BUILTIN_PROGRAM_ID),
|
||||||
process_instruction,
|
process_instruction,
|
||||||
|
@ -17,10 +17,6 @@ use crate::{
|
|||||||
instruction_recorder::InstructionRecorder,
|
instruction_recorder::InstructionRecorder,
|
||||||
log_collector::LogCollector,
|
log_collector::LogCollector,
|
||||||
message_processor::{Executors, MessageProcessor},
|
message_processor::{Executors, MessageProcessor},
|
||||||
process_instruction::{
|
|
||||||
ErasedProcessInstruction, ErasedProcessInstructionWithContext, Executor,
|
|
||||||
ProcessInstruction, ProcessInstructionWithContext,
|
|
||||||
},
|
|
||||||
rent_collector::RentCollector,
|
rent_collector::RentCollector,
|
||||||
stakes::Stakes,
|
stakes::Stakes,
|
||||||
status_cache::{SlotDelta, StatusCache},
|
status_cache::{SlotDelta, StatusCache},
|
||||||
@ -55,6 +51,7 @@ use solana_sdk::{
|
|||||||
native_loader,
|
native_loader,
|
||||||
native_token::sol_to_lamports,
|
native_token::sol_to_lamports,
|
||||||
nonce, nonce_account,
|
nonce, nonce_account,
|
||||||
|
process_instruction::{BpfComputeBudget, Executor, ProcessInstructionWithContext},
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
recent_blockhashes_account,
|
recent_blockhashes_account,
|
||||||
@ -138,52 +135,33 @@ type RentCollectionCycleParams = (
|
|||||||
|
|
||||||
type EpochCount = u64;
|
type EpochCount = u64;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(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)]
|
|
||||||
pub struct Builtin {
|
pub struct Builtin {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: Pubkey,
|
pub id: Pubkey,
|
||||||
pub entrypoint: Entrypoint,
|
pub process_instruction_with_context: ProcessInstructionWithContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builtin {
|
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 {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
id,
|
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
|
/// Copy-on-write holder of CachedExecutors
|
||||||
#[derive(AbiExample, Debug, Default)]
|
#[derive(AbiExample, Debug, Default)]
|
||||||
struct CowCachedExecutors {
|
struct CowCachedExecutors {
|
||||||
@ -224,7 +202,7 @@ impl AbiExample for Builtin {
|
|||||||
Self {
|
Self {
|
||||||
name: String::default(),
|
name: String::default(),
|
||||||
id: Pubkey::default(),
|
id: Pubkey::default(),
|
||||||
entrypoint: Entrypoint::Program(|_, _, _| Ok(())),
|
process_instruction_with_context: |_, _, _, _| Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -693,6 +671,8 @@ pub struct Bank {
|
|||||||
/// The Message processor
|
/// The Message processor
|
||||||
message_processor: MessageProcessor,
|
message_processor: MessageProcessor,
|
||||||
|
|
||||||
|
bpf_compute_budget: Option<BpfComputeBudget>,
|
||||||
|
|
||||||
/// Builtin programs activated dynamically by feature
|
/// Builtin programs activated dynamically by feature
|
||||||
feature_builtins: Arc<Vec<(Builtin, Pubkey)>>,
|
feature_builtins: Arc<Vec<(Builtin, Pubkey)>>,
|
||||||
|
|
||||||
@ -829,6 +809,7 @@ impl Bank {
|
|||||||
tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
|
tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
|
||||||
signature_count: AtomicU64::new(0),
|
signature_count: AtomicU64::new(0),
|
||||||
message_processor: parent.message_processor.clone(),
|
message_processor: parent.message_processor.clone(),
|
||||||
|
bpf_compute_budget: parent.bpf_compute_budget,
|
||||||
feature_builtins: parent.feature_builtins.clone(),
|
feature_builtins: parent.feature_builtins.clone(),
|
||||||
hard_forks: parent.hard_forks.clone(),
|
hard_forks: parent.hard_forks.clone(),
|
||||||
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
|
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
|
||||||
@ -934,6 +915,7 @@ impl Bank {
|
|||||||
epoch_stakes: fields.epoch_stakes,
|
epoch_stakes: fields.epoch_stakes,
|
||||||
is_delta: AtomicBool::new(fields.is_delta),
|
is_delta: AtomicBool::new(fields.is_delta),
|
||||||
message_processor: new(),
|
message_processor: new(),
|
||||||
|
bpf_compute_budget: None,
|
||||||
feature_builtins: new(),
|
feature_builtins: new(),
|
||||||
last_vote_sync: new(),
|
last_vote_sync: new(),
|
||||||
rewards: new(),
|
rewards: new(),
|
||||||
@ -2375,6 +2357,9 @@ impl Bank {
|
|||||||
let mut inner_instructions: Vec<Option<InnerInstructionsList>> =
|
let mut inner_instructions: Vec<Option<InnerInstructionsList>> =
|
||||||
Vec::with_capacity(txs.len());
|
Vec::with_capacity(txs.len());
|
||||||
let mut transaction_logs: Vec<TransactionLogMessages> = 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
|
let executed: Vec<TransactionProcessResult> = loaded_accounts
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -2413,6 +2398,7 @@ impl Bank {
|
|||||||
executors.clone(),
|
executors.clone(),
|
||||||
instruction_recorders.as_deref(),
|
instruction_recorders.as_deref(),
|
||||||
self.feature_set.clone(),
|
self.feature_set.clone(),
|
||||||
|
bpf_compute_budget,
|
||||||
);
|
);
|
||||||
|
|
||||||
if enable_log_recording {
|
if enable_log_recording {
|
||||||
@ -3365,7 +3351,11 @@ impl Bank {
|
|||||||
.extend_from_slice(&additional_builtins.feature_builtins);
|
.extend_from_slice(&additional_builtins.feature_builtins);
|
||||||
}
|
}
|
||||||
for builtin in builtins.genesis_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);
|
self.feature_builtins = Arc::new(builtins.feature_builtins);
|
||||||
|
|
||||||
@ -3376,6 +3366,10 @@ impl Bank {
|
|||||||
*self.inflation.write().unwrap() = inflation;
|
*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>> {
|
pub fn hard_forks(&self) -> Arc<RwLock<HardForks>> {
|
||||||
self.hard_forks.clone()
|
self.hard_forks.clone()
|
||||||
}
|
}
|
||||||
@ -3823,43 +3817,17 @@ impl Bank {
|
|||||||
!self.is_delta.load(Relaxed)
|
!self.is_delta.load(Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_builtin_program(
|
/// Add an instruction processor to intercept instructions before the dynamic loader.
|
||||||
&mut self,
|
pub fn add_builtin(
|
||||||
name: &str,
|
|
||||||
program_id: Pubkey,
|
|
||||||
process_instruction: ProcessInstruction,
|
|
||||||
) {
|
|
||||||
self.add_builtin(name, program_id, Entrypoint::Program(process_instruction));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_builtin_loader(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
process_instruction_with_context: ProcessInstructionWithContext,
|
process_instruction_with_context: ProcessInstructionWithContext,
|
||||||
) {
|
) {
|
||||||
self.add_builtin(
|
debug!("Added program {} under {:?}", name, program_id);
|
||||||
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) {
|
|
||||||
self.add_native_program(name, &program_id);
|
self.add_native_program(name, &program_id);
|
||||||
match entrypoint {
|
|
||||||
Entrypoint::Program(process_instruction) => {
|
|
||||||
self.message_processor
|
self.message_processor
|
||||||
.add_program(program_id, process_instruction);
|
.add_program(program_id, process_instruction_with_context);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean_accounts(&self, skip_last: bool) {
|
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)
|
let should_populate = init_or_warp && self.feature_set.is_active(&feature)
|
||||||
|| !init_or_warp && new_feature_activations.contains(&feature);
|
|| !init_or_warp && new_feature_activations.contains(&feature);
|
||||||
if should_populate {
|
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,
|
BOOTSTRAP_VALIDATOR_LAMPORTS,
|
||||||
},
|
},
|
||||||
native_loader::NativeLoaderError,
|
native_loader::NativeLoaderError,
|
||||||
process_instruction::InvokeContext,
|
|
||||||
status_cache::MAX_CACHE_ENTRIES,
|
status_cache::MAX_CACHE_ENTRIES,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -4138,6 +4109,7 @@ mod tests {
|
|||||||
message::{Message, MessageHeader},
|
message::{Message, MessageHeader},
|
||||||
nonce,
|
nonce,
|
||||||
poh_config::PohConfig,
|
poh_config::PohConfig,
|
||||||
|
process_instruction::InvokeContext,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
system_instruction::{self, SystemError},
|
system_instruction::{self, SystemError},
|
||||||
@ -4428,6 +4400,7 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
if let Ok(instruction) = bincode::deserialize(data) {
|
if let Ok(instruction) = bincode::deserialize(data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
@ -4577,7 +4550,7 @@ mod tests {
|
|||||||
) as u64,
|
) as u64,
|
||||||
);
|
);
|
||||||
bank.rent_collector.slots_per_year = 421_812.0;
|
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
|
bank
|
||||||
}
|
}
|
||||||
@ -7713,7 +7686,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_builtin_program() {
|
fn test_add_builtin() {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
||||||
let mut bank = Bank::new(&genesis_config);
|
let mut bank = Bank::new(&genesis_config);
|
||||||
|
|
||||||
@ -7724,6 +7697,7 @@ mod tests {
|
|||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
_keyed_accounts: &[KeyedAccount],
|
_keyed_accounts: &[KeyedAccount],
|
||||||
_instruction_data: &[u8],
|
_instruction_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
if mock_vote_program_id() != *program_id {
|
if mock_vote_program_id() != *program_id {
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(InstructionError::IncorrectProgramId);
|
||||||
@ -7732,7 +7706,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert!(bank.get_account(&mock_vote_program_id()).is_none());
|
assert!(bank.get_account(&mock_vote_program_id()).is_none());
|
||||||
bank.add_builtin_program(
|
bank.add_builtin(
|
||||||
"mock_vote_program",
|
"mock_vote_program",
|
||||||
mock_vote_program_id(),
|
mock_vote_program_id(),
|
||||||
mock_vote_processor,
|
mock_vote_processor,
|
||||||
@ -7781,6 +7755,7 @@ mod tests {
|
|||||||
_pubkey: &Pubkey,
|
_pubkey: &Pubkey,
|
||||||
_ka: &[KeyedAccount],
|
_ka: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
Err(InstructionError::Custom(42))
|
Err(InstructionError::Custom(42))
|
||||||
}
|
}
|
||||||
@ -7805,7 +7780,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
|
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",
|
||||||
solana_vote_program::id(),
|
solana_vote_program::id(),
|
||||||
mock_vote_processor,
|
mock_vote_processor,
|
||||||
@ -7831,6 +7806,7 @@ mod tests {
|
|||||||
_pubkey: &Pubkey,
|
_pubkey: &Pubkey,
|
||||||
_ka: &[KeyedAccount],
|
_ka: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
Err(InstructionError::Custom(42))
|
Err(InstructionError::Custom(42))
|
||||||
}
|
}
|
||||||
@ -7850,15 +7826,15 @@ mod tests {
|
|||||||
assert!(!bank.stakes.read().unwrap().stake_delegations().is_empty());
|
assert!(!bank.stakes.read().unwrap().stake_delegations().is_empty());
|
||||||
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
|
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
|
||||||
|
|
||||||
bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor);
|
bank.add_builtin("mock_program1", vote_id, mock_ix_processor);
|
||||||
bank.add_builtin_program("mock_program2", stake_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().vote_accounts().is_empty());
|
||||||
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
|
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
|
||||||
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
|
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
|
||||||
|
|
||||||
// Re-adding builtin programs should be no-op
|
// Re-adding builtin programs should be no-op
|
||||||
bank.add_builtin_program("mock_program1", vote_id, mock_ix_processor);
|
bank.add_builtin("mock_program1", vote_id, mock_ix_processor);
|
||||||
bank.add_builtin_program("mock_program2", stake_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().vote_accounts().is_empty());
|
||||||
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
|
assert!(bank.stakes.read().unwrap().stake_delegations().is_empty());
|
||||||
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
|
assert_eq!(bank.calculate_capitalization(), bank.capitalization());
|
||||||
@ -8499,6 +8475,7 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
let lamports = data[0] as u64;
|
let lamports = data[0] as u64;
|
||||||
{
|
{
|
||||||
@ -8513,7 +8490,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
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 from_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
let to_pubkey = solana_sdk::pubkey::new_rand();
|
let to_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
@ -8551,12 +8528,13 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
_keyed_accounts: &[KeyedAccount],
|
_keyed_accounts: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
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 from_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
let to_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());
|
tx.message.account_keys.push(solana_sdk::pubkey::new_rand());
|
||||||
|
|
||||||
bank.add_builtin_program(
|
bank.add_builtin(
|
||||||
"mock_vote",
|
"mock_vote",
|
||||||
solana_vote_program::id(),
|
solana_vote_program::id(),
|
||||||
mock_ok_vote_processor,
|
mock_ok_vote_processor,
|
||||||
@ -8662,7 +8640,7 @@ mod tests {
|
|||||||
AccountMeta::new(to_pubkey, false),
|
AccountMeta::new(to_pubkey, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
bank.add_builtin_program(
|
bank.add_builtin(
|
||||||
"mock_vote",
|
"mock_vote",
|
||||||
solana_vote_program::id(),
|
solana_vote_program::id(),
|
||||||
mock_ok_vote_processor,
|
mock_ok_vote_processor,
|
||||||
@ -8695,7 +8673,7 @@ mod tests {
|
|||||||
AccountMeta::new(to_pubkey, false),
|
AccountMeta::new(to_pubkey, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
bank.add_builtin_program(
|
bank.add_builtin(
|
||||||
"mock_vote",
|
"mock_vote",
|
||||||
solana_vote_program::id(),
|
solana_vote_program::id(),
|
||||||
mock_ok_vote_processor,
|
mock_ok_vote_processor,
|
||||||
@ -8733,6 +8711,7 @@ mod tests {
|
|||||||
_pubkey: &Pubkey,
|
_pubkey: &Pubkey,
|
||||||
_ka: &[KeyedAccount],
|
_ka: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -8750,7 +8729,7 @@ mod tests {
|
|||||||
AccountMeta::new(to_pubkey, false),
|
AccountMeta::new(to_pubkey, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
bank.add_builtin_program(
|
bank.add_builtin(
|
||||||
"mock_vote",
|
"mock_vote",
|
||||||
solana_vote_program::id(),
|
solana_vote_program::id(),
|
||||||
mock_ok_vote_processor,
|
mock_ok_vote_processor,
|
||||||
@ -8786,7 +8765,7 @@ mod tests {
|
|||||||
.map(|i| {
|
.map(|i| {
|
||||||
let key = solana_sdk::pubkey::new_rand();
|
let key = solana_sdk::pubkey::new_rand();
|
||||||
let name = format!("program{:?}", i);
|
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())
|
(key, name.as_bytes().to_vec())
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -8981,6 +8960,7 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
assert_eq!(42, keyed_accounts[0].lamports().unwrap());
|
assert_eq!(42, keyed_accounts[0].lamports().unwrap());
|
||||||
let mut account = keyed_accounts[0].try_account_ref_mut()?;
|
let mut account = keyed_accounts[0].try_account_ref_mut()?;
|
||||||
@ -8993,7 +8973,7 @@ mod tests {
|
|||||||
|
|
||||||
// Add a new program
|
// Add a new program
|
||||||
let program1_pubkey = solana_sdk::pubkey::new_rand();
|
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
|
// Add a new program owned by the first
|
||||||
let program2_pubkey = solana_sdk::pubkey::new_rand();
|
let program2_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
@ -9155,13 +9135,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_builtin_program_no_overwrite() {
|
fn test_add_builtin_no_overwrite() {
|
||||||
let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
|
let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
|
||||||
|
|
||||||
fn mock_ix_processor(
|
fn mock_ix_processor(
|
||||||
_pubkey: &Pubkey,
|
_pubkey: &Pubkey,
|
||||||
_ka: &[KeyedAccount],
|
_ka: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -9176,19 +9157,15 @@ mod tests {
|
|||||||
));
|
));
|
||||||
assert_eq!(bank.get_account_modified_slot(&program_id), None);
|
assert_eq!(bank.get_account_modified_slot(&program_id), None);
|
||||||
|
|
||||||
Arc::get_mut(&mut bank).unwrap().add_builtin_program(
|
Arc::get_mut(&mut bank)
|
||||||
"mock_program",
|
.unwrap()
|
||||||
program_id,
|
.add_builtin("mock_program", program_id, mock_ix_processor);
|
||||||
mock_ix_processor,
|
|
||||||
);
|
|
||||||
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
||||||
|
|
||||||
let mut bank = Arc::new(new_from_parent(&bank));
|
let mut bank = Arc::new(new_from_parent(&bank));
|
||||||
Arc::get_mut(&mut bank).unwrap().add_builtin_program(
|
Arc::get_mut(&mut bank)
|
||||||
"mock_program",
|
.unwrap()
|
||||||
program_id,
|
.add_builtin("mock_program", program_id, mock_ix_processor);
|
||||||
mock_ix_processor,
|
|
||||||
);
|
|
||||||
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
|
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);
|
assert_eq!(bank.get_account_modified_slot(&loader_id), None);
|
||||||
|
|
||||||
Arc::get_mut(&mut bank).unwrap().add_builtin_loader(
|
Arc::get_mut(&mut bank)
|
||||||
"mock_program",
|
.unwrap()
|
||||||
loader_id,
|
.add_builtin("mock_program", loader_id, mock_ix_processor);
|
||||||
mock_ix_processor,
|
|
||||||
);
|
|
||||||
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
||||||
|
|
||||||
let mut bank = Arc::new(new_from_parent(&bank));
|
let mut bank = Arc::new(new_from_parent(&bank));
|
||||||
Arc::get_mut(&mut bank).unwrap().add_builtin_loader(
|
Arc::get_mut(&mut bank)
|
||||||
"mock_program",
|
.unwrap()
|
||||||
loader_id,
|
.add_builtin("mock_program", loader_id, mock_ix_processor);
|
||||||
mock_ix_processor,
|
|
||||||
);
|
|
||||||
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10061,25 +10034,4 @@ mod tests {
|
|||||||
let debug = format!("{:#?}", bank);
|
let debug = format!("{:#?}", bank);
|
||||||
assert!(!debug.is_empty());
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bank::{Builtin, Builtins, Entrypoint},
|
bank::{Builtin, Builtins},
|
||||||
feature_set, system_instruction_processor,
|
feature_set, system_instruction_processor,
|
||||||
};
|
};
|
||||||
use solana_sdk::{pubkey::Pubkey, system_program};
|
use solana_sdk::{pubkey::Pubkey, system_program};
|
||||||
@ -10,22 +10,22 @@ fn genesis_builtins() -> Vec<Builtin> {
|
|||||||
Builtin::new(
|
Builtin::new(
|
||||||
"system_program",
|
"system_program",
|
||||||
system_program::id(),
|
system_program::id(),
|
||||||
Entrypoint::Program(system_instruction_processor::process_instruction),
|
system_instruction_processor::process_instruction,
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"vote_program",
|
"vote_program",
|
||||||
solana_vote_program::id(),
|
solana_vote_program::id(),
|
||||||
Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction),
|
solana_vote_program::vote_instruction::process_instruction,
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"stake_program",
|
"stake_program",
|
||||||
solana_stake_program::id(),
|
solana_stake_program::id(),
|
||||||
Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction),
|
solana_stake_program::stake_instruction::process_instruction,
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"config_program",
|
"config_program",
|
||||||
solana_config_program::id(),
|
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(
|
Builtin::new(
|
||||||
"secp256k1_program",
|
"secp256k1_program",
|
||||||
solana_sdk::secp256k1_program::id(),
|
solana_sdk::secp256k1_program::id(),
|
||||||
Entrypoint::Program(solana_secp256k1_program::process_instruction),
|
solana_secp256k1_program::process_instruction,
|
||||||
),
|
),
|
||||||
feature_set::secp256k1_program_enabled::id(),
|
feature_set::secp256k1_program_enabled::id(),
|
||||||
)]
|
)]
|
||||||
|
@ -10,12 +10,9 @@ pub mod bank_forks;
|
|||||||
pub mod bank_utils;
|
pub mod bank_utils;
|
||||||
mod blockhash_queue;
|
mod blockhash_queue;
|
||||||
pub mod bloom;
|
pub mod bloom;
|
||||||
pub mod bpf_test_utils;
|
|
||||||
pub mod builtins;
|
pub mod builtins;
|
||||||
pub mod commitment;
|
pub mod commitment;
|
||||||
pub mod epoch_stakes;
|
pub mod epoch_stakes;
|
||||||
pub mod feature;
|
|
||||||
pub mod feature_set;
|
|
||||||
pub mod genesis_utils;
|
pub mod genesis_utils;
|
||||||
pub mod hardened_unpack;
|
pub mod hardened_unpack;
|
||||||
pub mod instruction_recorder;
|
pub mod instruction_recorder;
|
||||||
@ -23,7 +20,6 @@ pub mod loader_utils;
|
|||||||
pub mod log_collector;
|
pub mod log_collector;
|
||||||
pub mod message_processor;
|
pub mod message_processor;
|
||||||
mod native_loader;
|
mod native_loader;
|
||||||
pub mod process_instruction;
|
|
||||||
pub mod rent_collector;
|
pub mod rent_collector;
|
||||||
pub mod serde_snapshot;
|
pub mod serde_snapshot;
|
||||||
pub mod snapshot_package;
|
pub mod snapshot_package;
|
||||||
@ -35,6 +31,10 @@ pub mod transaction_batch;
|
|||||||
pub mod transaction_utils;
|
pub mod transaction_utils;
|
||||||
pub mod vote_sender_types;
|
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_config_program;
|
||||||
extern crate solana_stake_program;
|
extern crate solana_stake_program;
|
||||||
extern crate solana_vote_program;
|
extern crate solana_vote_program;
|
||||||
|
@ -3,10 +3,6 @@ use crate::{
|
|||||||
instruction_recorder::InstructionRecorder,
|
instruction_recorder::InstructionRecorder,
|
||||||
log_collector::LogCollector,
|
log_collector::LogCollector,
|
||||||
native_loader::NativeLoader,
|
native_loader::NativeLoader,
|
||||||
process_instruction::{
|
|
||||||
ComputeBudget, ComputeMeter, ErasedProcessInstruction, ErasedProcessInstructionWithContext,
|
|
||||||
Executor, InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext,
|
|
||||||
},
|
|
||||||
rent_collector::RentCollector,
|
rent_collector::RentCollector,
|
||||||
};
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
@ -18,6 +14,10 @@ use solana_sdk::{
|
|||||||
keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
|
keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
|
||||||
message::Message,
|
message::Message,
|
||||||
native_loader,
|
native_loader,
|
||||||
|
process_instruction::{
|
||||||
|
BpfComputeBudget, ComputeMeter, Executor, InvokeContext, Logger,
|
||||||
|
ProcessInstructionWithContext,
|
||||||
|
},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
system_program,
|
system_program,
|
||||||
@ -201,31 +201,31 @@ impl ComputeMeter for ThisComputeMeter {
|
|||||||
self.remaining
|
self.remaining
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct ThisInvokeContext {
|
pub struct ThisInvokeContext<'a> {
|
||||||
program_ids: Vec<Pubkey>,
|
program_ids: Vec<Pubkey>,
|
||||||
rent: Rent,
|
rent: Rent,
|
||||||
pre_accounts: Vec<PreAccount>,
|
pre_accounts: Vec<PreAccount>,
|
||||||
programs: Vec<(Pubkey, ProcessInstruction)>,
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
||||||
logger: Rc<RefCell<dyn Logger>>,
|
logger: Rc<RefCell<dyn Logger>>,
|
||||||
compute_budget: ComputeBudget,
|
bpf_compute_budget: BpfComputeBudget,
|
||||||
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
instruction_recorder: Option<InstructionRecorder>,
|
instruction_recorder: Option<InstructionRecorder>,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
}
|
}
|
||||||
impl ThisInvokeContext {
|
impl<'a> ThisInvokeContext<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
rent: Rent,
|
rent: Rent,
|
||||||
pre_accounts: Vec<PreAccount>,
|
pre_accounts: Vec<PreAccount>,
|
||||||
programs: Vec<(Pubkey, ProcessInstruction)>,
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
||||||
log_collector: Option<Rc<LogCollector>>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
compute_budget: ComputeBudget,
|
bpf_compute_budget: BpfComputeBudget,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
instruction_recorder: Option<InstructionRecorder>,
|
instruction_recorder: Option<InstructionRecorder>,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
) -> Self {
|
) -> 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);
|
program_ids.push(*program_id);
|
||||||
Self {
|
Self {
|
||||||
program_ids,
|
program_ids,
|
||||||
@ -233,9 +233,9 @@ impl ThisInvokeContext {
|
|||||||
pre_accounts,
|
pre_accounts,
|
||||||
programs,
|
programs,
|
||||||
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
||||||
compute_budget,
|
bpf_compute_budget,
|
||||||
compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
|
compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
|
||||||
remaining: compute_budget.max_units,
|
remaining: bpf_compute_budget.max_units,
|
||||||
})),
|
})),
|
||||||
executors,
|
executors,
|
||||||
instruction_recorder,
|
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> {
|
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);
|
return Err(InstructionError::CallDepth);
|
||||||
}
|
}
|
||||||
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
|
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
|
||||||
@ -281,14 +281,14 @@ impl InvokeContext for ThisInvokeContext {
|
|||||||
.last()
|
.last()
|
||||||
.ok_or(InstructionError::GenericError)
|
.ok_or(InstructionError::GenericError)
|
||||||
}
|
}
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
|
||||||
&self.programs
|
self.programs
|
||||||
}
|
}
|
||||||
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
||||||
self.logger.clone()
|
self.logger.clone()
|
||||||
}
|
}
|
||||||
fn get_compute_budget(&self) -> &ComputeBudget {
|
fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
|
||||||
&self.compute_budget
|
&self.bpf_compute_budget
|
||||||
}
|
}
|
||||||
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
|
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
|
||||||
self.compute_meter.clone()
|
self.compute_meter.clone()
|
||||||
@ -326,9 +326,7 @@ impl Logger for ThisLogger {
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct MessageProcessor {
|
pub struct MessageProcessor {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
programs: Vec<(Pubkey, ProcessInstruction)>,
|
programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
|
||||||
#[serde(skip)]
|
|
||||||
loaders: Vec<(Pubkey, ProcessInstructionWithContext)>,
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
native_loader: NativeLoader,
|
native_loader: NativeLoader,
|
||||||
}
|
}
|
||||||
@ -338,9 +336,17 @@ impl std::fmt::Debug for MessageProcessor {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct MessageProcessor<'a> {
|
struct MessageProcessor<'a> {
|
||||||
programs: Vec<String>,
|
programs: Vec<String>,
|
||||||
loaders: Vec<String>,
|
|
||||||
native_loader: &'a NativeLoader,
|
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
|
// rustc doesn't compile due to bug without this work around
|
||||||
// https://github.com/rust-lang/rust/issues/50280
|
// https://github.com/rust-lang/rust/issues/50280
|
||||||
// https://users.rust-lang.org/t/display-function-pointer/17073/2
|
// https://users.rust-lang.org/t/display-function-pointer/17073/2
|
||||||
@ -348,14 +354,6 @@ impl std::fmt::Debug for MessageProcessor {
|
|||||||
programs: self
|
programs: self
|
||||||
.programs
|
.programs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(pubkey, instruction)| {
|
|
||||||
let erased_instruction: ErasedProcessInstruction = *instruction;
|
|
||||||
format!("{}: {:p}", pubkey, erased_instruction)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
loaders: self
|
|
||||||
.loaders
|
|
||||||
.iter()
|
|
||||||
.map(|(pubkey, instruction)| {
|
.map(|(pubkey, instruction)| {
|
||||||
let erased_instruction: ErasedProcessInstructionWithContext = *instruction;
|
let erased_instruction: ErasedProcessInstructionWithContext = *instruction;
|
||||||
format!("{}: {:p}", pubkey, erased_instruction)
|
format!("{}: {:p}", pubkey, erased_instruction)
|
||||||
@ -372,7 +370,6 @@ impl Default for MessageProcessor {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
programs: vec![],
|
programs: vec![],
|
||||||
loaders: vec![],
|
|
||||||
native_loader: NativeLoader::default(),
|
native_loader: NativeLoader::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,7 +378,6 @@ impl Clone for MessageProcessor {
|
|||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
MessageProcessor {
|
MessageProcessor {
|
||||||
programs: self.programs.clone(),
|
programs: self.programs.clone(),
|
||||||
loaders: self.loaders.clone(),
|
|
||||||
native_loader: NativeLoader::default(),
|
native_loader: NativeLoader::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,7 +394,11 @@ impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor {
|
|||||||
|
|
||||||
impl MessageProcessor {
|
impl MessageProcessor {
|
||||||
/// Add a static entrypoint to intercept instructions before the dynamic loader.
|
/// 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) {
|
match self.programs.iter_mut().find(|(key, _)| program_id == *key) {
|
||||||
Some((_, processor)) => *processor = process_instruction,
|
Some((_, processor)) => *processor = process_instruction,
|
||||||
None => self.programs.push((program_id, process_instruction)),
|
None => self.programs.push((program_id, process_instruction)),
|
||||||
@ -410,14 +410,7 @@ impl MessageProcessor {
|
|||||||
program_id: Pubkey,
|
program_id: Pubkey,
|
||||||
process_instruction: ProcessInstructionWithContext,
|
process_instruction: ProcessInstructionWithContext,
|
||||||
) {
|
) {
|
||||||
match self.loaders.iter_mut().find(|(key, _)| program_id == *key) {
|
self.add_program(program_id, process_instruction);
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the KeyedAccounts that will be passed to the program
|
/// 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 let Some(root_account) = keyed_accounts.iter().next() {
|
||||||
if native_loader::check_id(&root_account.owner()?) {
|
if native_loader::check_id(&root_account.owner()?) {
|
||||||
let root_id = root_account.unsigned_key();
|
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 {
|
for (id, process_instruction) in &self.programs {
|
||||||
if id == root_id {
|
if id == root_id {
|
||||||
// Call the builtin program
|
// Call the builtin program
|
||||||
@ -476,6 +458,7 @@ impl MessageProcessor {
|
|||||||
&root_id,
|
&root_id,
|
||||||
&keyed_accounts[1..],
|
&keyed_accounts[1..],
|
||||||
instruction_data,
|
instruction_data,
|
||||||
|
invoke_context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -488,7 +471,7 @@ impl MessageProcessor {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let owner_id = &root_account.owner()?;
|
let owner_id = &root_account.owner()?;
|
||||||
for (id, process_instruction) in &self.loaders {
|
for (id, process_instruction) in &self.programs {
|
||||||
if id == owner_id {
|
if id == owner_id {
|
||||||
// Call the program via a builtin loader
|
// Call the program via a builtin loader
|
||||||
return process_instruction(
|
return process_instruction(
|
||||||
@ -667,6 +650,7 @@ impl MessageProcessor {
|
|||||||
instruction_recorder: Option<InstructionRecorder>,
|
instruction_recorder: Option<InstructionRecorder>,
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
|
bpf_compute_budget: BpfComputeBudget,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
// Fixup the special instructions key if present
|
// Fixup the special instructions key if present
|
||||||
// before the account pre-values are taken care of
|
// before the account pre-values are taken care of
|
||||||
@ -688,9 +672,9 @@ impl MessageProcessor {
|
|||||||
instruction.program_id(&message.account_keys),
|
instruction.program_id(&message.account_keys),
|
||||||
rent_collector.rent,
|
rent_collector.rent,
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
self.programs.clone(), // get rid of clone
|
&self.programs,
|
||||||
log_collector,
|
log_collector,
|
||||||
Self::get_compute_budget(&feature_set),
|
bpf_compute_budget,
|
||||||
executors,
|
executors,
|
||||||
instruction_recorder,
|
instruction_recorder,
|
||||||
feature_set,
|
feature_set,
|
||||||
@ -723,6 +707,7 @@ impl MessageProcessor {
|
|||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
instruction_recorders: Option<&[InstructionRecorder]>,
|
instruction_recorders: Option<&[InstructionRecorder]>,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
|
bpf_compute_budget: BpfComputeBudget,
|
||||||
) -> Result<(), TransactionError> {
|
) -> Result<(), TransactionError> {
|
||||||
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
||||||
let instruction_recorder = instruction_recorders
|
let instruction_recorder = instruction_recorders
|
||||||
@ -739,6 +724,7 @@ impl MessageProcessor {
|
|||||||
instruction_recorder,
|
instruction_recorder,
|
||||||
instruction_index,
|
instruction_index,
|
||||||
feature_set.clone(),
|
feature_set.clone(),
|
||||||
|
bpf_compute_budget,
|
||||||
)
|
)
|
||||||
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
||||||
}
|
}
|
||||||
@ -781,9 +767,9 @@ mod tests {
|
|||||||
&program_ids[0],
|
&program_ids[0],
|
||||||
Rent::default(),
|
Rent::default(),
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
vec![],
|
&[],
|
||||||
None,
|
None,
|
||||||
ComputeBudget::default(),
|
BpfComputeBudget::default(),
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
Rc::new(RefCell::new(Executors::default())),
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
@ -1266,6 +1252,7 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if let Ok(instruction) = bincode::deserialize(data) {
|
if let Ok(instruction) = bincode::deserialize(data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
@ -1327,6 +1314,7 @@ mod tests {
|
|||||||
executors.clone(),
|
executors.clone(),
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
|
BpfComputeBudget::new(&FeatureSet::all_enabled()),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
assert_eq!(accounts[0].borrow().lamports, 100);
|
assert_eq!(accounts[0].borrow().lamports, 100);
|
||||||
@ -1350,6 +1338,7 @@ mod tests {
|
|||||||
executors.clone(),
|
executors.clone(),
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
|
BpfComputeBudget::new(&FeatureSet::all_enabled()),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -1377,6 +1366,7 @@ mod tests {
|
|||||||
executors,
|
executors,
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
|
BpfComputeBudget::new(&FeatureSet::all_enabled()),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -1400,6 +1390,7 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if let Ok(instruction) = bincode::deserialize(data) {
|
if let Ok(instruction) = bincode::deserialize(data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
@ -1487,6 +1478,7 @@ mod tests {
|
|||||||
executors.clone(),
|
executors.clone(),
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
|
BpfComputeBudget::new(&FeatureSet::all_enabled()),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -1514,6 +1506,7 @@ mod tests {
|
|||||||
executors.clone(),
|
executors.clone(),
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
|
BpfComputeBudget::new(&FeatureSet::all_enabled()),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
|
|
||||||
@ -1538,6 +1531,7 @@ mod tests {
|
|||||||
executors,
|
executors,
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
|
BpfComputeBudget::new(&FeatureSet::all_enabled()),
|
||||||
);
|
);
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
assert_eq!(accounts[0].borrow().lamports, 80);
|
assert_eq!(accounts[0].borrow().lamports, 80);
|
||||||
@ -1559,6 +1553,7 @@ mod tests {
|
|||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
assert_eq!(*program_id, keyed_accounts[0].owner()?);
|
assert_eq!(*program_id, keyed_accounts[0].owner()?);
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
@ -1609,9 +1604,9 @@ mod tests {
|
|||||||
&caller_program_id,
|
&caller_program_id,
|
||||||
Rent::default(),
|
Rent::default(),
|
||||||
vec![owned_preaccount, not_owned_preaccount],
|
vec![owned_preaccount, not_owned_preaccount],
|
||||||
vec![],
|
&[],
|
||||||
None,
|
None,
|
||||||
ComputeBudget::default(),
|
BpfComputeBudget::default(),
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
Rc::new(RefCell::new(Executors::default())),
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
@ -1675,6 +1670,7 @@ mod tests {
|
|||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
_keyed_accounts: &[KeyedAccount],
|
_keyed_accounts: &[KeyedAccount],
|
||||||
_data: &[u8],
|
_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
//! Native loader
|
//! Native loader
|
||||||
use crate::process_instruction::{InvokeContext, LoaderEntrypoint};
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use libloading::os::unix::*;
|
use libloading::os::unix::*;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -11,6 +10,7 @@ use solana_sdk::{
|
|||||||
entrypoint_native::ProgramEntrypoint,
|
entrypoint_native::ProgramEntrypoint,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::{next_keyed_account, KeyedAccount},
|
keyed_account::{next_keyed_account, KeyedAccount},
|
||||||
|
process_instruction::{InvokeContext, LoaderEntrypoint},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock};
|
use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock};
|
||||||
|
@ -6,6 +6,7 @@ use solana_sdk::{
|
|||||||
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
|
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
|
||||||
nonce,
|
nonce,
|
||||||
nonce_keyed_account::NonceKeyedAccount,
|
nonce_keyed_account::NonceKeyedAccount,
|
||||||
|
process_instruction::InvokeContext,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH},
|
system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH},
|
||||||
@ -213,6 +214,7 @@ pub fn process_instruction(
|
|||||||
_owner: &Pubkey,
|
_owner: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
|
_invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let instruction = limited_deserialize(instruction_data)?;
|
let instruction = limited_deserialize(instruction_data)?;
|
||||||
|
|
||||||
@ -363,7 +365,9 @@ mod tests {
|
|||||||
hash::{hash, Hash},
|
hash::{hash, Hash},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
nonce, nonce_account, recent_blockhashes_account,
|
nonce, nonce_account,
|
||||||
|
process_instruction::MockInvokeContext,
|
||||||
|
recent_blockhashes_account,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
system_instruction, system_program, sysvar,
|
system_instruction, system_program, sysvar,
|
||||||
sysvar::recent_blockhashes::IterItem,
|
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> {
|
fn create_default_account() -> RefCell<Account> {
|
||||||
RefCell::new(Account::default())
|
RefCell::new(Account::default())
|
||||||
}
|
}
|
||||||
@ -1194,7 +1211,7 @@ mod tests {
|
|||||||
.zip(accounts.iter())
|
.zip(accounts.iter())
|
||||||
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
|
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
|
||||||
.collect();
|
.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]
|
#[test]
|
||||||
fn test_process_nonce_ix_no_keyed_accs_fail() {
|
fn test_process_nonce_ix_no_keyed_accs_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[],
|
&[],
|
||||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap()
|
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap()
|
||||||
@ -1224,7 +1241,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_nonce_ix_only_nonce_acc_fail() {
|
fn test_process_nonce_ix_only_nonce_acc_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[KeyedAccount::new(
|
&[KeyedAccount::new(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@ -1240,7 +1257,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_nonce_ix_bad_recent_blockhash_state_fail() {
|
fn test_process_nonce_ix_bad_recent_blockhash_state_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
|
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
|
||||||
@ -1259,7 +1276,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_nonce_ix_ok() {
|
fn test_process_nonce_ix_ok() {
|
||||||
let nonce_acc = nonce_account::create_account(1_000_000);
|
let nonce_acc = nonce_account::create_account(1_000_000);
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
|
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
|
||||||
@ -1288,7 +1305,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),
|
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),
|
||||||
@ -1320,7 +1337,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_withdraw_ix_no_keyed_accs_fail() {
|
fn test_process_withdraw_ix_no_keyed_accs_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[],
|
&[],
|
||||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||||
@ -1332,7 +1349,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_withdraw_ix_only_nonce_acc_fail() {
|
fn test_process_withdraw_ix_only_nonce_acc_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[KeyedAccount::new(
|
&[KeyedAccount::new(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@ -1348,7 +1365,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() {
|
fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
|
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
|
||||||
@ -1368,7 +1385,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_withdraw_ix_bad_rent_state_fail() {
|
fn test_process_withdraw_ix_bad_rent_state_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(
|
KeyedAccount::new(
|
||||||
@ -1393,7 +1410,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_withdraw_ix_ok() {
|
fn test_process_withdraw_ix_ok() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(
|
KeyedAccount::new(
|
||||||
@ -1418,7 +1435,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_initialize_ix_no_keyed_accs_fail() {
|
fn test_process_initialize_ix_no_keyed_accs_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[],
|
&[],
|
||||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||||
@ -1430,7 +1447,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_initialize_ix_only_nonce_acc_fail() {
|
fn test_process_initialize_ix_only_nonce_acc_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[KeyedAccount::new(
|
&[KeyedAccount::new(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
@ -1446,7 +1463,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_initialize_bad_recent_blockhash_state_fail() {
|
fn test_process_initialize_bad_recent_blockhash_state_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(
|
KeyedAccount::new(
|
||||||
@ -1469,7 +1486,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_initialize_ix_bad_rent_state_fail() {
|
fn test_process_initialize_ix_bad_rent_state_fail() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(
|
KeyedAccount::new(
|
||||||
@ -1493,7 +1510,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_initialize_ix_ok() {
|
fn test_process_initialize_ix_ok() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(
|
KeyedAccount::new(
|
||||||
@ -1517,7 +1534,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_process_authorize_ix_ok() {
|
fn test_process_authorize_ix_ok() {
|
||||||
let nonce_acc = nonce_account::create_account(1_000_000);
|
let nonce_acc = nonce_account::create_account(1_000_000);
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[
|
&[
|
||||||
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
|
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
|
||||||
@ -1532,7 +1549,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
super::process_instruction(
|
process_instruction(
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
&[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),],
|
&[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),],
|
||||||
&serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(),
|
&serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(),
|
||||||
|
@ -46,6 +46,7 @@ generic-array = { version = "0.14.3", default-features = false, features = ["ser
|
|||||||
hex = "0.4.2"
|
hex = "0.4.2"
|
||||||
hmac = "0.7.0"
|
hmac = "0.7.0"
|
||||||
itertools = "0.9.0"
|
itertools = "0.9.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
memmap = { version = "0.7.0", optional = true }
|
memmap = { version = "0.7.0", optional = true }
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
|
@ -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);
|
void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||||
#define sol_log_64 sol_log_64_
|
#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
|
* Size of Public key in bytes
|
||||||
*/
|
*/
|
||||||
|
@ -96,3 +96,19 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) {
|
|||||||
info!("Instruction data");
|
info!("Instruction data");
|
||||||
sol_log_slice(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_();
|
||||||
|
}
|
||||||
|
@ -19,6 +19,9 @@ pub trait SyscallStubs: Sync + Send {
|
|||||||
fn sol_log(&self, message: &str) {
|
fn sol_log(&self, message: &str) {
|
||||||
println!("{}", message);
|
println!("{}", message);
|
||||||
}
|
}
|
||||||
|
fn sol_log_compute_units(&self) {
|
||||||
|
sol_log("SyscallStubs: sol_log_compute_units() not available");
|
||||||
|
}
|
||||||
fn sol_invoke_signed(
|
fn sol_invoke_signed(
|
||||||
&self,
|
&self,
|
||||||
_instruction: &Instruction,
|
_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));
|
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(
|
pub(crate) fn sol_invoke_signed(
|
||||||
instruction: &Instruction,
|
instruction: &Instruction,
|
||||||
account_infos: &[AccountInfo],
|
account_infos: &[AccountInfo],
|
||||||
|
@ -86,15 +86,19 @@ macro_rules! declare_name {
|
|||||||
/// # // wrapper is used so that the macro invocation occurs in the item position
|
/// # // wrapper is used so that the macro invocation occurs in the item position
|
||||||
/// # // rather than in the statement position which isn't allowed.
|
/// # // rather than in the statement position which isn't allowed.
|
||||||
/// # mod item_wrapper {
|
/// # mod item_wrapper {
|
||||||
/// use solana_sdk::keyed_account::KeyedAccount;
|
/// use solana_sdk::{
|
||||||
/// use solana_sdk::instruction::InstructionError;
|
/// declare_program,
|
||||||
/// use solana_sdk::pubkey::Pubkey;
|
/// instruction::InstructionError,
|
||||||
/// use solana_sdk::declare_program;
|
/// keyed_account::KeyedAccount,
|
||||||
|
/// process_instruction::InvokeContext,
|
||||||
|
/// pubkey::Pubkey,
|
||||||
|
/// };
|
||||||
///
|
///
|
||||||
/// fn my_process_instruction(
|
/// fn my_process_instruction(
|
||||||
/// program_id: &Pubkey,
|
/// program_id: &Pubkey,
|
||||||
/// keyed_accounts: &[KeyedAccount],
|
/// keyed_accounts: &[KeyedAccount],
|
||||||
/// instruction_data: &[u8],
|
/// instruction_data: &[u8],
|
||||||
|
/// invoke_context: &mut dyn InvokeContext,
|
||||||
/// ) -> Result<(), InstructionError> {
|
/// ) -> Result<(), InstructionError> {
|
||||||
/// // Process an instruction
|
/// // Process an instruction
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
@ -117,15 +121,19 @@ macro_rules! declare_name {
|
|||||||
/// # // wrapper is used so that the macro invocation occurs in the item position
|
/// # // wrapper is used so that the macro invocation occurs in the item position
|
||||||
/// # // rather than in the statement position which isn't allowed.
|
/// # // rather than in the statement position which isn't allowed.
|
||||||
/// # mod item_wrapper {
|
/// # mod item_wrapper {
|
||||||
/// use solana_sdk::keyed_account::KeyedAccount;
|
/// use solana_sdk::{
|
||||||
/// use solana_sdk::instruction::InstructionError;
|
/// declare_program,
|
||||||
/// use solana_sdk::pubkey::Pubkey;
|
/// instruction::InstructionError,
|
||||||
/// use solana_sdk::declare_program;
|
/// keyed_account::KeyedAccount,
|
||||||
|
/// process_instruction::InvokeContext,
|
||||||
|
/// pubkey::Pubkey,
|
||||||
|
/// };
|
||||||
///
|
///
|
||||||
/// fn my_process_instruction(
|
/// fn my_process_instruction(
|
||||||
/// program_id: &Pubkey,
|
/// program_id: &Pubkey,
|
||||||
/// keyed_accounts: &[KeyedAccount],
|
/// keyed_accounts: &[KeyedAccount],
|
||||||
/// instruction_data: &[u8],
|
/// instruction_data: &[u8],
|
||||||
|
/// invoke_context: &mut dyn InvokeContext,
|
||||||
/// ) -> Result<(), InstructionError> {
|
/// ) -> Result<(), InstructionError> {
|
||||||
/// // Process an instruction
|
/// // Process an instruction
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
@ -152,8 +160,9 @@ macro_rules! declare_program(
|
|||||||
program_id: &$crate::pubkey::Pubkey,
|
program_id: &$crate::pubkey::Pubkey,
|
||||||
keyed_accounts: &[$crate::keyed_account::KeyedAccount],
|
keyed_accounts: &[$crate::keyed_account::KeyedAccount],
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
|
invoke_context: &mut dyn $crate::process_instruction::InvokeContext,
|
||||||
) -> Result<(), $crate::instruction::InstructionError> {
|
) -> Result<(), $crate::instruction::InstructionError> {
|
||||||
$entrypoint(program_id, keyed_accounts, instruction_data)
|
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -34,7 +34,7 @@ pub mod bpf_loader2_program {
|
|||||||
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
|
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod compute_budget_balancing {
|
pub mod bpf_compute_budget_balancing {
|
||||||
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
|
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +66,10 @@ pub mod cumulative_rent_related_fixes {
|
|||||||
solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5");
|
solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod sol_log_compute_units_syscall {
|
||||||
|
solana_sdk::declare_id!("BHuZqHAj7JdZc68wVgZZcy51jZykvgrx4zptR44RyChe");
|
||||||
|
}
|
||||||
|
|
||||||
pub mod pubkey_log_syscall_enabled {
|
pub mod pubkey_log_syscall_enabled {
|
||||||
solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN");
|
solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN");
|
||||||
}
|
}
|
||||||
@ -84,7 +88,7 @@ lazy_static! {
|
|||||||
(inflation_kill_switch::id(), "inflation kill switch"),
|
(inflation_kill_switch::id(), "inflation kill switch"),
|
||||||
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
||||||
(bpf_loader2_program::id(), "bpf_loader2 program"),
|
(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"),
|
(sha256_syscall_enabled::id(), "sha256 syscall"),
|
||||||
(no_overflow_rent_distribution::id(), "no overflow rent distribution"),
|
(no_overflow_rent_distribution::id(), "no overflow rent distribution"),
|
||||||
(ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"),
|
(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"),
|
(max_program_call_depth_64::id(), "max program call depth 64"),
|
||||||
(timestamp_correction::id(), "correct bank timestamps"),
|
(timestamp_correction::id(), "correct bank timestamps"),
|
||||||
(cumulative_rent_related_fixes::id(), "rent fixes (#10206, #10468, #11342)"),
|
(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"),
|
(pubkey_log_syscall_enabled::id(), "pubkey log syscall"),
|
||||||
(pull_request_ping_pong_check::id(), "ping-pong packet check #12794"),
|
(pull_request_ping_pong_check::id(), "ping-pong packet check #12794"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
@ -16,6 +16,8 @@ pub mod entrypoint;
|
|||||||
pub mod entrypoint_deprecated;
|
pub mod entrypoint_deprecated;
|
||||||
pub mod entrypoint_native;
|
pub mod entrypoint_native;
|
||||||
pub mod epoch_info;
|
pub mod epoch_info;
|
||||||
|
pub mod feature;
|
||||||
|
pub mod feature_set;
|
||||||
pub mod genesis_config;
|
pub mod genesis_config;
|
||||||
pub mod hard_forks;
|
pub mod hard_forks;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
@ -27,6 +29,7 @@ pub mod nonce_account;
|
|||||||
pub mod nonce_keyed_account;
|
pub mod nonce_keyed_account;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
pub mod poh_config;
|
pub mod poh_config;
|
||||||
|
pub mod process_instruction;
|
||||||
pub mod program_utils;
|
pub mod program_utils;
|
||||||
pub mod pubkey;
|
pub mod pubkey;
|
||||||
pub mod recent_blockhashes_account;
|
pub mod recent_blockhashes_account;
|
||||||
|
@ -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::{
|
use solana_sdk::{
|
||||||
account::Account,
|
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},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
message::Message,
|
message::Message,
|
||||||
@ -24,24 +24,9 @@ pub type LoaderEntrypoint = unsafe extern "C" fn(
|
|||||||
invoke_context: &dyn InvokeContext,
|
invoke_context: &dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError>;
|
) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
|
||||||
pub type ProcessInstructionWithContext =
|
pub type ProcessInstructionWithContext =
|
||||||
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
|
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
|
/// Invocation context passed to loaders
|
||||||
pub trait InvokeContext {
|
pub trait InvokeContext {
|
||||||
/// Push a program ID on to the invocation stack
|
/// 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
|
/// Get the program ID of the currently executing program
|
||||||
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
||||||
/// Get a list of built-in programs
|
/// Get a list of built-in programs
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)];
|
||||||
/// Get this invocation's logger
|
/// Get this invocation's logger
|
||||||
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
||||||
/// Get this invocation's compute budget
|
/// 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
|
/// Get this invocation's compute meter
|
||||||
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
|
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>>;
|
||||||
/// Loaders may need to do work in order to execute a program. Cache
|
/// 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;
|
fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, AbiExample)]
|
||||||
pub struct ComputeBudget {
|
pub struct BpfComputeBudget {
|
||||||
/// Number of compute units that an instruction is allowed. Compute units
|
/// Number of compute units that an instruction is allowed. Compute units
|
||||||
/// are consumed by program execution, resources they use, etc...
|
/// are consumed by program execution, resources they use, etc...
|
||||||
pub max_units: u64,
|
pub max_units: u64,
|
||||||
@ -103,16 +88,16 @@ pub struct ComputeBudget {
|
|||||||
/// Number of compute units consumed by logging a `Pubkey`
|
/// Number of compute units consumed by logging a `Pubkey`
|
||||||
pub log_pubkey_units: u64,
|
pub log_pubkey_units: u64,
|
||||||
}
|
}
|
||||||
impl Default for ComputeBudget {
|
impl Default for BpfComputeBudget {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(&FeatureSet::all_enabled())
|
Self::new(&FeatureSet::all_enabled())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ComputeBudget {
|
impl BpfComputeBudget {
|
||||||
pub fn new(feature_set: &FeatureSet) -> Self {
|
pub fn new(feature_set: &FeatureSet) -> Self {
|
||||||
let mut compute_budget =
|
let mut bpf_compute_budget =
|
||||||
// Original
|
// Original
|
||||||
ComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: 100_000,
|
max_units: 100_000,
|
||||||
log_units: 0,
|
log_units: 0,
|
||||||
log_64_units: 0,
|
log_64_units: 0,
|
||||||
@ -126,36 +111,36 @@ impl ComputeBudget {
|
|||||||
log_pubkey_units: 0,
|
log_pubkey_units: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if feature_set.is_active(&compute_budget_balancing::id()) {
|
if feature_set.is_active(&bpf_compute_budget_balancing::id()) {
|
||||||
compute_budget = ComputeBudget {
|
bpf_compute_budget = BpfComputeBudget {
|
||||||
max_units: 200_000,
|
max_units: 200_000,
|
||||||
log_units: 100,
|
log_units: 100,
|
||||||
log_64_units: 100,
|
log_64_units: 100,
|
||||||
create_program_address_units: 1500,
|
create_program_address_units: 1500,
|
||||||
invoke_units: 1000,
|
invoke_units: 1000,
|
||||||
..compute_budget
|
..bpf_compute_budget
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if feature_set.is_active(&max_invoke_depth_4::id()) {
|
if feature_set.is_active(&max_invoke_depth_4::id()) {
|
||||||
compute_budget = ComputeBudget {
|
bpf_compute_budget = BpfComputeBudget {
|
||||||
max_invoke_depth: 4,
|
max_invoke_depth: 4,
|
||||||
..compute_budget
|
..bpf_compute_budget
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if feature_set.is_active(&max_program_call_depth_64::id()) {
|
if feature_set.is_active(&max_program_call_depth_64::id()) {
|
||||||
compute_budget = ComputeBudget {
|
bpf_compute_budget = BpfComputeBudget {
|
||||||
max_call_depth: 64,
|
max_call_depth: 64,
|
||||||
..compute_budget
|
..bpf_compute_budget
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if feature_set.is_active(&pubkey_log_syscall_enabled::id()) {
|
if feature_set.is_active(&pubkey_log_syscall_enabled::id()) {
|
||||||
compute_budget = ComputeBudget {
|
bpf_compute_budget = BpfComputeBudget {
|
||||||
log_pubkey_units: 100,
|
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,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError>;
|
) -> 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
|
||||||
|
}
|
||||||
|
}
|
@ -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-frozen-abi-macro = { path = "../frozen-abi/macro", version = "1.4.4" }
|
||||||
solana-logger = { path = "../logger", version = "1.4.4" }
|
solana-logger = { path = "../logger", version = "1.4.4" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.4.4" }
|
solana-sdk = { path = "../sdk", version = "1.4.4" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.4.4" }
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "solana_version"
|
name = "solana_version"
|
||||||
|
@ -51,7 +51,7 @@ fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
|
|||||||
impl Default for Version {
|
impl Default for Version {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let feature_set = u32::from_le_bytes(
|
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()
|
.try_into()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user