Make BPF Loader static (#11516)
This commit is contained in:
parent
346e982e28
commit
7c736f71fe
|
@ -3378,7 +3378,6 @@ version = "1.4.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"byteorder",
|
||||
"jemalloc-sys",
|
||||
"num-derive 0.3.0",
|
||||
"num-traits",
|
||||
"rand 0.7.3",
|
||||
|
@ -3556,7 +3555,6 @@ dependencies = [
|
|||
"serial_test_derive",
|
||||
"solana-account-decoder",
|
||||
"solana-banks-server",
|
||||
"solana-bpf-loader-program",
|
||||
"solana-clap-utils",
|
||||
"solana-client",
|
||||
"solana-faucet",
|
||||
|
|
|
@ -45,7 +45,6 @@ serde_derive = "1.0.103"
|
|||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.4.0" }
|
||||
solana-banks-server = { path = "../banks-server", version = "1.4.0" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.4.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.0" }
|
||||
solana-client = { path = "../client", version = "1.4.0" }
|
||||
solana-faucet = { path = "../faucet", version = "1.4.0" }
|
||||
|
|
|
@ -72,9 +72,6 @@ pub mod vote_stake_tracker;
|
|||
pub mod weighted_shuffle;
|
||||
pub mod window_service;
|
||||
|
||||
#[macro_use]
|
||||
extern crate solana_bpf_loader_program;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
|
|
|
@ -868,13 +868,6 @@ impl TestValidator {
|
|||
42,
|
||||
bootstrap_validator_lamports,
|
||||
);
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_program!());
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_deprecated_program!());
|
||||
|
||||
genesis_config.rent.lamports_per_byte_year = 1;
|
||||
genesis_config.rent.exemption_threshold = 1.0;
|
||||
genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0);
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
use solana_sdk::{
|
||||
clock::Epoch, genesis_config::OperatingMode, inflation::Inflation, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
extern crate solana_bpf_loader_program;
|
||||
#[macro_use]
|
||||
|
@ -13,6 +9,10 @@ extern crate solana_vest_program;
|
|||
|
||||
use log::*;
|
||||
use solana_runtime::bank::{Bank, EnteredEpochCallback};
|
||||
use solana_sdk::{
|
||||
clock::Epoch, entrypoint_native::ProcessInstructionWithContext, genesis_config::OperatingMode,
|
||||
inflation::Inflation, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option<Inflation> {
|
||||
match operating_mode {
|
||||
|
@ -44,22 +44,27 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option<Infl
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(String, Pubkey)>> {
|
||||
enum Program {
|
||||
Native((String, Pubkey)),
|
||||
BuiltinLoader((String, Pubkey, ProcessInstructionWithContext)),
|
||||
}
|
||||
|
||||
fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<Program>> {
|
||||
match operating_mode {
|
||||
OperatingMode::Development => {
|
||||
if epoch == 0 {
|
||||
// Programs used for testing
|
||||
Some(vec![
|
||||
solana_bpf_loader_program!(),
|
||||
solana_bpf_loader_deprecated_program!(),
|
||||
solana_vest_program!(),
|
||||
solana_budget_program!(),
|
||||
solana_exchange_program!(),
|
||||
Program::BuiltinLoader(solana_bpf_loader_program!()),
|
||||
Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()),
|
||||
Program::Native(solana_vest_program!()),
|
||||
Program::Native(solana_budget_program!()),
|
||||
Program::Native(solana_exchange_program!()),
|
||||
])
|
||||
} else if epoch == std::u64::MAX {
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
Some(vec![solana_bpf_loader_program!()])
|
||||
Some(vec![Program::BuiltinLoader(solana_bpf_loader_program!())])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -68,7 +73,10 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
|
|||
if epoch == std::u64::MAX {
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
Some(vec![solana_bpf_loader_program!(), solana_vest_program!()])
|
||||
Some(vec![
|
||||
Program::BuiltinLoader(solana_bpf_loader_program!()),
|
||||
Program::Native(solana_vest_program!()),
|
||||
])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -77,7 +85,10 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
|
|||
if epoch == std::u64::MAX {
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
Some(vec![solana_bpf_loader_program!(), solana_vest_program!()])
|
||||
Some(vec![
|
||||
Program::BuiltinLoader(solana_bpf_loader_program!()),
|
||||
Program::Native(solana_vest_program!()),
|
||||
])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -85,21 +96,48 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_native_programs(
|
||||
operating_mode: OperatingMode,
|
||||
epoch: Epoch,
|
||||
) -> Option<Vec<(String, Pubkey)>> {
|
||||
match get_programs(operating_mode, epoch) {
|
||||
Some(programs) => {
|
||||
let mut native_programs = vec![];
|
||||
for program in programs {
|
||||
if let Program::Native((string, key)) = program {
|
||||
native_programs.push((string, key));
|
||||
}
|
||||
}
|
||||
Some(native_programs)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpochCallback {
|
||||
Box::new(move |bank: &mut Bank| {
|
||||
info!(
|
||||
"Entering epoch {} with operating_mode {:?}",
|
||||
bank.epoch(),
|
||||
operating_mode
|
||||
);
|
||||
if let Some(inflation) = get_inflation(operating_mode, bank.epoch()) {
|
||||
info!("Entering new epoch with inflation {:?}", inflation);
|
||||
bank.set_inflation(inflation);
|
||||
}
|
||||
if let Some(new_programs) = get_programs(operating_mode, bank.epoch()) {
|
||||
for (name, program_id) in new_programs.iter() {
|
||||
info!("Registering {} at {}", name, program_id);
|
||||
bank.add_native_program(name, program_id);
|
||||
if let Some(programs) = get_programs(operating_mode, bank.epoch()) {
|
||||
for program in programs {
|
||||
match program {
|
||||
Program::Native((name, program_id)) => {
|
||||
bank.add_native_program(&name, &program_id);
|
||||
}
|
||||
Program::BuiltinLoader((
|
||||
name,
|
||||
program_id,
|
||||
process_instruction_with_context,
|
||||
)) => {
|
||||
bank.add_builtin_loader(
|
||||
&name,
|
||||
program_id,
|
||||
process_instruction_with_context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if OperatingMode::Stable == operating_mode {
|
||||
|
@ -118,8 +156,13 @@ mod tests {
|
|||
#[test]
|
||||
fn test_id_uniqueness() {
|
||||
let mut unique = HashSet::new();
|
||||
let ids = get_programs(OperatingMode::Development, 0).unwrap();
|
||||
assert!(ids.into_iter().all(move |id| unique.insert(id)));
|
||||
let programs = get_programs(OperatingMode::Development, 0).unwrap();
|
||||
for program in programs {
|
||||
match program {
|
||||
Program::Native((name, id)) => assert!(unique.insert((name, id))),
|
||||
Program::BuiltinLoader((name, id, _)) => assert!(unique.insert((name, id))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -137,7 +180,18 @@ mod tests {
|
|||
get_programs(OperatingMode::Development, 0).unwrap().len(),
|
||||
5
|
||||
);
|
||||
assert_eq!(get_programs(OperatingMode::Development, 1), None);
|
||||
assert!(get_programs(OperatingMode::Development, 1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_native_development_programs() {
|
||||
assert_eq!(
|
||||
get_native_programs(OperatingMode::Development, 0)
|
||||
.unwrap()
|
||||
.len(),
|
||||
3
|
||||
);
|
||||
assert!(get_native_programs(OperatingMode::Development, 1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -155,7 +209,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_softlaunch_programs() {
|
||||
assert_eq!(get_programs(OperatingMode::Stable, 1), None);
|
||||
assert!(get_programs(OperatingMode::Stable, 1).is_none());
|
||||
assert!(get_programs(OperatingMode::Stable, std::u64::MAX).is_some());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -468,7 +468,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
);
|
||||
|
||||
let native_instruction_processors =
|
||||
solana_genesis_programs::get_programs(operating_mode, 0).unwrap_or_else(Vec::new);
|
||||
solana_genesis_programs::get_native_programs(operating_mode, 0).unwrap_or_else(Vec::new);
|
||||
let inflation = solana_genesis_programs::get_inflation(operating_mode, 0).unwrap();
|
||||
|
||||
let mut genesis_config = GenesisConfig {
|
||||
|
|
|
@ -323,11 +323,11 @@ pub fn process_blockstore(
|
|||
}
|
||||
|
||||
// Setup bank for slot 0
|
||||
let bank0 = Arc::new(Bank::new_with_paths(
|
||||
&genesis_config,
|
||||
account_paths,
|
||||
&opts.frozen_accounts,
|
||||
));
|
||||
let mut bank0 = Bank::new_with_paths(&genesis_config, account_paths, &opts.frozen_accounts);
|
||||
let callback =
|
||||
solana_genesis_programs::get_entered_epoch_callback(genesis_config.operating_mode);
|
||||
callback(&mut bank0);
|
||||
let bank0 = Arc::new(bank0);
|
||||
info!("processing ledger for slot 0...");
|
||||
let recyclers = VerifyRecyclers::default();
|
||||
process_bank_0(&bank0, blockstore, &opts, &recyclers)?;
|
||||
|
|
|
@ -171,7 +171,7 @@ impl LocalCluster {
|
|||
match genesis_config.operating_mode {
|
||||
OperatingMode::Stable | OperatingMode::Preview => {
|
||||
genesis_config.native_instruction_processors =
|
||||
solana_genesis_programs::get_programs(genesis_config.operating_mode, 0)
|
||||
solana_genesis_programs::get_native_programs(genesis_config.operating_mode, 0)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
_ => (),
|
||||
|
|
|
@ -1616,7 +1616,6 @@ version = "1.4.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"byteorder 1.3.4",
|
||||
"jemalloc-sys",
|
||||
"num-derive 0.3.0",
|
||||
"num-traits",
|
||||
"solana-runtime",
|
||||
|
|
|
@ -1,394 +1,413 @@
|
|||
#![cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate solana_bpf_loader_program;
|
||||
|
||||
use solana_runtime::{
|
||||
bank::Bank,
|
||||
bank_client::BankClient,
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
loader_utils::load_program,
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
bpf_loader,
|
||||
client::SyncClient,
|
||||
clock::DEFAULT_SLOTS_PER_EPOCH,
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::Keypair,
|
||||
signature::Signer,
|
||||
sysvar::{clock, fees, rent, rewards, slot_hashes, stake_history},
|
||||
transaction::TransactionError,
|
||||
};
|
||||
use std::{env, fs::File, io::Read, path::PathBuf, sync::Arc};
|
||||
|
||||
/// BPF program file extension
|
||||
const PLATFORM_FILE_EXTENSION_BPF: &str = "so";
|
||||
|
||||
/// Create a BPF program file name
|
||||
fn create_bpf_path(name: &str) -> PathBuf {
|
||||
let mut pathbuf = {
|
||||
let current_exe = env::current_exe().unwrap();
|
||||
PathBuf::from(current_exe.parent().unwrap().parent().unwrap())
|
||||
};
|
||||
pathbuf.push("bpf/");
|
||||
pathbuf.push(name);
|
||||
pathbuf.set_extension(PLATFORM_FILE_EXTENSION_BPF);
|
||||
pathbuf
|
||||
}
|
||||
|
||||
fn load_bpf_program(bank_client: &BankClient, payer_keypair: &Keypair, name: &str) -> Pubkey {
|
||||
let path = create_bpf_path(name);
|
||||
let mut file = File::open(path).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
load_program(bank_client, payer_keypair, &bpf_loader::id(), elf)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
|
||||
mod bpf {
|
||||
use solana_bpf_loader_program::solana_bpf_loader_program;
|
||||
use solana_runtime::{
|
||||
bank::Bank,
|
||||
bank_client::BankClient,
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
loader_utils::load_program,
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
bpf_loader,
|
||||
client::SyncClient,
|
||||
clock::DEFAULT_SLOTS_PER_EPOCH,
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::Keypair,
|
||||
signature::Signer,
|
||||
sysvar::{clock, fees, rent, rewards, slot_hashes, stake_history},
|
||||
transaction::TransactionError,
|
||||
};
|
||||
use std::{env, fs::File, io::Read, path::PathBuf, sync::Arc};
|
||||
fn test_program_bpf_sanity() {
|
||||
solana_logger::setup();
|
||||
|
||||
/// BPF program file extension
|
||||
const PLATFORM_FILE_EXTENSION_BPF: &str = "so";
|
||||
|
||||
/// Create a BPF program file name
|
||||
fn create_bpf_path(name: &str) -> PathBuf {
|
||||
let mut pathbuf = {
|
||||
let current_exe = env::current_exe().unwrap();
|
||||
PathBuf::from(current_exe.parent().unwrap().parent().unwrap())
|
||||
};
|
||||
pathbuf.push("bpf/");
|
||||
pathbuf.push(name);
|
||||
pathbuf.set_extension(PLATFORM_FILE_EXTENSION_BPF);
|
||||
pathbuf
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[
|
||||
("bpf_to_bpf", true),
|
||||
("multiple_static", true),
|
||||
("noop", true),
|
||||
("noop++", true),
|
||||
("panic", false),
|
||||
("relative_call", true),
|
||||
("struct_pass", true),
|
||||
("struct_ret", true),
|
||||
]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[
|
||||
("solana_bpf_rust_128bit", true),
|
||||
("solana_bpf_rust_alloc", true),
|
||||
("solana_bpf_rust_dep_crate", true),
|
||||
("solana_bpf_rust_external_spend", false),
|
||||
("solana_bpf_rust_iter", true),
|
||||
("solana_bpf_rust_many_args", true),
|
||||
("solana_bpf_rust_noop", true),
|
||||
("solana_bpf_rust_panic", false),
|
||||
("solana_bpf_rust_param_passing", true),
|
||||
("solana_bpf_rust_sysval", true),
|
||||
]);
|
||||
}
|
||||
|
||||
fn load_bpf_program(bank_client: &BankClient, payer_keypair: &Keypair, name: &str) -> Pubkey {
|
||||
let path = create_bpf_path(name);
|
||||
let mut file = File::open(path).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
load_program(bank_client, payer_keypair, &bpf_loader::id(), elf)
|
||||
}
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program.0);
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
|
||||
fn test_program_bpf_sanity() {
|
||||
solana_logger::setup();
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
||||
bank.add_builtin_loader(&name, id, entrypoint);
|
||||
let bank = Arc::new(bank);
|
||||
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[
|
||||
("bpf_to_bpf", true),
|
||||
("multiple_static", true),
|
||||
("noop", true),
|
||||
("noop++", true),
|
||||
("panic", false),
|
||||
("relative_call", true),
|
||||
("struct_pass", true),
|
||||
("struct_ret", true),
|
||||
]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[
|
||||
("solana_bpf_rust_128bit", true),
|
||||
("solana_bpf_rust_alloc", true),
|
||||
("solana_bpf_rust_dep_crate", true),
|
||||
("solana_bpf_rust_external_spend", false),
|
||||
("solana_bpf_rust_iter", true),
|
||||
("solana_bpf_rust_many_args", true),
|
||||
("solana_bpf_rust_noop", true),
|
||||
("solana_bpf_rust_panic", false),
|
||||
("solana_bpf_rust_param_passing", true),
|
||||
("solana_bpf_rust_sysval", true),
|
||||
]);
|
||||
}
|
||||
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test
|
||||
let bank = Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program.0);
|
||||
|
||||
let GenesisConfigInfo {
|
||||
mut genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_program!());
|
||||
let bank = Arc::new(Bank::new(&genesis_config));
|
||||
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test
|
||||
let bank =
|
||||
Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
||||
// Call user program
|
||||
let program_id = load_bpf_program(&bank_client, &mint_keypair, program.0);
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(mint_keypair.pubkey(), true),
|
||||
AccountMeta::new(Keypair::new().pubkey(), false),
|
||||
AccountMeta::new(clock::id(), false),
|
||||
AccountMeta::new(fees::id(), false),
|
||||
AccountMeta::new(rewards::id(), false),
|
||||
AccountMeta::new(slot_hashes::id(), false),
|
||||
AccountMeta::new(stake_history::id(), false),
|
||||
AccountMeta::new(rent::id(), false),
|
||||
];
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas);
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
if program.1 {
|
||||
assert!(result.is_ok());
|
||||
} else {
|
||||
assert!(result.is_err());
|
||||
}
|
||||
// Call user program
|
||||
let program_id = load_bpf_program(&bank_client, &mint_keypair, program.0);
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(mint_keypair.pubkey(), true),
|
||||
AccountMeta::new(Keypair::new().pubkey(), false),
|
||||
AccountMeta::new(clock::id(), false),
|
||||
AccountMeta::new(fees::id(), false),
|
||||
AccountMeta::new(rewards::id(), false),
|
||||
AccountMeta::new(slot_hashes::id(), false),
|
||||
AccountMeta::new(stake_history::id(), false),
|
||||
AccountMeta::new(rent::id(), false),
|
||||
];
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas);
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
if program.1 {
|
||||
assert!(result.is_ok());
|
||||
} else {
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_program_bpf_duplicate_accounts() {
|
||||
solana_logger::setup();
|
||||
#[test]
|
||||
fn test_program_bpf_duplicate_accounts() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[("dup_accounts")]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_dup_accounts")]);
|
||||
}
|
||||
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
|
||||
let GenesisConfigInfo {
|
||||
mut genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_program!());
|
||||
let bank = Arc::new(Bank::new(&genesis_config));
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
let program_id = load_bpf_program(&bank_client, &mint_keypair, program);
|
||||
let payee_account = Account::new(10, 1, &program_id);
|
||||
let payee_pubkey = Pubkey::new_rand();
|
||||
bank.store_account(&payee_pubkey, &payee_account);
|
||||
|
||||
let account = Account::new(10, 1, &program_id);
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(mint_keypair.pubkey(), true),
|
||||
AccountMeta::new(payee_pubkey, false),
|
||||
AccountMeta::new(pubkey, false),
|
||||
AccountMeta::new(pubkey, false),
|
||||
];
|
||||
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(data[0], 1);
|
||||
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(data[0], 2);
|
||||
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(data[0], 3);
|
||||
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let lamports = bank_client.get_balance(&pubkey).unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lamports, 11);
|
||||
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let lamports = bank_client.get_balance(&pubkey).unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lamports, 12);
|
||||
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let lamports = bank_client.get_balance(&pubkey).unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lamports, 13);
|
||||
}
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[("dup_accounts")]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_dup_accounts")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_program_bpf_error_handling() {
|
||||
solana_logger::setup();
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[("error_handling")]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_error_handling")]);
|
||||
}
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
||||
bank.add_builtin_loader(&name, id, entrypoint);
|
||||
let bank = Arc::new(bank);
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
let program_id = load_bpf_program(&bank_client, &mint_keypair, program);
|
||||
let payee_account = Account::new(10, 1, &program_id);
|
||||
let payee_pubkey = Pubkey::new_rand();
|
||||
bank.store_account(&payee_pubkey, &payee_account);
|
||||
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
let account = Account::new(10, 1, &program_id);
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(mint_keypair.pubkey(), true),
|
||||
AccountMeta::new(payee_pubkey, false),
|
||||
AccountMeta::new(pubkey, false),
|
||||
AccountMeta::new(pubkey, false),
|
||||
];
|
||||
|
||||
let GenesisConfigInfo {
|
||||
mut genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_program!());
|
||||
let bank = Bank::new(&genesis_config);
|
||||
let bank_client = BankClient::new(bank);
|
||||
let program_id = load_bpf_program(&bank_client, &mint_keypair, program);
|
||||
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(data[0], 1);
|
||||
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert!(result.is_ok());
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(data[0], 2);
|
||||
|
||||
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
|
||||
);
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(data[0], 3);
|
||||
|
||||
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(0))
|
||||
);
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let lamports = bank_client.get_balance(&pubkey).unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lamports, 11);
|
||||
|
||||
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(42))
|
||||
);
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let lamports = bank_client.get_balance(&pubkey).unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lamports, 12);
|
||||
|
||||
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let result = result.unwrap_err().unwrap();
|
||||
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
||||
!= result
|
||||
{
|
||||
assert_eq!(
|
||||
result,
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidError)
|
||||
);
|
||||
}
|
||||
bank.store_account(&pubkey, &account);
|
||||
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let lamports = bank_client.get_balance(&pubkey).unwrap();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(lamports, 13);
|
||||
}
|
||||
}
|
||||
|
||||
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let result = result.unwrap_err().unwrap();
|
||||
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
||||
!= result
|
||||
{
|
||||
assert_eq!(
|
||||
result,
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidError)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_program_bpf_error_handling() {
|
||||
solana_logger::setup();
|
||||
|
||||
let instruction = Instruction::new(program_id, &7u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let result = result.unwrap_err().unwrap();
|
||||
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
||||
!= result
|
||||
{
|
||||
assert_eq!(
|
||||
result,
|
||||
TransactionError::InstructionError(0, InstructionError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
|
||||
let instruction = Instruction::new(program_id, &8u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
||||
);
|
||||
|
||||
let instruction = Instruction::new(program_id, &9u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded)
|
||||
);
|
||||
}
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[("error_handling")]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_error_handling")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_program_bpf_invoke() {
|
||||
solana_logger::setup();
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
|
||||
const TEST_SUCCESS: u8 = 1;
|
||||
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
|
||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
||||
bank.add_builtin_loader(&name, id, entrypoint);
|
||||
let bank_client = BankClient::new(bank);
|
||||
let program_id = load_bpf_program(&bank_client, &mint_keypair, program);
|
||||
let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
|
||||
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let instruction = Instruction::new(program_id, &2u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
|
||||
);
|
||||
|
||||
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(0))
|
||||
);
|
||||
|
||||
let instruction = Instruction::new(program_id, &4u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(42))
|
||||
);
|
||||
|
||||
let instruction = Instruction::new(program_id, &5u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let result = result.unwrap_err().unwrap();
|
||||
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
|
||||
{
|
||||
programs.extend_from_slice(&[("invoke", "invoked")]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_invoke", "solana_bpf_rust_invoked")]);
|
||||
}
|
||||
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
|
||||
let GenesisConfigInfo {
|
||||
mut genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
genesis_config
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_program!());
|
||||
let bank = Arc::new(Bank::new(&genesis_config));
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
let invoke_program_id = load_bpf_program(&bank_client, &mint_keypair, program.0);
|
||||
let invoked_program_id = load_bpf_program(&bank_client, &mint_keypair, program.1);
|
||||
|
||||
let argument_keypair = Keypair::new();
|
||||
let account = Account::new(41, 100, &invoke_program_id);
|
||||
bank.store_account(&argument_keypair.pubkey(), &account);
|
||||
|
||||
let invoked_argument_keypair = Keypair::new();
|
||||
let account = Account::new(10, 10, &invoked_program_id);
|
||||
bank.store_account(&invoked_argument_keypair.pubkey(), &account);
|
||||
|
||||
let from_keypair = Keypair::new();
|
||||
let account = Account::new(43, 0, &solana_sdk::system_program::id());
|
||||
bank.store_account(&from_keypair.pubkey(), &account);
|
||||
|
||||
let (derived_key1, nonce1) =
|
||||
Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id);
|
||||
let (derived_key2, nonce2) =
|
||||
Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoked_program_id);
|
||||
let (derived_key3, nonce3) =
|
||||
Pubkey::find_program_address(&[derived_key2.as_ref()], &invoked_program_id);
|
||||
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(mint_pubkey, true),
|
||||
AccountMeta::new(argument_keypair.pubkey(), true),
|
||||
AccountMeta::new_readonly(invoked_program_id, false),
|
||||
AccountMeta::new(invoked_argument_keypair.pubkey(), true),
|
||||
AccountMeta::new_readonly(invoked_program_id, false),
|
||||
AccountMeta::new(argument_keypair.pubkey(), true),
|
||||
AccountMeta::new(derived_key1, false),
|
||||
AccountMeta::new(derived_key2, false),
|
||||
AccountMeta::new_readonly(derived_key3, false),
|
||||
AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
|
||||
AccountMeta::new(from_keypair.pubkey(), true),
|
||||
];
|
||||
|
||||
// success cases
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&[TEST_SUCCESS, nonce1, nonce2, nonce3],
|
||||
account_metas.clone(),
|
||||
assert_eq!(
|
||||
result,
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidError)
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
assert!(bank_client
|
||||
}
|
||||
|
||||
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let result = result.unwrap_err().unwrap();
|
||||
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
|
||||
{
|
||||
assert_eq!(
|
||||
result,
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidError)
|
||||
);
|
||||
}
|
||||
|
||||
let instruction = Instruction::new(program_id, &7u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
let result = result.unwrap_err().unwrap();
|
||||
if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
|
||||
{
|
||||
assert_eq!(
|
||||
result,
|
||||
TransactionError::InstructionError(0, InstructionError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
|
||||
let instruction = Instruction::new(program_id, &8u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
||||
);
|
||||
|
||||
let instruction = Instruction::new(program_id, &9u8, account_metas.clone());
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_program_bpf_invoke() {
|
||||
solana_logger::setup();
|
||||
|
||||
const TEST_SUCCESS: u8 = 1;
|
||||
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
|
||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
||||
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[("invoke", "invoked")]);
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_invoke", "solana_bpf_rust_invoked")]);
|
||||
}
|
||||
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
||||
bank.add_builtin_loader(&name, id, entrypoint);
|
||||
let bank = Arc::new(bank);
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
let invoke_program_id = load_bpf_program(&bank_client, &mint_keypair, program.0);
|
||||
let invoked_program_id = load_bpf_program(&bank_client, &mint_keypair, program.1);
|
||||
|
||||
let argument_keypair = Keypair::new();
|
||||
let account = Account::new(41, 100, &invoke_program_id);
|
||||
bank.store_account(&argument_keypair.pubkey(), &account);
|
||||
|
||||
let invoked_argument_keypair = Keypair::new();
|
||||
let account = Account::new(10, 10, &invoked_program_id);
|
||||
bank.store_account(&invoked_argument_keypair.pubkey(), &account);
|
||||
|
||||
let from_keypair = Keypair::new();
|
||||
let account = Account::new(43, 0, &solana_sdk::system_program::id());
|
||||
bank.store_account(&from_keypair.pubkey(), &account);
|
||||
|
||||
let (derived_key1, nonce1) =
|
||||
Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id);
|
||||
let (derived_key2, nonce2) =
|
||||
Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoked_program_id);
|
||||
let (derived_key3, nonce3) =
|
||||
Pubkey::find_program_address(&[derived_key2.as_ref()], &invoked_program_id);
|
||||
|
||||
let mint_pubkey = mint_keypair.pubkey();
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(mint_pubkey, true),
|
||||
AccountMeta::new(argument_keypair.pubkey(), true),
|
||||
AccountMeta::new_readonly(invoked_program_id, false),
|
||||
AccountMeta::new(invoked_argument_keypair.pubkey(), true),
|
||||
AccountMeta::new_readonly(invoked_program_id, false),
|
||||
AccountMeta::new(argument_keypair.pubkey(), true),
|
||||
AccountMeta::new(derived_key1, false),
|
||||
AccountMeta::new(derived_key2, false),
|
||||
AccountMeta::new_readonly(derived_key3, false),
|
||||
AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
|
||||
AccountMeta::new(from_keypair.pubkey(), true),
|
||||
];
|
||||
|
||||
// success cases
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&[TEST_SUCCESS, nonce1, nonce2, nonce3],
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
assert!(bank_client
|
||||
.send_and_confirm_message(
|
||||
&[
|
||||
&mint_keypair,
|
||||
&argument_keypair,
|
||||
&invoked_argument_keypair,
|
||||
&from_keypair
|
||||
],
|
||||
message,
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
// failure cases
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&TEST_PRIVILEGE_ESCALATION_SIGNER,
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
assert_eq!(
|
||||
bank_client
|
||||
.send_and_confirm_message(
|
||||
&[
|
||||
&mint_keypair,
|
||||
|
@ -398,53 +417,31 @@ mod bpf {
|
|||
],
|
||||
message,
|
||||
)
|
||||
.is_ok());
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
|
||||
);
|
||||
|
||||
// failure cases
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&TEST_PRIVILEGE_ESCALATION_SIGNER,
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
assert_eq!(
|
||||
bank_client
|
||||
.send_and_confirm_message(
|
||||
&[
|
||||
&mint_keypair,
|
||||
&argument_keypair,
|
||||
&invoked_argument_keypair,
|
||||
&from_keypair
|
||||
],
|
||||
message,
|
||||
)
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
|
||||
);
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&TEST_PRIVILEGE_ESCALATION_WRITABLE,
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
assert_eq!(
|
||||
bank_client
|
||||
.send_and_confirm_message(
|
||||
&[
|
||||
&mint_keypair,
|
||||
&argument_keypair,
|
||||
&invoked_argument_keypair,
|
||||
&from_keypair
|
||||
],
|
||||
message,
|
||||
)
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
|
||||
);
|
||||
}
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&TEST_PRIVILEGE_ESCALATION_WRITABLE,
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
assert_eq!(
|
||||
bank_client
|
||||
.send_and_confirm_message(
|
||||
&[
|
||||
&mint_keypair,
|
||||
&argument_keypair,
|
||||
&invoked_argument_keypair,
|
||||
&from_keypair
|
||||
],
|
||||
message,
|
||||
)
|
||||
.unwrap_err()
|
||||
.unwrap(),
|
||||
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ edition = "2018"
|
|||
[dependencies]
|
||||
bincode = "1.3.1"
|
||||
byteorder = "1.3.4"
|
||||
jemalloc-sys = { version = "0.3.2", features = ["disable_initial_exec_tls"] }
|
||||
num-derive = { version = "0.3" }
|
||||
num-traits = { version = "0.2" }
|
||||
solana-runtime = { path = "../../runtime", version = "1.4.0" }
|
||||
|
@ -24,7 +23,7 @@ rand = "0.7.3"
|
|||
rustversion = "1.0.3"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
crate-type = ["lib"]
|
||||
name = "solana_bpf_loader_program"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use crate::process_instruction;
|
||||
|
||||
solana_sdk::declare_loader!(
|
||||
solana_sdk::declare_builtin!(
|
||||
solana_sdk::bpf_loader_deprecated::ID,
|
||||
solana_bpf_loader_deprecated_program,
|
||||
process_instruction,
|
||||
solana_bpf_loader_program,
|
||||
solana_bpf_loader_program::process_instruction,
|
||||
deprecated::id
|
||||
);
|
||||
|
|
|
@ -29,11 +29,10 @@ use solana_sdk::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
|
||||
solana_sdk::declare_loader!(
|
||||
solana_sdk::declare_builtin!(
|
||||
solana_sdk::bpf_loader::ID,
|
||||
solana_bpf_loader_program,
|
||||
process_instruction,
|
||||
solana_bpf_loader_program
|
||||
solana_bpf_loader_program::process_instruction
|
||||
);
|
||||
|
||||
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
|
||||
|
@ -280,15 +279,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[rustversion::since(1.46.0)]
|
||||
#[test]
|
||||
fn test_bpf_loader_same_crate() {
|
||||
// Ensure that we can invoke this macro from the same crate
|
||||
// where it is defined.
|
||||
solana_bpf_loader_program!();
|
||||
solana_bpf_loader_deprecated_program!();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "ExceededMaxInstructions(10)")]
|
||||
fn test_bpf_loader_non_terminating_program() {
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
accounts_db::{ErrorCounters, SnapshotStorages},
|
||||
accounts_index::Ancestors,
|
||||
blockhash_queue::BlockhashQueue,
|
||||
builtin_programs::{get_builtin_programs, get_epoch_activated_builtin_programs},
|
||||
builtins::{get_builtins, get_epoch_activated_builtins},
|
||||
epoch_stakes::{EpochStakes, NodeVoteAccounts},
|
||||
log_collector::LogCollector,
|
||||
message_processor::MessageProcessor,
|
||||
|
@ -35,7 +35,7 @@ use solana_sdk::{
|
|||
Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND,
|
||||
MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY,
|
||||
},
|
||||
entrypoint_native::ProcessInstruction,
|
||||
entrypoint_native::{ProcessInstruction, ProcessInstructionWithContext},
|
||||
epoch_info::EpochInfo,
|
||||
epoch_schedule::EpochSchedule,
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
|
@ -98,6 +98,26 @@ type RentCollectionCycleParams = (
|
|||
|
||||
type EpochCount = u64;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Entrypoint {
|
||||
Program(ProcessInstruction),
|
||||
Loader(ProcessInstructionWithContext),
|
||||
}
|
||||
pub struct Builtin {
|
||||
pub name: String,
|
||||
pub id: Pubkey,
|
||||
pub entrypoint: Entrypoint,
|
||||
}
|
||||
impl Builtin {
|
||||
pub fn new(name: &str, id: Pubkey, entrypoint: Entrypoint) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
id,
|
||||
entrypoint,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BankRc {
|
||||
/// where all the Accounts are stored
|
||||
|
@ -544,11 +564,9 @@ impl Bank {
|
|||
entered_epoch_callback(&mut new)
|
||||
}
|
||||
|
||||
if let Some(builtin_programs) =
|
||||
get_epoch_activated_builtin_programs(new.operating_mode(), new.epoch)
|
||||
{
|
||||
for program in builtin_programs.iter() {
|
||||
new.add_builtin_program(&program.name, program.id, program.process_instruction);
|
||||
if let Some(builtins) = get_epoch_activated_builtins(new.operating_mode(), new.epoch) {
|
||||
for program in builtins.iter() {
|
||||
new.add_builtin(&program.name, program.id, program.entrypoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2575,9 +2593,9 @@ impl Bank {
|
|||
}
|
||||
|
||||
pub fn finish_init(&mut self) {
|
||||
let builtin_programs = get_builtin_programs(self.operating_mode(), self.epoch);
|
||||
for program in builtin_programs.iter() {
|
||||
self.add_builtin_program(&program.name, program.id, program.process_instruction);
|
||||
let builtins = get_builtins();
|
||||
for program in builtins.iter() {
|
||||
self.add_builtin(&program.name, program.id, program.entrypoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3021,19 +3039,36 @@ impl Bank {
|
|||
!self.is_delta.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Add an instruction processor to intercept instructions before the dynamic loader.
|
||||
pub fn add_builtin_program(
|
||||
&mut self,
|
||||
name: &str,
|
||||
program_id: Pubkey,
|
||||
process_instruction: ProcessInstruction,
|
||||
) {
|
||||
self.add_builtin(name, program_id, Entrypoint::Program(process_instruction));
|
||||
}
|
||||
|
||||
pub fn add_builtin_loader(
|
||||
&mut self,
|
||||
name: &str,
|
||||
program_id: Pubkey,
|
||||
process_instruction_with_context: ProcessInstructionWithContext,
|
||||
) {
|
||||
self.add_builtin(
|
||||
name,
|
||||
program_id,
|
||||
Entrypoint::Loader(process_instruction_with_context),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add an instruction processor to intercept instructions before the dynamic loader.
|
||||
pub fn add_builtin(&mut self, name: &str, program_id: Pubkey, entrypoint: Entrypoint) {
|
||||
match self.get_account(&program_id) {
|
||||
Some(account) => {
|
||||
assert_eq!(
|
||||
account.owner,
|
||||
native_loader::id(),
|
||||
"Cannot overwrite non-native loader account"
|
||||
"Cannot overwrite non-native account"
|
||||
);
|
||||
}
|
||||
None => {
|
||||
|
@ -3042,9 +3077,18 @@ impl Bank {
|
|||
self.store_account(&program_id, &account);
|
||||
}
|
||||
}
|
||||
self.message_processor
|
||||
.add_program(program_id, process_instruction);
|
||||
debug!("Added static program {} under {:?}", name, program_id);
|
||||
match entrypoint {
|
||||
Entrypoint::Program(process_instruction) => {
|
||||
self.message_processor
|
||||
.add_program(program_id, process_instruction);
|
||||
debug!("Added builtin program {} under {:?}", name, program_id);
|
||||
}
|
||||
Entrypoint::Loader(process_instruction_with_context) => {
|
||||
self.message_processor
|
||||
.add_loader(program_id, process_instruction_with_context);
|
||||
debug!("Added builtin loader {} under {:?}", name, program_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compare_bank(&self, dbank: &Bank) {
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
use crate::system_instruction_processor;
|
||||
use solana_sdk::{
|
||||
clock::Epoch, entrypoint_native::ProcessInstruction, genesis_config::OperatingMode,
|
||||
pubkey::Pubkey, system_program,
|
||||
};
|
||||
|
||||
pub struct BuiltinProgram {
|
||||
pub name: String,
|
||||
pub id: Pubkey,
|
||||
pub process_instruction: ProcessInstruction,
|
||||
}
|
||||
impl BuiltinProgram {
|
||||
pub fn new(name: &str, id: Pubkey, process_instruction: ProcessInstruction) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
id,
|
||||
process_instruction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All builtin programs that should be active at the given (operating_mode, epoch)
|
||||
pub fn get_builtin_programs(_operating_mode: OperatingMode, _epoch: Epoch) -> Vec<BuiltinProgram> {
|
||||
vec![
|
||||
BuiltinProgram::new(
|
||||
"system_program",
|
||||
system_program::id(),
|
||||
system_instruction_processor::process_instruction,
|
||||
),
|
||||
BuiltinProgram::new(
|
||||
"config_program",
|
||||
solana_config_program::id(),
|
||||
solana_config_program::config_processor::process_instruction,
|
||||
),
|
||||
BuiltinProgram::new(
|
||||
"stake_program",
|
||||
solana_stake_program::id(),
|
||||
solana_stake_program::stake_instruction::process_instruction,
|
||||
),
|
||||
BuiltinProgram::new(
|
||||
"vote_program",
|
||||
solana_vote_program::id(),
|
||||
solana_vote_program::vote_instruction::process_instruction,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Builtin programs that activate at the given (operating_mode, epoch)
|
||||
pub fn get_epoch_activated_builtin_programs(
|
||||
_operating_mode: OperatingMode,
|
||||
_epoch: Epoch,
|
||||
) -> Option<Vec<BuiltinProgram>> {
|
||||
None
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
use crate::{
|
||||
bank::{Builtin, Entrypoint},
|
||||
system_instruction_processor,
|
||||
};
|
||||
use solana_sdk::{clock::Epoch, genesis_config::OperatingMode, system_program};
|
||||
|
||||
/// All builtin programs that should be active at the given (operating_mode, epoch)
|
||||
pub fn get_builtins() -> Vec<Builtin> {
|
||||
vec![
|
||||
Builtin::new(
|
||||
"system_program",
|
||||
system_program::id(),
|
||||
Entrypoint::Program(system_instruction_processor::process_instruction),
|
||||
),
|
||||
Builtin::new(
|
||||
"config_program",
|
||||
solana_config_program::id(),
|
||||
Entrypoint::Program(solana_config_program::config_processor::process_instruction),
|
||||
),
|
||||
Builtin::new(
|
||||
"stake_program",
|
||||
solana_stake_program::id(),
|
||||
Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction),
|
||||
),
|
||||
Builtin::new(
|
||||
"vote_program",
|
||||
solana_vote_program::id(),
|
||||
Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Builtin programs that activate at the given (operating_mode, epoch)
|
||||
pub fn get_epoch_activated_builtins(
|
||||
_operating_mode: OperatingMode,
|
||||
_epoch: Epoch,
|
||||
) -> Option<Vec<Builtin>> {
|
||||
None
|
||||
}
|
|
@ -9,7 +9,7 @@ pub mod bank_forks;
|
|||
pub mod bank_utils;
|
||||
mod blockhash_queue;
|
||||
pub mod bloom;
|
||||
pub mod builtin_programs;
|
||||
pub mod builtins;
|
||||
pub mod commitment;
|
||||
pub mod epoch_stakes;
|
||||
pub mod genesis_utils;
|
||||
|
|
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||
use solana_sdk::{
|
||||
account::{create_keyed_readonly_accounts, Account, KeyedAccount},
|
||||
clock::Epoch,
|
||||
entrypoint_native::{InvokeContext, Logger, ProcessInstruction},
|
||||
entrypoint_native::{InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext},
|
||||
instruction::{CompiledInstruction, InstructionError},
|
||||
message::Message,
|
||||
native_loader,
|
||||
|
@ -247,9 +247,6 @@ impl Logger for ThisLogger {
|
|||
}
|
||||
}
|
||||
|
||||
pub type ProcessInstructionWithContext =
|
||||
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct MessageProcessor {
|
||||
#[serde(skip)]
|
||||
|
@ -353,6 +350,17 @@ impl MessageProcessor {
|
|||
) -> Result<(), InstructionError> {
|
||||
if native_loader::check_id(&keyed_accounts[0].owner()?) {
|
||||
let root_id = keyed_accounts[0].unsigned_key();
|
||||
for (id, process_instruction) in &self.loaders {
|
||||
if id == root_id {
|
||||
// Call the program via a builtin loader
|
||||
return process_instruction(
|
||||
&root_id,
|
||||
&keyed_accounts[1..],
|
||||
instruction_data,
|
||||
invoke_context,
|
||||
);
|
||||
}
|
||||
}
|
||||
for (id, process_instruction) in &self.programs {
|
||||
if id == root_id {
|
||||
// Call the builtin program
|
||||
|
@ -367,9 +375,9 @@ impl MessageProcessor {
|
|||
invoke_context,
|
||||
);
|
||||
} else {
|
||||
let owner_id = keyed_accounts[0].owner()?;
|
||||
let owner_id = &keyed_accounts[0].owner()?;
|
||||
for (id, process_instruction) in &self.loaders {
|
||||
if *id == owner_id {
|
||||
if id == owner_id {
|
||||
// Call the program via a builtin loader
|
||||
return process_instruction(
|
||||
&owner_id,
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
//! @brief Solana builtin helper macros
|
||||
|
||||
#[rustversion::since(1.46.0)]
|
||||
#[macro_export]
|
||||
macro_rules! declare_builtin_name {
|
||||
($name:ident, $id:path, $entrypoint:expr) => {
|
||||
#[macro_export]
|
||||
macro_rules! $name {
|
||||
() => {
|
||||
// Subtle:
|
||||
// The outer `declare_builtin_name!` macro may be expanded in another
|
||||
// crate, causing the macro `$name!` to be defined in that
|
||||
// crate. We want to emit a call to `$crate::id()`, and have
|
||||
// `$crate` be resolved in the crate where `$name!` gets defined,
|
||||
// *not* in this crate (where `declare_builtin_name! is defined).
|
||||
//
|
||||
// When a macro_rules! macro gets expanded, any $crate tokens
|
||||
// in its output will be 'marked' with the crate they were expanded
|
||||
// from. This includes nested macros like our macro `$name` - even
|
||||
// though it looks like a separate macro, Rust considers it to be
|
||||
// just another part of the output of `declare_program!`.
|
||||
//
|
||||
// We pass `$name` as the second argument to tell `respan!` to
|
||||
// apply use the `Span` of `$name` when resolving `$crate::id`.
|
||||
// This causes `$crate` to behave as though it was written
|
||||
// at the same location as the `$name` value passed
|
||||
// to `declare_builtin_name!` (e.g. the 'foo' in
|
||||
// `declare_builtin_name(foo)`
|
||||
//
|
||||
// See the `respan!` macro for more details.
|
||||
// This should use `crate::respan!` once
|
||||
// https://github.com/rust-lang/rust/pull/72121 is merged:
|
||||
// see https://github.com/solana-labs/solana/issues/10933.
|
||||
// For now, we need to use `::solana_sdk`
|
||||
//
|
||||
// `respan!` respans the path `$crate::id`, which we then call (hence the extra
|
||||
// parens)
|
||||
(
|
||||
stringify!($name).to_string(),
|
||||
::solana_sdk::respan!($crate::$id, $name)(),
|
||||
$entrypoint,
|
||||
)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[rustversion::not(since(1.46.0))]
|
||||
#[macro_export]
|
||||
macro_rules! declare_builtin_name {
|
||||
($name:ident, $id:path, $entrypoint:expr) => {
|
||||
#[macro_export]
|
||||
macro_rules! $name {
|
||||
() => {
|
||||
(stringify!($name).to_string(), $crate::$id(), $entrypoint)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Convenience macro to declare a builtin
|
||||
///
|
||||
/// bs58_string: bs58 string representation the program's id
|
||||
/// name: Name of the program
|
||||
/// entrypoint: Program's entrypoint, must be of `type Entrypoint`
|
||||
/// id: Path to the program id access function, used if this macro is not
|
||||
/// called in `src/lib`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::str::FromStr;
|
||||
/// // wrapper is used so that the macro invocation occurs in the item position
|
||||
/// // rather than in the statement position which isn't allowed.
|
||||
/// mod item_wrapper {
|
||||
/// use solana_sdk::account::KeyedAccount;
|
||||
/// use solana_sdk::instruction::InstructionError;
|
||||
/// use solana_sdk::pubkey::Pubkey;
|
||||
/// use solana_sdk::declare_builtin;
|
||||
///
|
||||
/// fn my_process_instruction(
|
||||
/// program_id: &Pubkey,
|
||||
/// keyed_accounts: &[KeyedAccount],
|
||||
/// instruction_data: &[u8],
|
||||
/// ) -> Result<(), InstructionError> {
|
||||
/// // Process an instruction
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// declare_builtin!(
|
||||
/// "My11111111111111111111111111111111111111111",
|
||||
/// solana_my_program,
|
||||
/// my_process_instruction
|
||||
/// );
|
||||
///
|
||||
/// # }
|
||||
/// # use solana_sdk::pubkey::Pubkey;
|
||||
/// # use item_wrapper::id;
|
||||
/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
|
||||
/// assert_eq!(id(), my_id);
|
||||
/// ```
|
||||
/// ```
|
||||
/// use std::str::FromStr;
|
||||
/// # // wrapper is used so that the macro invocation occurs in the item position
|
||||
/// # // rather than in the statement position which isn't allowed.
|
||||
/// # mod item_wrapper {
|
||||
/// use solana_sdk::account::KeyedAccount;
|
||||
/// use solana_sdk::instruction::InstructionError;
|
||||
/// use solana_sdk::pubkey::Pubkey;
|
||||
/// use solana_sdk::declare_builtin;
|
||||
///
|
||||
/// fn my_process_instruction(
|
||||
/// program_id: &Pubkey,
|
||||
/// keyed_accounts: &[KeyedAccount],
|
||||
/// instruction_data: &[u8],
|
||||
/// ) -> Result<(), InstructionError> {
|
||||
/// // Process an instruction
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// declare_builtin!(
|
||||
/// solana_sdk::system_program::ID,
|
||||
/// solana_my_program,
|
||||
/// my_process_instruction
|
||||
/// );
|
||||
/// }
|
||||
///
|
||||
/// # use item_wrapper::id;
|
||||
/// assert_eq!(id(), solana_sdk::system_program::ID);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! declare_builtin {
|
||||
($bs58_string:expr, $name:ident, $entrypoint:expr) => {
|
||||
$crate::declare_builtin!($bs58_string, $name, $entrypoint, id);
|
||||
};
|
||||
($bs58_string:expr, $name:ident, $entrypoint:expr, $id:path) => {
|
||||
$crate::declare_id!($bs58_string);
|
||||
$crate::declare_builtin_name!($name, $id, $entrypoint);
|
||||
};
|
||||
}
|
|
@ -93,7 +93,8 @@ macro_rules! declare_name {
|
|||
/// name: Name of the program
|
||||
/// filename: must match the library name in Cargo.toml
|
||||
/// entrypoint: Program's entrypoint, must be of `type Entrypoint`
|
||||
/// id: Path to the program id access function, used if not called in `src/lib`
|
||||
/// id: Path to the program id access function, used if this macro is not
|
||||
/// called in `src/lib`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -174,32 +175,9 @@ macro_rules! declare_program(
|
|||
)
|
||||
);
|
||||
|
||||
/// Same as declare_program but for native loaders
|
||||
#[macro_export]
|
||||
macro_rules! declare_loader {
|
||||
($bs58_string:expr, $name:ident, $entrypoint:expr) => {
|
||||
$crate::declare_loader!($bs58_string, $name, $entrypoint, $name, id);
|
||||
};
|
||||
($bs58_string:expr, $name:ident, $entrypoint:expr, $filename:ident) => {
|
||||
$crate::declare_loader!($bs58_string, $name, $entrypoint, $filename, id);
|
||||
};
|
||||
($bs58_string:expr, $name:ident, $entrypoint:expr, $filename:ident, $id:path) => {
|
||||
$crate::declare_id!($bs58_string);
|
||||
$crate::declare_name!($name, $filename, $id);
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn $name(
|
||||
program_id: &$crate::pubkey::Pubkey,
|
||||
keyed_accounts: &[$crate::account::KeyedAccount],
|
||||
instruction_data: &[u8],
|
||||
invoke_context: &mut dyn $crate::entrypoint_native::InvokeContext,
|
||||
) -> Result<(), $crate::instruction::InstructionError> {
|
||||
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
||||
pub type ProcessInstructionWithContext =
|
||||
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
|
||||
|
||||
/// Invocation context passed to loaders
|
||||
pub trait InvokeContext {
|
||||
|
|
|
@ -13,6 +13,7 @@ pub mod account;
|
|||
pub mod account_utils;
|
||||
pub mod bpf_loader;
|
||||
pub mod bpf_loader_deprecated;
|
||||
pub mod builtins;
|
||||
pub mod clock;
|
||||
pub mod commitment_config;
|
||||
pub mod decode_error;
|
||||
|
|
Loading…
Reference in New Issue