Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changelog/unreleased/bug-fixes/4729-fix-wasm-alloc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Allow to execute WASM with a tx payload that doesn't fit into the initial WASM
memory. ([\#4729](https://github.com/anoma/namada/pull/4729))
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Always allocate for the initial data to allow to execute larger WASMs
([\#4786](https://github.com/anoma/namada/pull/4786))
7 changes: 3 additions & 4 deletions crates/vm/src/host_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ where
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?;
consume_tx_gas::<MEM, D, H, CA>(env, gas)?;

tracing::debug!("tx_update {}, {:?}", key, value);
tracing::debug!("tx_update {}", key);

let key = Key::parse(key)?;
if key.is_validity_predicate().is_some() {
Expand Down Expand Up @@ -955,7 +955,7 @@ where
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?;
consume_tx_gas::<MEM, D, H, CA>(env, gas)?;

tracing::debug!("tx_write_temp {}, {:?}", key, value);
tracing::debug!("tx_write_temp {}", key);

let key = Key::parse(key)?;

Expand Down Expand Up @@ -1144,10 +1144,9 @@ where
let state = env.state();
let value = vp_host_fns::read_pre(gas_meter, &state, &key)?;
tracing::debug!(
"vp_read_pre addr {}, key {}, value {:?}",
"vp_read_pre addr {}, key {}",
unsafe { env.ctx.address.get() },
key,
value,
);
Ok(match value {
Some(value) => {
Expand Down
47 changes: 37 additions & 10 deletions crates/vm/src/wasm/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub enum Error {
Arith(#[from] arith::Error),
#[error("{0}")]
TryFromInt(#[from] std::num::TryFromIntError),
#[error("Failed to allocate memory: {0}")]
GuestAlloc(wasmer::RuntimeError),
}

/// Result of a function that may fail
Expand All @@ -65,11 +67,11 @@ impl From<Error> for namada_state::Error {
/// Initial pages in tx memory
pub const TX_MEMORY_INIT_PAGES: u32 = 100; // 6.4 MiB
/// Mamixmum pages in tx memory
pub const TX_MEMORY_MAX_PAGES: u32 = 200; // 12.8 MiB
pub const TX_MEMORY_MAX_PAGES: u32 = 400; // 25.6 MiB
/// Initial pages in VP memory
pub const VP_MEMORY_INIT_PAGES: u32 = 100; // 6.4 MiB
pub const VP_MEMORY_INIT_PAGES: u32 = TX_MEMORY_INIT_PAGES; // 6.4 MiB
/// Mamixmum pages in VP memory
pub const VP_MEMORY_MAX_PAGES: u32 = 200; // 12.8 MiB
pub const VP_MEMORY_MAX_PAGES: u32 = TX_MEMORY_MAX_PAGES; // 25.6 MiB

/// Prepare memory for instantiating a transaction module
pub fn prepare_tx_memory(
Expand Down Expand Up @@ -107,15 +109,16 @@ pub struct TxCallInput {

/// Write transaction inputs into wasm memory
pub fn write_tx_inputs(
instance: &wasmer::Instance,
store: &mut impl wasmer::AsStoreMut,
memory: &wasmer::Memory,
tx_data: &BatchedTxRef<'_>,
) -> Result<TxCallInput> {
let tx_data_ptr = 0;
let tx_data_bytes = tx_data.serialize_to_vec();
let tx_data_len = tx_data_bytes.len() as _;
let tx_data_len = tx_data_bytes.len() as u64;
let tx_data_ptr = wasm_alloc(instance, store, tx_data_len)?;

write_memory_bytes(store, memory, tx_data_ptr, tx_data_bytes)?;
write_memory_bytes(store, memory, tx_data_ptr, &tx_data_bytes)?;

Ok(TxCallInput {
tx_data_ptr,
Expand Down Expand Up @@ -146,6 +149,7 @@ pub struct VpCallInput {

/// Write validity predicate inputs into wasm memory
pub fn write_vp_inputs(
instance: &wasmer::Instance,
store: &mut impl wasmer::AsStoreMut,
memory: &wasmer::Memory,
VpInput {
Expand All @@ -155,20 +159,16 @@ pub fn write_vp_inputs(
verifiers,
}: VpInput<'_>,
) -> Result<VpCallInput> {
let addr_ptr = 0_u64;
let addr_bytes = addr.serialize_to_vec();
let addr_len = addr_bytes.len() as _;

let data_bytes = data.serialize_to_vec();
let data_ptr = checked!(addr_ptr + addr_len)?;
let data_len = data_bytes.len() as _;

let keys_changed_bytes = keys_changed.serialize_to_vec();
let keys_changed_ptr = checked!(data_ptr + data_len)?;
let keys_changed_len = keys_changed_bytes.len() as _;

let verifiers_bytes = verifiers.serialize_to_vec();
let verifiers_ptr = checked!(keys_changed_ptr + keys_changed_len)?;
let verifiers_len = verifiers_bytes.len() as _;

let bytes = [
Expand All @@ -178,6 +178,13 @@ pub fn write_vp_inputs(
&verifiers_bytes[..],
]
.concat();
let bytes_len = bytes.len() as u64;

let addr_ptr = wasm_alloc(instance, store, bytes_len)?;
let data_ptr = checked!(addr_ptr + addr_len)?;
let keys_changed_ptr = checked!(data_ptr + data_len)?;
let verifiers_ptr = checked!(keys_changed_ptr + keys_changed_len)?;

write_memory_bytes(store, memory, addr_ptr, bytes)?;

Ok(VpCallInput {
Expand All @@ -192,6 +199,26 @@ pub fn write_vp_inputs(
})
}

/// Allocated inside the wasm instance using the injected function and return a
/// ptr to it
fn wasm_alloc(
instance: &wasmer::Instance,
store: &mut impl wasmer::AsStoreMut,
len: u64,
) -> Result<u64> {
let alloc_fn = instance
.exports
.get_function(super::run::ALLOC_FN_NAME)
.unwrap()
.typed::<i32, i32>(&*store)
.unwrap();

let len: i32 = len.try_into().map_err(Error::TryFromInt)?;
let ptr = alloc_fn.call(&mut *store, len).map_err(Error::GuestAlloc)?;
let ptr: u64 = ptr.try_into().map_err(Error::TryFromInt)?;
Ok(ptr)
}

/// Check that the given offset and length fits into the memory bounds. If not,
/// it will try to grow the memory.
fn check_bounds<F, S>(
Expand Down
Loading
Loading