Description
Similar to #2292, but this time the proposal's instructions are actually used.
The proposal adds:
@bulk_memory MemoryInit { data_index: u32, mem: u32 } => visit_memory_init
@bulk_memory DataDrop { data_index: u32 } => visit_data_drop
@bulk_memory MemoryCopy { dst_mem: u32, src_mem: u32 } => visit_memory_copy
@bulk_memory MemoryFill { mem: u32 } => visit_memory_fill
@bulk_memory TableInit { elem_index: u32, table: u32 } => visit_table_init
@bulk_memory ElemDrop { elem_index: u32 } => visit_elem_drop
@bulk_memory TableCopy { dst_table: u32, src_table: u32 } => visit_table_copy
We probably need to fully support this proposal, meaning:
- benchmark the instructions
- adjust the
Metering
middleware from wasmer (more details below) - enable the proposal during static validation (see
ParsedWasm
type) - allow the instructions in the
Gatekeeper
Metering
Instructions like memory.copy
don't hardcode the amount of data they work with. Instead, it is a runtime value passed on the Wasm stack. Therefore, we need to adjust the middleware to calculate the gas of memory.copy
and friends based on stack values (in this case probably something like copy_len * gas_per_byte
. This needs to be done in the injected Wasm code that handles the metering.
Also, because it is likely easy to produce very big runtime overhead with a single instruction and because of the way we need to inject this, we will need to handle these instructions like the "accounting operators", meaning we need to add up the accumulated cost with the cost for the memory instruction and then check if that exceeds the gas limit. If so, end execution. Otherwise, subtract both accumulated cost and cost for the memory operation.
While doing all this, we need to make sure that the stack value we read is on the stack again when we are done, i.e. the stack is unchanged by our metering.