Add adjustable stack size and call depth (#12728)
This commit is contained in:
parent
16d45b8480
commit
c3907be623
|
@ -4790,9 +4790,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.1.31"
|
version = "0.1.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "962f8f04ac7239fe4dd45fa4ce706ec78b59a0da9f41def463832857e36c60b0"
|
checksum = "9a95dbe2b00920ac4e1524b7442cf5319f01e8fa5742930ac60148882fd7738b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -1798,6 +1798,13 @@ dependencies = [
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "solana-bpf-rust-call-depth"
|
||||||
|
version = "1.4.0"
|
||||||
|
dependencies = [
|
||||||
|
"solana-sdk",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-bpf-rust-custom-heap"
|
name = "solana-bpf-rust-custom-heap"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -2191,9 +2198,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.1.31"
|
version = "0.1.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "962f8f04ac7239fe4dd45fa4ce706ec78b59a0da9f41def463832857e36c60b0"
|
checksum = "9a95dbe2b00920ac4e1524b7442cf5319f01e8fa5742930ac60148882fd7738b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -27,7 +27,7 @@ solana-logger = { path = "../../logger", version = "1.5.0" }
|
||||||
solana-measure = { path = "../../measure", version = "1.5.0" }
|
solana-measure = { path = "../../measure", version = "1.5.0" }
|
||||||
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
||||||
solana_rbpf = "=0.1.31"
|
solana_rbpf = "=0.1.32"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "bpf_loader"
|
name = "bpf_loader"
|
||||||
|
@ -57,6 +57,7 @@ members = [
|
||||||
"rust/ristretto",
|
"rust/ristretto",
|
||||||
"rust/sanity",
|
"rust/sanity",
|
||||||
"rust/sha256",
|
"rust/sha256",
|
||||||
|
"rust/call_depth",
|
||||||
"rust/sysval",
|
"rust/sysval",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ fn main() {
|
||||||
"ristretto",
|
"ristretto",
|
||||||
"sanity",
|
"sanity",
|
||||||
"sha256",
|
"sha256",
|
||||||
|
"call_depth",
|
||||||
"sysval",
|
"sysval",
|
||||||
];
|
];
|
||||||
for program in rust_programs.iter() {
|
for program in rust_programs.iter() {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
# Note: This crate must be built using do.sh
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "solana-bpf-rust-call-depth"
|
||||||
|
version = "1.4.0"
|
||||||
|
description = "Solana BPF test program written in Rust"
|
||||||
|
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||||
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
homepage = "https://solana.com/"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
solana-sdk = { path = "../../../../sdk/", version = "1.4.0", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
program = ["solana-sdk/program"]
|
||||||
|
default = ["program", "solana-sdk/default"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "solana_bpf_rust_call_depth"
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
|
@ -0,0 +1,2 @@
|
||||||
|
[target.bpfel-unknown-unknown.dependencies.std]
|
||||||
|
features = []
|
|
@ -0,0 +1,27 @@
|
||||||
|
//! @brief Example Rust-based BPF program that tests call depth and stack usage
|
||||||
|
|
||||||
|
use solana_sdk::{entrypoint::SUCCESS, info};
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn recurse(data: &mut [u8]) {
|
||||||
|
if data.len() <= 1 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recurse(&mut data[1..]);
|
||||||
|
info!(line!(), 0, 0, 0, data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[inline(never)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
|
||||||
|
info!("Call depth");
|
||||||
|
let depth = *(input.add(16) as *mut u8);
|
||||||
|
info!(line!(), 0, 0, 0, depth);
|
||||||
|
let mut data = Vec::with_capacity(depth as usize);
|
||||||
|
for i in 0_u8..depth {
|
||||||
|
data.push(i);
|
||||||
|
}
|
||||||
|
recurse(&mut data);
|
||||||
|
SUCCESS
|
||||||
|
}
|
|
@ -643,6 +643,43 @@ fn test_program_bpf_invoke() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bpf_rust")]
|
||||||
|
#[test]
|
||||||
|
fn test_program_bpf_call_depth() {
|
||||||
|
solana_logger::setup();
|
||||||
|
|
||||||
|
println!("Test program: solana_bpf_rust_call_depth");
|
||||||
|
|
||||||
|
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,
|
||||||
|
&bpf_loader::id(),
|
||||||
|
&mint_keypair,
|
||||||
|
"solana_bpf_rust_call_depth",
|
||||||
|
);
|
||||||
|
|
||||||
|
let instruction = Instruction::new(
|
||||||
|
program_id,
|
||||||
|
&(ComputeBudget::default().max_call_depth - 1),
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
let instruction =
|
||||||
|
Instruction::new(program_id, &ComputeBudget::default().max_call_depth, vec![]);
|
||||||
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_instruction_count() {
|
fn assert_instruction_count() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
|
@ -16,7 +16,7 @@ num-derive = "0.3"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
||||||
solana_rbpf = "=0.1.31"
|
solana_rbpf = "=0.1.32"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -14,7 +14,7 @@ use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use solana_rbpf::{
|
use solana_rbpf::{
|
||||||
error::{EbpfError, UserDefinedError},
|
error::{EbpfError, UserDefinedError},
|
||||||
memory_region::MemoryRegion,
|
memory_region::MemoryRegion,
|
||||||
vm::{EbpfVm, Executable, InstructionMeter},
|
vm::{Config, EbpfVm, Executable, InstructionMeter},
|
||||||
};
|
};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
feature_set::compute_budget_balancing,
|
feature_set::compute_budget_balancing,
|
||||||
|
@ -116,7 +116,14 @@ 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 mut vm = EbpfVm::new(executable)?;
|
let compute_budget = invoke_context.get_compute_budget();
|
||||||
|
let mut vm = EbpfVm::new(
|
||||||
|
executable,
|
||||||
|
Config {
|
||||||
|
max_call_depth: compute_budget.max_call_depth,
|
||||||
|
stack_frame_size: compute_budget.stack_frame_size,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
let heap_region =
|
let heap_region =
|
||||||
syscalls::register_syscalls(loader_id, &mut vm, parameter_accounts, invoke_context)?;
|
syscalls::register_syscalls(loader_id, &mut vm, parameter_accounts, invoke_context)?;
|
||||||
Ok((vm, heap_region))
|
Ok((vm, heap_region))
|
||||||
|
@ -404,7 +411,7 @@ mod tests {
|
||||||
let input = &mut [0x00];
|
let input = &mut [0x00];
|
||||||
|
|
||||||
let executable = EbpfVm::create_executable_from_text_bytes(program, None).unwrap();
|
let executable = EbpfVm::create_executable_from_text_bytes(program, None).unwrap();
|
||||||
let mut vm = EbpfVm::<BPFError>::new(executable.as_ref()).unwrap();
|
let mut vm = EbpfVm::<BPFError>::new(executable.as_ref(), Config::default()).unwrap();
|
||||||
let instruction_meter = TestInstructionMeter { remaining: 10 };
|
let instruction_meter = TestInstructionMeter { remaining: 10 };
|
||||||
vm.execute_program_metered(input, &[], &[], instruction_meter)
|
vm.execute_program_metered(input, &[], &[], instruction_meter)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -603,6 +610,8 @@ mod tests {
|
||||||
max_invoke_depth: 2,
|
max_invoke_depth: 2,
|
||||||
sha256_base_cost: 85,
|
sha256_base_cost: 85,
|
||||||
sha256_byte_cost: 1,
|
sha256_byte_cost: 1,
|
||||||
|
max_call_depth: 20,
|
||||||
|
stack_frame_size: 4096,
|
||||||
},
|
},
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
Rc::new(RefCell::new(Executors::default())),
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -53,6 +53,10 @@ pub mod max_invoke_depth_4 {
|
||||||
solana_sdk::declare_id!("EdM9xggY5y7AhNMskRG8NgGMnaP4JFNsWi8ZZtyT1af5");
|
solana_sdk::declare_id!("EdM9xggY5y7AhNMskRG8NgGMnaP4JFNsWi8ZZtyT1af5");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod max_program_call_depth_64 {
|
||||||
|
solana_sdk::declare_id!("YCKSgA6XmjtkQrHBQjpyNrX6EMhJPcYcLWMVgWn36iv");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||||
|
@ -68,6 +72,7 @@ lazy_static! {
|
||||||
(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"),
|
||||||
(max_invoke_depth_4::id(), "max invoke call depth 4"),
|
(max_invoke_depth_4::id(), "max invoke call depth 4"),
|
||||||
|
(max_program_call_depth_64::id(), "max program call depth 64")
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::feature_set::{compute_budget_balancing, max_invoke_depth_4, FeatureSet};
|
use crate::feature_set::{
|
||||||
|
compute_budget_balancing, max_invoke_depth_4, max_program_call_depth_64, FeatureSet,
|
||||||
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{Account, KeyedAccount},
|
account::{Account, KeyedAccount},
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
|
@ -92,6 +94,10 @@ pub struct ComputeBudget {
|
||||||
pub sha256_base_cost: u64,
|
pub sha256_base_cost: u64,
|
||||||
/// Incremental number of units consumed by sha256 (based on bytes)
|
/// Incremental number of units consumed by sha256 (based on bytes)
|
||||||
pub sha256_byte_cost: u64,
|
pub sha256_byte_cost: u64,
|
||||||
|
/// Maximum BPF to BPF call depth
|
||||||
|
pub max_call_depth: usize,
|
||||||
|
/// Size of a stack frame in bytes, must match the size specified in the LLVM BPF backend
|
||||||
|
pub stack_frame_size: usize,
|
||||||
}
|
}
|
||||||
impl Default for ComputeBudget {
|
impl Default for ComputeBudget {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -111,6 +117,8 @@ impl ComputeBudget {
|
||||||
max_invoke_depth: 1,
|
max_invoke_depth: 1,
|
||||||
sha256_base_cost: 85,
|
sha256_base_cost: 85,
|
||||||
sha256_byte_cost: 1,
|
sha256_byte_cost: 1,
|
||||||
|
max_call_depth: 20,
|
||||||
|
stack_frame_size: 4_096,
|
||||||
};
|
};
|
||||||
|
|
||||||
if feature_set.is_active(&compute_budget_balancing::id()) {
|
if feature_set.is_active(&compute_budget_balancing::id()) {
|
||||||
|
@ -127,9 +135,15 @@ impl ComputeBudget {
|
||||||
compute_budget = ComputeBudget {
|
compute_budget = ComputeBudget {
|
||||||
max_invoke_depth: 4,
|
max_invoke_depth: 4,
|
||||||
..compute_budget
|
..compute_budget
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if feature_set.is_active(&max_program_call_depth_64::id()) {
|
||||||
|
compute_budget = ComputeBudget {
|
||||||
|
max_call_depth: 64,
|
||||||
|
..compute_budget
|
||||||
|
};
|
||||||
|
}
|
||||||
compute_budget
|
compute_budget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue