diff --git a/soroban-env-host/src/test/invocation.rs b/soroban-env-host/src/test/invocation.rs index 61ce5eeb7..4a83c44fb 100644 --- a/soroban-env-host/src/test/invocation.rs +++ b/soroban-env-host/src/test/invocation.rs @@ -2,7 +2,7 @@ use expect_test::expect; use soroban_env_common::{xdr::ScErrorCode, Env, TryFromVal, Val}; use crate::{events::HostEvent, xdr::ScErrorType, Error, Host, HostError, Symbol, Tag}; -use soroban_test_wasms::{ADD_I32, INVOKE_CONTRACT, VEC}; +use soroban_test_wasms::{ADD_I32, ALLOC, INVOKE_CONTRACT, VEC}; #[test] fn invoke_single_contract_function() -> Result<(), HostError> { @@ -29,6 +29,34 @@ fn invoke_single_contract_function() -> Result<(), HostError> { Ok(()) } +#[test] +fn invoke_alloc() -> Result<(), HostError> { + let host = Host::test_host_with_recording_footprint(); + host.enable_debug()?; + let contract_id_obj = host.register_test_contract_wasm(ALLOC); + let res = host.call( + contract_id_obj, + Symbol::try_from_small_str("sum")?, + host.test_vec_obj::(&[128])?, + )?; + assert!(res.shallow_eq(&8128_u32.into())); + let used_bytes = host.budget_cloned().get_mem_bytes_consumed()?; + // The general pattern of memory growth in this contract will be a sequence + // of vector-doublings, but these are masked by the fact that we only see + // the calls that cause the backing vector of wasm linear memory to grow, + // which happens as the guest vector crosses 64k boundaries (and eventually + // starts growing in steps larger than 64k itself). + // + // So we wind up with a growth-sequence that's a bit irregular: +0x10000, + // +0x20000, +0x30000, +0x50000, +0x90000. Total is 1 + 2 + 3 + 5 + 9 = 20 + // pages or about 1.3 MiB, plus the initial 17 pages (1.1MiB) plus some more + // slop from general host machinery allocations, we get around 2.5MiB. Call + // is "less than 3MiB". + assert!(used_bytes > (128 * 4096)); + assert!(used_bytes < 0x30_0000); + Ok(()) +} + fn invoke_cross_contract(diagnostics: bool) -> Result<(), HostError> { let host = Host::test_host_with_recording_footprint(); if diagnostics { diff --git a/soroban-test-wasms/src/lib.rs b/soroban-test-wasms/src/lib.rs index 11f9cb53a..5c8399fa9 100644 --- a/soroban-test-wasms/src/lib.rs +++ b/soroban-test-wasms/src/lib.rs @@ -44,6 +44,7 @@ pub const ADD_I32: &[u8] = include_bytes!("../wasm-workspace/opt/example_add_i32.wasm").as_slice(); pub const ADD_F32: &[u8] = include_bytes!("../wasm-workspace/opt/example_add_f32.wasm").as_slice(); +pub const ALLOC: &[u8] = include_bytes!("../wasm-workspace/opt/example_alloc.wasm").as_slice(); pub const CREATE_CONTRACT: &[u8] = include_bytes!("../wasm-workspace/opt/example_create_contract.wasm").as_slice(); pub const CONTRACT_STORAGE: &[u8] = diff --git a/soroban-test-wasms/wasm-workspace/Cargo.lock b/soroban-test-wasms/wasm-workspace/Cargo.lock index 7a4a8107e..83c20f0f6 100644 --- a/soroban-test-wasms/wasm-workspace/Cargo.lock +++ b/soroban-test-wasms/wasm-workspace/Cargo.lock @@ -408,6 +408,13 @@ dependencies = [ "soroban-sdk", ] +[[package]] +name = "example_alloc" +version = "0.0.0" +dependencies = [ + "soroban-sdk", +] + [[package]] name = "example_complex" version = "0.0.0" diff --git a/soroban-test-wasms/wasm-workspace/Cargo.toml b/soroban-test-wasms/wasm-workspace/Cargo.toml index a43e70f5d..e8f7ff2c4 100644 --- a/soroban-test-wasms/wasm-workspace/Cargo.toml +++ b/soroban-test-wasms/wasm-workspace/Cargo.toml @@ -19,6 +19,7 @@ resolver = "2" members = [ "add_i32", "add_f32", + "alloc", "auth", "fib", "contract_data", @@ -31,7 +32,7 @@ members = [ "fannkuch", "simple_account", "update", - "delegated_account" + "delegated_account", ] [profile.release] opt-level = "z" diff --git a/soroban-test-wasms/wasm-workspace/alloc/Cargo.toml b/soroban-test-wasms/wasm-workspace/alloc/Cargo.toml new file mode 100644 index 000000000..1b50386fe --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/alloc/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "example_alloc" +version = "0.0.0" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version = "1.65" + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true, features = ["alloc"] } diff --git a/soroban-test-wasms/wasm-workspace/alloc/src/lib.rs b/soroban-test-wasms/wasm-workspace/alloc/src/lib.rs new file mode 100644 index 000000000..89bc1e972 --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/alloc/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env}; + +extern crate alloc; + +#[contract] +pub struct AllocContract; + +struct Large { + x: u32, + space: [u8;4096] +} + +#[contractimpl] +impl AllocContract { + /// Allocates a temporary vector holding values (0..count), then computes + /// and returns their sum. Also allocates these values in a "large" + /// structure (with a bunch of pointless padding) to ensure the contract + /// allocates lots of memory. + pub fn sum(_env: Env, count: u32) -> u32 { + let mut v1 = alloc::vec![]; + for i in 0..count { + v1.push(Large{x: i, space: [0u8; 4096]}) + } + v1.iter().map(|l| l.x + l.space[0] as u32).sum() + } +} diff --git a/soroban-test-wasms/wasm-workspace/opt/example_alloc.wasm b/soroban-test-wasms/wasm-workspace/opt/example_alloc.wasm new file mode 100644 index 000000000..75e55bd4f Binary files /dev/null and b/soroban-test-wasms/wasm-workspace/opt/example_alloc.wasm differ