* Add adjustable stack size and call depth (#12728)
(cherry picked from commit c3907be623)
# Conflicts:
#	programs/bpf/Cargo.lock
#	programs/bpf/Cargo.toml
#	programs/bpf/build.rs
#	programs/bpf_loader/Cargo.toml
#	programs/bpf_loader/src/lib.rs
#	runtime/src/feature_set.rs
#	runtime/src/process_instruction.rs
* resolve conflicts
Co-authored-by: Jack May <jack@solana.com>
			
			
This commit is contained in:
		
							
								
								
									
										11
									
								
								programs/bpf/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								programs/bpf/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -1784,6 +1784,13 @@ dependencies = [
 | 
			
		||||
 "solana-sdk",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "solana-bpf-rust-call-depth"
 | 
			
		||||
version = "1.3.16"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "solana-sdk",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "solana-bpf-rust-dep-crate"
 | 
			
		||||
version = "1.3.16"
 | 
			
		||||
@@ -2145,9 +2152,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "solana_rbpf"
 | 
			
		||||
version = "0.1.31"
 | 
			
		||||
version = "0.1.32"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "962f8f04ac7239fe4dd45fa4ce706ec78b59a0da9f41def463832857e36c60b0"
 | 
			
		||||
checksum = "9a95dbe2b00920ac4e1524b7442cf5319f01e8fa5742930ac60148882fd7738b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "byteorder 1.3.4",
 | 
			
		||||
 "combine",
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ solana-logger = { path = "../../logger", version = "1.3.16" }
 | 
			
		||||
solana-measure = { path = "../../measure", version = "1.3.16" }
 | 
			
		||||
solana-runtime = { path = "../../runtime", version = "1.3.16" }
 | 
			
		||||
solana-sdk = { path = "../../sdk", version = "1.3.16" }
 | 
			
		||||
solana_rbpf = "=0.1.31"
 | 
			
		||||
solana_rbpf = "=0.1.32"
 | 
			
		||||
 | 
			
		||||
[[bench]]
 | 
			
		||||
name = "bpf_loader"
 | 
			
		||||
@@ -37,6 +37,7 @@ members = [
 | 
			
		||||
    "rust/128bit",
 | 
			
		||||
    "rust/128bit_dep",
 | 
			
		||||
    "rust/alloc",
 | 
			
		||||
    "rust/call_depth",
 | 
			
		||||
    "rust/dep_crate",
 | 
			
		||||
    "rust/deprecated_loader",
 | 
			
		||||
    "rust/dup_accounts",
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,7 @@ fn main() {
 | 
			
		||||
        let rust_programs = [
 | 
			
		||||
            "128bit",
 | 
			
		||||
            "alloc",
 | 
			
		||||
            "call_depth",
 | 
			
		||||
            "dep_crate",
 | 
			
		||||
            "deprecated_loader",
 | 
			
		||||
            "dup_accounts",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								programs/bpf/rust/call_depth/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								programs/bpf/rust/call_depth/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
 | 
			
		||||
# Note: This crate must be built using do.sh
 | 
			
		||||
 | 
			
		||||
[package]
 | 
			
		||||
name = "solana-bpf-rust-call-depth"
 | 
			
		||||
version = "1.3.16"
 | 
			
		||||
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.3.16", 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"]
 | 
			
		||||
							
								
								
									
										2
									
								
								programs/bpf/rust/call_depth/Xargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								programs/bpf/rust/call_depth/Xargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
[target.bpfel-unknown-unknown.dependencies.std]
 | 
			
		||||
features = []
 | 
			
		||||
							
								
								
									
										27
									
								
								programs/bpf/rust/call_depth/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								programs/bpf/rust/call_depth/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
}
 | 
			
		||||
@@ -638,6 +638,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]
 | 
			
		||||
fn assert_instruction_count() {
 | 
			
		||||
    solana_logger::setup();
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ num-derive = "0.3"
 | 
			
		||||
num-traits = "0.2"
 | 
			
		||||
solana-runtime = { path = "../../runtime", version = "1.3.16" }
 | 
			
		||||
solana-sdk = { path = "../../sdk", version = "1.3.16" }
 | 
			
		||||
solana_rbpf = "=0.1.31"
 | 
			
		||||
solana_rbpf = "=0.1.32"
 | 
			
		||||
thiserror = "1.0"
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ use num_derive::{FromPrimitive, ToPrimitive};
 | 
			
		||||
use solana_rbpf::{
 | 
			
		||||
    error::{EbpfError, UserDefinedError},
 | 
			
		||||
    memory_region::MemoryRegion,
 | 
			
		||||
    vm::{EbpfVm, Executable, InstructionMeter},
 | 
			
		||||
    vm::{Config, EbpfVm, Executable, InstructionMeter},
 | 
			
		||||
};
 | 
			
		||||
use solana_runtime::{
 | 
			
		||||
    feature_set::compute_budget_balancing,
 | 
			
		||||
@@ -116,7 +116,14 @@ pub fn create_vm<'a>(
 | 
			
		||||
    parameter_accounts: &'a [KeyedAccount<'a>],
 | 
			
		||||
    invoke_context: &'a mut dyn InvokeContext,
 | 
			
		||||
) -> 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 =
 | 
			
		||||
        syscalls::register_syscalls(loader_id, &mut vm, parameter_accounts, invoke_context)?;
 | 
			
		||||
    Ok((vm, heap_region))
 | 
			
		||||
@@ -404,7 +411,7 @@ mod tests {
 | 
			
		||||
        let input = &mut [0x00];
 | 
			
		||||
 | 
			
		||||
        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 };
 | 
			
		||||
        vm.execute_program_metered(input, &[], &[], instruction_meter)
 | 
			
		||||
            .unwrap();
 | 
			
		||||
@@ -601,6 +608,8 @@ mod tests {
 | 
			
		||||
                create_program_address_units: 1500,
 | 
			
		||||
                invoke_units: 1000,
 | 
			
		||||
                max_invoke_depth: 2,
 | 
			
		||||
                max_call_depth: 20,
 | 
			
		||||
                stack_frame_size: 4096,
 | 
			
		||||
            },
 | 
			
		||||
            Rc::new(RefCell::new(Executors::default())),
 | 
			
		||||
            None,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user