From e13904b4c9b75ce53be2cd0b80851192f472f6c2 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Tue, 18 Jun 2024 01:08:51 +0300 Subject: [PATCH 01/28] detect write op --- .../mappers/linked-list-repeat/file.txt | 2150 +++++++++++++++++ .../src/linked_list_repeat.rs | 6 +- .../linked-list-repeat/wasm/src/lib.rs | 6 +- 3 files changed, 2157 insertions(+), 5 deletions(-) create mode 100644 contracts/benchmarks/mappers/linked-list-repeat/file.txt diff --git a/contracts/benchmarks/mappers/linked-list-repeat/file.txt b/contracts/benchmarks/mappers/linked-list-repeat/file.txt new file mode 100644 index 0000000000..799122fd71 --- /dev/null +++ b/contracts/benchmarks/mappers/linked-list-repeat/file.txt @@ -0,0 +1,2150 @@ + /home/bibi/Desktop/mx-sdk-rs/contracts/benchmarks/mappers/linked-list-repeat + +Found 1 contract crates. + +(1/1) +In /home/bibi/Desktop/mx-sdk-rs/contracts/benchmarks/mappers/linked-list-repeat/meta +Calling `cargo run build` +Using workspace target directory: /home/bibi/Desktop/mx-sdk-rs/target ... +Building linked-list-repeat.wasm in /home/bibi/Desktop/mx-sdk-rs/contracts/benchmarks/mappers/linked-list-repeat/wasm ... +RUSTFLAGS="-C link-arg=-s -C link-arg=-zstack-size=131072" cargo build --target=wasm32-unknown-unknown --release --target-dir /home/bibi/Desktop/mx-sdk-rs/target +Copying /home/bibi/Desktop/mx-sdk-rs/target/wasm32-unknown-unknown/release/linked_list_repeat_wasm.wasm to ../output/linked-list-repeat.wasm ... +Calling wasm-opt on ../output/linked-list-repeat.wasm ... +Extracting imports to ../output/linked-list-repeat.imports.json ... +FailAllocator used while memory allocation is accessible in code. Contract may fail unexpectedly when memory allocation is attempted +Instruction: Call { function_index: 24 } +Call instruction: calls function index 24 +Instruction: I32Const { value: 131268 } +Instruction: I32Const { value: 131268 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: I32Const { value: 1 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: End +Instruction: Call { function_index: 2 } +Call instruction: calls function index 2 +Instruction: LocalTee { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 3 } +Call instruction: calls function index 3 +Instruction: Drop +Instruction: LocalGet { local_index: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 4 } +Call instruction: calls function index 4 +Instruction: I32Const { value: 0 } +Instruction: I32GtS +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 96 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Eqz +Instruction: If { blockty: Type(I64) } +Instruction: I64Const { value: 0 } +Instruction: Else +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: Call { function_index: 28 } +Call instruction: calls function index 28 +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: Call { function_index: 25 } +Call instruction: calls function index 25 +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } +Instruction: Call { function_index: 23 } +Call instruction: calls function index 23 +Instruction: LocalSet { local_index: 3 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } +Instruction: Call { function_index: 25 } +Call instruction: calls function index 25 +Instruction: LocalSet { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } +Instruction: LocalSet { local_index: 6 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } +Instruction: Call { function_index: 23 } +Call instruction: calls function index 23 +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 5 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 6 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 3 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 66 } +Call instruction: calls function index 66 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: If { blockty: Type(I32) } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: Call { function_index: 25 } +Call instruction: calls function index 25 +Instruction: LocalSet { local_index: 3 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: LocalTee { local_index: 6 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalSet { local_index: 7 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalTee { local_index: 8 } +Instruction: Call { function_index: 31 } +Call instruction: calls function index 31 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 3 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 66 } +Call instruction: calls function index 66 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 33 } +Call instruction: calls function index 33 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 1 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: I32Const { value: 4 } +Instruction: Call { function_index: 47 } +Call instruction: calls function index 47 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 24 } +Call instruction: calls function index 24 +Instruction: LocalTee { local_index: 0 } +Instruction: Call { function_index: 17 } +Call instruction: calls function index 17 +Instruction: Drop +Instruction: LocalGet { local_index: 0 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 36 } +Call instruction: calls function index 36 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 1 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: Call { function_index: 24 } +Call instruction: calls function index 24 +Instruction: LocalTee { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 5 } +Call instruction: calls function index 5 +Instruction: Drop +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 38 } +Call instruction: calls function index 38 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 7 } +Call instruction: calls function index 7 +Instruction: LocalTee { local_index: 3 } +Instruction: I32Const { value: 24 } +Instruction: I32Shl +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: I32Const { value: 8 } +Instruction: I32Shl +Instruction: I32Or +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 8 } +Instruction: I32ShrU +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 24 } +Instruction: I32ShrU +Instruction: I32Or +Instruction: I32Or +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: I32Const { value: 4 } +Instruction: Call { function_index: 73 } +Call instruction: calls function index 73 +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 24 } +Call instruction: calls function index 24 +Instruction: LocalTee { local_index: 1 } +Instruction: Call { function_index: 6 } +Call instruction: calls function index 6 +Instruction: Drop +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 7 } +Call instruction: calls function index 7 +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 0 } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 24 } +Call instruction: calls function index 24 +Instruction: LocalTee { local_index: 0 } +Instruction: Call { function_index: 8 } +Call instruction: calls function index 8 +Instruction: Drop +Instruction: LocalGet { local_index: 0 } +Instruction: End +Instruction: I32Const { value: 131086 } +Instruction: I32Const { value: 23 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: Call { function_index: 24 } +Call instruction: calls function index 24 +Instruction: LocalTee { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 16 } +Call instruction: calls function index 16 +Instruction: Drop +Instruction: LocalGet { local_index: 2 } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 40 } +Call instruction: calls function index 40 +Instruction: LocalTee { local_index: 3 } +Instruction: Call { function_index: 7 } +Call instruction: calls function index 7 +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 0 } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 28, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: LocalTee { local_index: 3 } +Instruction: Call { function_index: 33 } +Call instruction: calls function index 33 +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 44 } +Call instruction: calls function index 44 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I64Const { value: 0 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: I32Const { value: 8 } +Instruction: Call { function_index: 47 } +Call instruction: calls function index 47 +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 11 } +Call instruction: calls function index 11 +Instruction: LocalTee { local_index: 0 } +Instruction: I64Const { value: 4294967296 } +Instruction: I64GeU +Instruction: If { blockty: Empty } +Instruction: I32Const { value: 131189 } +Instruction: I32Const { value: 11 } +Instruction: I32Const { value: 131072 } +Instruction: I32Const { value: 14 } +Instruction: Call { function_index: 41 } +Call instruction: calls function index 41 +Instruction: Unreachable +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32WrapI64 +Instruction: End +Instruction: Call { function_index: 12 } +Call instruction: calls function index 12 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Eq +Instruction: If { blockty: Empty } +Instruction: Return +Instruction: End +Instruction: I32Const { value: 131112 } +Instruction: I32Const { value: 25 } +Instruction: Call { function_index: 13 } +Call instruction: calls function index 13 +Instruction: Unreachable +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 53 } +Call instruction: calls function index 53 +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 2 } +Call instruction: calls function index 2 +Instruction: LocalTee { local_index: 1 } +Instruction: Call { function_index: 18 } +Call instruction: calls function index 18 +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Eqz +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 1 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: I32Const { value: 4 } +Instruction: Call { function_index: 74 } +Call instruction: calls function index 74 +Instruction: I32Const { value: 131162 } +Instruction: I32Const { value: 22 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: LocalTee { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 9 } +Call instruction: calls function index 9 +Instruction: Drop +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 10 } +Call instruction: calls function index 10 +Instruction: Unreachable +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 14 } +Call instruction: calls function index 14 +Instruction: I32Eqz +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 15 } +Call instruction: calls function index 15 +Instruction: I32Const { value: 0 } +Instruction: I32Ne +Instruction: End +Instruction: Block { blockty: Empty } +Instruction: Block { blockty: Empty } +Instruction: Block { blockty: Type(I32) } +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 8, memory: 0 } } +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalTee { local_index: 4 } +Instruction: Call { function_index: 7 } +Call instruction: calls function index 7 +Instruction: LocalTee { local_index: 5 } +Instruction: I32Const { value: 10000 } +Instruction: I32GtU +Instruction: BrIf { relative_depth: 1 } +Instruction: I32Const { value: 141276 } +Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: BrIf { relative_depth: 1 } +Instruction: I32Const { value: 141272 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: I32Const { value: 141276 } +Instruction: I32Const { value: 1 } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Const { value: 0 } +Instruction: I32Const { value: 131272 } +Instruction: LocalGet { local_index: 5 } +Instruction: Call { function_index: 52 } +Call instruction: calls function index 52 +Instruction: Drop +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 1 } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 8, memory: 0 } } +Instruction: End +Instruction: I32Const { value: 1 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Add +Instruction: LocalTee { local_index: 0 } +Instruction: I32Const { value: 141272 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: I32GtU +Instruction: BrIf { relative_depth: 1 } +Instruction: Drop +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32LtU +Instruction: BrIf { relative_depth: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 10000 } +Instruction: I32GtU +Instruction: BrIf { relative_depth: 3 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 131272 } +Instruction: I32Add +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 89 } +Call instruction: calls function index 89 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: -25 } +Instruction: Call { function_index: 6 } +Call instruction: calls function index 6 +Instruction: Drop +Instruction: I32Const { value: -25 } +Instruction: Call { function_index: 7 } +Call instruction: calls function index 7 +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 56 } +Call instruction: calls function index 56 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: Call { function_index: 19 } +Call instruction: calls function index 19 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 58 } +Call instruction: calls function index 58 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 25 } +Call instruction: calls function index 25 +Instruction: LocalTee { local_index: 0 } +Instruction: I32Const { value: 131157 } +Instruction: I32Const { value: 5 } +Instruction: Call { function_index: 9 } +Call instruction: calls function index 9 +Instruction: Drop +Instruction: LocalGet { local_index: 0 } +Instruction: End +Instruction: I32Const { value: 131224 } +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 24 } +Instruction: I32Shl +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: I32Const { value: 8 } +Instruction: I32Shl +Instruction: I32Or +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32ShrU +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 24 } +Instruction: I32ShrU +Instruction: I32Or +Instruction: I32Or +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: I32Const { value: 4 } +Instruction: Call { function_index: 73 } +Call instruction: calls function index 73 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 19 } +Call instruction: calls function index 19 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 25 } +Call instruction: calls function index 25 +Instruction: LocalTee { local_index: 0 } +Instruction: I32Const { value: 131152 } +Instruction: I32Const { value: 5 } +Instruction: Call { function_index: 9 } +Call instruction: calls function index 9 +Instruction: Drop +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 24 } +Instruction: I32Shl +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: I32Const { value: 8 } +Instruction: I32Shl +Instruction: I32Or +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 8 } +Instruction: I32ShrU +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 24 } +Instruction: I32ShrU +Instruction: I32Or +Instruction: I32Or +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: I32Const { value: 4 } +Instruction: Call { function_index: 9 } +Call instruction: calls function index 9 +Instruction: Drop +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: Call { function_index: 59 } +Call instruction: calls function index 59 +Instruction: LocalSet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 38 } +Call instruction: calls function index 38 +Instruction: LocalGet { local_index: 2 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 65 } +Call instruction: calls function index 65 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 56 } +Instruction: I64Shl +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 65280 } +Instruction: I64And +Instruction: I64Const { value: 40 } +Instruction: I64Shl +Instruction: I64Or +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 16711680 } +Instruction: I64And +Instruction: I64Const { value: 24 } +Instruction: I64Shl +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 4278190080 } +Instruction: I64And +Instruction: I64Const { value: 8 } +Instruction: I64Shl +Instruction: I64Or +Instruction: I64Or +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 8 } +Instruction: I64ShrU +Instruction: I64Const { value: 4278190080 } +Instruction: I64And +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 24 } +Instruction: I64ShrU +Instruction: I64Const { value: 16711680 } +Instruction: I64And +Instruction: I64Or +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 40 } +Instruction: I64ShrU +Instruction: I64Const { value: 65280 } +Instruction: I64And +Instruction: LocalGet { local_index: 0 } +Instruction: I64Const { value: 56 } +Instruction: I64ShrU +Instruction: I64Or +Instruction: I64Or +Instruction: I64Or +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: I32Const { value: 8 } +Instruction: Call { function_index: 73 } +Call instruction: calls function index 73 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: Call { function_index: 54 } +Call instruction: calls function index 54 +Instruction: I32Eqz +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 3 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: Call { function_index: 39 } +Call instruction: calls function index 39 +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 36 } +Call instruction: calls function index 36 +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 4 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: I32Eq +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 28, memory: 0 } } +Instruction: If { blockty: Empty } +Instruction: I32Const { value: 141272 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: I32Const { value: 141276 } +Instruction: I32Const { value: 0 } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 32 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: Return +Instruction: End +Instruction: I32Const { value: 131072 } +Instruction: I32Const { value: 14 } +Instruction: Call { function_index: 50 } +Call instruction: calls function index 50 +Instruction: Unreachable +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 3 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: Call { function_index: 39 } +Call instruction: calls function index 39 +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 36 } +Call instruction: calls function index 36 +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 72 } +Call instruction: calls function index 72 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 32 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalTee { local_index: 3 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Block { blockty: Empty } +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 58 } +Call instruction: calls function index 58 +Instruction: LocalTee { local_index: 1 } +Instruction: Call { function_index: 54 } +Call instruction: calls function index 54 +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: I32Const { value: 0 } +Instruction: LocalSet { local_index: 1 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: LocalTee { local_index: 3 } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 39 } +Call instruction: calls function index 39 +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 3 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 4 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: Call { function_index: 49 } +Call instruction: calls function index 49 +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: I32Ne +Instruction: BrIf { relative_depth: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 28, memory: 0 } } +Instruction: I32Eqz +Instruction: BrIf { relative_depth: 0 } +Instruction: I32Const { value: 141272 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: I32Const { value: 141276 } +Instruction: I32Const { value: 0 } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 32 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: Return +Instruction: End +Instruction: I32Const { value: 131072 } +Instruction: I32Const { value: 14 } +Instruction: Call { function_index: 50 } +Call instruction: calls function index 50 +Instruction: Unreachable +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 80 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: -64 } +Instruction: I32Sub +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalTee { local_index: 3 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 68, memory: 0 } } +Instruction: Call { function_index: 29 } +Call instruction: calls function index 29 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Const { value: 56 } +Instruction: Call { function_index: 89 } +Call instruction: calls function index 89 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 2 } +Instruction: GlobalSet { global_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I64Const { value: 0 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: I32Const { value: 8 } +Instruction: Call { function_index: 74 } +Call instruction: calls function index 74 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 9 } +Call instruction: calls function index 9 +Instruction: Drop +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 53 } +Call instruction: calls function index 53 +Instruction: If { blockty: Empty } +Instruction: I32Const { value: 131137 } +Instruction: I32Const { value: 15 } +Instruction: Call { function_index: 50 } +Call instruction: calls function index 50 +Instruction: Unreachable +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Add +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: End +Instruction: I32Const { value: 131200 } +Instruction: I32Const { value: 12 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: End +Instruction: I32Const { value: 131212 } +Instruction: I32Const { value: 9 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: End +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 2 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: Call { function_index: 45 } +Call instruction: calls function index 45 +Instruction: LocalSet { local_index: 6 } +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 40 } +Call instruction: calls function index 40 +Instruction: LocalSet { local_index: 7 } +Instruction: Call { function_index: 76 } +Call instruction: calls function index 76 +Instruction: LocalSet { local_index: 2 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 6 } +Instruction: I32Ne +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 7 } +Instruction: Call { function_index: 25 } +Call instruction: calls function index 25 +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 24 } +Instruction: I32Shl +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: I32Const { value: 8 } +Instruction: I32Shl +Instruction: I32Or +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 8 } +Instruction: I32ShrU +Instruction: I32Const { value: 65280 } +Instruction: I32And +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 24 } +Instruction: I32ShrU +Instruction: I32Or +Instruction: I32Or +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 5 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: I32Const { value: 4 } +Instruction: Call { function_index: 9 } +Call instruction: calls function index 9 +Instruction: Drop +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalTee { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalTee { local_index: 8 } +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: I32Const { value: 0 } +Instruction: LocalSet { local_index: 4 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: LocalTee { local_index: 9 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } +Instruction: LocalTee { local_index: 4 } +Instruction: Call { function_index: 67 } +Call instruction: calls function index 67 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 4 } +Instruction: LocalGet { local_index: 9 } +Instruction: Call { function_index: 62 } +Call instruction: calls function index 62 +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: Call { function_index: 62 } +Call instruction: calls function index 62 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 8 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 57 } +Call instruction: calls function index 57 +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: -64 } +Instruction: I32Add +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 40 } +Call instruction: calls function index 40 +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 76 } +Call instruction: calls function index 76 +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: Call { function_index: 69 } +Call instruction: calls function index 69 +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 44 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: Call { function_index: 30 } +Call instruction: calls function index 30 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 44, memory: 0 } } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 48, memory: 0 } } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 26 } +Call instruction: calls function index 26 +Instruction: LocalGet { local_index: 1 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 1 } +Instruction: I64ExtendI32U +Instruction: Call { function_index: 21 } +Call instruction: calls function index 21 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: -64 } +Instruction: I32Sub +Instruction: GlobalSet { global_index: 0 } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: -64 } +Instruction: I32Add +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: Call { function_index: 45 } +Call instruction: calls function index 45 +Instruction: LocalSet { local_index: 5 } +Instruction: Call { function_index: 76 } +Call instruction: calls function index 76 +Instruction: LocalSet { local_index: 1 } +Instruction: Block { blockty: Empty } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 5 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 12 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalTee { local_index: 2 } +Instruction: Call { function_index: 66 } +Call instruction: calls function index 66 +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 28 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 31 } +Call instruction: calls function index 31 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } +Instruction: I32Eqz +Instruction: BrIf { relative_depth: 3 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 44, memory: 0 } } +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 40, memory: 0 } } +Instruction: LocalSet { local_index: 3 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 36, memory: 0 } } +Instruction: LocalTee { local_index: 6 } +Instruction: Call { function_index: 66 } +Call instruction: calls function index 66 +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 2 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 67 } +Call instruction: calls function index 67 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 36, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 62 } +Call instruction: calls function index 62 +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 52, memory: 0 } } +Instruction: End +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 3 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 28 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 67 } +Call instruction: calls function index 67 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 40, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 62 } +Call instruction: calls function index 62 +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 56, memory: 0 } } +Instruction: End +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 6 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: Call { function_index: 55 } +Call instruction: calls function index 55 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 48, memory: 0 } } +Instruction: I32Const { value: 1 } +Instruction: I32Sub +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 48, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Add +Instruction: Call { function_index: 57 } +Call instruction: calls function index 57 +Instruction: End +Instruction: LocalGet { local_index: 5 } +Instruction: I32Const { value: 1 } +Instruction: I32Sub +Instruction: LocalSet { local_index: 5 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: -64 } +Instruction: I32Sub +Instruction: GlobalSet { global_index: 0 } +Instruction: Return +Instruction: End +Instruction: Call { function_index: 81 } +Call instruction: calls function index 81 +Instruction: Call { function_index: 88 } +Call instruction: calls function index 88 +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 76 } +Call instruction: calls function index 76 +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 69 } +Call instruction: calls function index 69 +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 28 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: Call { function_index: 30 } +Call instruction: calls function index 30 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 32, memory: 0 } } +Instruction: Call { function_index: 22 } +Call instruction: calls function index 22 +Instruction: Drop +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 128 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 2 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: Call { function_index: 45 } +Call instruction: calls function index 45 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 32 } +Instruction: I32Add +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 43 } +Call instruction: calls function index 43 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 108 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 56 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalTee { local_index: 11 } +Instruction: I64Store { memarg: MemArg { align: 2, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 40 } +Instruction: I32Add +Instruction: LocalTee { local_index: 5 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 16 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 48 } +Instruction: I32Add +Instruction: LocalTee { local_index: 6 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 24 } +Instruction: I32Add +Instruction: LocalGet { local_index: 11 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 32, memory: 0 } } +Instruction: LocalTee { local_index: 11 } +Instruction: I64Store { memarg: MemArg { align: 2, max_align: 3, offset: 84, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 11 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64ExtendI32U +Instruction: LocalSet { local_index: 12 } +Instruction: I64Const { value: 0 } +Instruction: LocalSet { local_index: 11 } +Instruction: Call { function_index: 75 } +Call instruction: calls function index 75 +Instruction: LocalSet { local_index: 1 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 11 } +Instruction: LocalGet { local_index: 12 } +Instruction: I64Eq +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 80 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 28 } +Call instruction: calls function index 28 +Instruction: LocalGet { local_index: 5 } +Instruction: LocalGet { local_index: 11 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 6 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 96 } +Instruction: I32Add +Instruction: LocalTee { local_index: 7 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 4 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 104 } +Instruction: I32Add +Instruction: LocalTee { local_index: 8 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 11 } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 32, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: -64 } +Instruction: I32Sub +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 76, memory: 0 } } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalTee { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 76, memory: 0 } } +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } +Instruction: LocalTee { local_index: 9 } +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 68, memory: 0 } } +Instruction: I32Const { value: 0 } +Instruction: LocalSet { local_index: 3 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 80 } +Instruction: I32Add +Instruction: LocalTee { local_index: 10 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 72, memory: 0 } } +Instruction: LocalTee { local_index: 3 } +Instruction: Call { function_index: 68 } +Call instruction: calls function index 68 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 116, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 10 } +Instruction: Call { function_index: 64 } +Call instruction: calls function index 64 +Instruction: End +Instruction: LocalGet { local_index: 8 } +Instruction: LocalGet { local_index: 4 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 7 } +Instruction: LocalGet { local_index: 6 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 88 } +Instruction: I32Add +Instruction: LocalGet { local_index: 5 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 32, memory: 0 } } +Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 80, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 120, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 0 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 116, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 112, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 80 } +Instruction: I32Add +Instruction: Call { function_index: 64 } +Call instruction: calls function index 64 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 9 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 72, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: -64 } +Instruction: I32Sub +Instruction: Call { function_index: 57 } +Call instruction: calls function index 57 +Instruction: LocalGet { local_index: 11 } +Instruction: I64Const { value: 1 } +Instruction: I64Add +Instruction: LocalSet { local_index: 11 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 128 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 160 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 43 } +Call instruction: calls function index 43 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 75 } +Call instruction: calls function index 75 +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 36, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 40 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 36 } +Instruction: I32Add +Instruction: Call { function_index: 71 } +Call instruction: calls function index 71 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } +Instruction: LocalSet { local_index: 3 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } +Instruction: LocalSet { local_index: 4 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } +Instruction: LocalSet { local_index: 6 } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } +Instruction: LocalSet { local_index: 10 } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } +Instruction: LocalSet { local_index: 11 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 104 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 40 } +Instruction: I32Add +Instruction: Call { function_index: 27 } +Call instruction: calls function index 27 +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 104, memory: 0 } } +Instruction: I64Eqz +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 112, memory: 0 } } +Instruction: LocalSet { local_index: 12 } +Instruction: I32Const { value: 0 } +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 140, memory: 0 } } +Instruction: LocalSet { local_index: 7 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 136, memory: 0 } } +Instruction: LocalSet { local_index: 8 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 132, memory: 0 } } +Instruction: LocalSet { local_index: 9 } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 120, memory: 0 } } +Instruction: LocalSet { local_index: 13 } +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 128, memory: 0 } } +Instruction: LocalGet { local_index: 6 } +Instruction: Call { function_index: 26 } +Call instruction: calls function index 26 +Instruction: I32Eqz +Instruction: LocalGet { local_index: 11 } +Instruction: LocalGet { local_index: 12 } +Instruction: I64Ne +Instruction: I32Or +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 9 } +Instruction: LocalGet { local_index: 5 } +Instruction: Call { function_index: 51 } +Call instruction: calls function index 51 +Instruction: I32Eqz +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 8 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 26 } +Call instruction: calls function index 26 +Instruction: I32Eqz +Instruction: LocalGet { local_index: 10 } +Instruction: LocalGet { local_index: 13 } +Instruction: I64Ne +Instruction: I32Or +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 7 } +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 51 } +Call instruction: calls function index 51 +Instruction: LocalSet { local_index: 2 } +Instruction: End +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 1 } +Instruction: I64ExtendI32U +Instruction: Call { function_index: 21 } +Call instruction: calls function index 21 +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 160 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 96 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 1 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: Call { function_index: 45 } +Call instruction: calls function index 45 +Instruction: LocalSet { local_index: 5 } +Instruction: Call { function_index: 75 } +Call instruction: calls function index 75 +Instruction: LocalSet { local_index: 1 } +Instruction: Block { blockty: Empty } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 5 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } +Instruction: LocalTee { local_index: 2 } +Instruction: Call { function_index: 66 } +Call instruction: calls function index 66 +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 24 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 29 } +Call instruction: calls function index 29 +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 24, memory: 0 } } +Instruction: I64Eqz +Instruction: BrIf { relative_depth: 3 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 72, memory: 0 } } +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 68, memory: 0 } } +Instruction: LocalSet { local_index: 3 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } +Instruction: LocalTee { local_index: 6 } +Instruction: Call { function_index: 66 } +Call instruction: calls function index 66 +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 80 } +Instruction: I32Add +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 70 } +Call instruction: calls function index 70 +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 2 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: Call { function_index: 68 } +Call instruction: calls function index 68 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 60, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 64 } +Call instruction: calls function index 64 +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 84, memory: 0 } } +Instruction: End +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 3 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 24 } +Instruction: I32Add +Instruction: LocalTee { local_index: 4 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: Call { function_index: 68 } +Call instruction: calls function index 68 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 4 } +Instruction: Call { function_index: 64 } +Call instruction: calls function index 64 +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 88, memory: 0 } } +Instruction: End +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 6 } +Instruction: Call { function_index: 63 } +Call instruction: calls function index 63 +Instruction: Call { function_index: 55 } +Call instruction: calls function index 55 +Instruction: LocalGet { local_index: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 80, memory: 0 } } +Instruction: I32Const { value: 1 } +Instruction: I32Sub +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 80, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 80 } +Instruction: I32Add +Instruction: Call { function_index: 57 } +Call instruction: calls function index 57 +Instruction: End +Instruction: LocalGet { local_index: 5 } +Instruction: I32Const { value: 1 } +Instruction: I32Sub +Instruction: LocalSet { local_index: 5 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 96 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: Return +Instruction: End +Instruction: Call { function_index: 81 } +Call instruction: calls function index 81 +Instruction: Unreachable +Instruction: End +Instruction: GlobalGet { global_index: 0 } +Instruction: I32Const { value: 128 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 0 } +Instruction: GlobalSet { global_index: 0 } +Instruction: Call { function_index: 20 } +Call instruction: calls function index 20 +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 46 } +Call instruction: calls function index 46 +Instruction: LocalGet { local_index: 0 } +Instruction: Call { function_index: 75 } +Call instruction: calls function index 75 +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: Call { function_index: 71 } +Call instruction: calls function index 71 +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 72 } +Instruction: I32Add +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 8 } +Instruction: I32Add +Instruction: Call { function_index: 27 } +Call instruction: calls function index 27 +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 72, memory: 0 } } +Instruction: I64Eqz +Instruction: I32Eqz +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 108, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 88, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 104, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 100, memory: 0 } } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 96, memory: 0 } } +Instruction: I32Const { value: 131224 } +Instruction: I32Const { value: 0 } +Instruction: Call { function_index: 42 } +Call instruction: calls function index 42 +Instruction: LocalTee { local_index: 1 } +Instruction: Call { function_index: 38 } +Call instruction: calls function index 38 +Instruction: LocalGet { local_index: 0 } +Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 80, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 65 } +Call instruction: calls function index 65 +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 37 } +Call instruction: calls function index 37 +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 38 } +Call instruction: calls function index 38 +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 65 } +Call instruction: calls function index 65 +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 37 } +Call instruction: calls function index 37 +Instruction: LocalGet { local_index: 1 } +Instruction: Call { function_index: 22 } +Call instruction: calls function index 22 +Instruction: Drop +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 128 } +Instruction: I32Add +Instruction: GlobalSet { global_index: 0 } +Instruction: End +Instruction: End +Instruction: I32Const { value: 131224 } +Instruction: I32Const { value: 14 } +Instruction: Call { function_index: 13 } +Call instruction: calls function index 13 +Instruction: Unreachable +Instruction: End +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalTee { local_index: 4 } +Instruction: I32Const { value: 16 } +Instruction: I32LtU +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalSet { local_index: 2 } +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: I32Const { value: 0 } +Instruction: LocalGet { local_index: 0 } +Instruction: I32Sub +Instruction: I32Const { value: 3 } +Instruction: I32And +Instruction: LocalTee { local_index: 3 } +Instruction: I32Add +Instruction: LocalSet { local_index: 5 } +Instruction: LocalGet { local_index: 3 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 0 } +Instruction: LocalSet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalSet { local_index: 6 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 6 } +Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 6 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalSet { local_index: 6 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalTee { local_index: 2 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32LtU +Instruction: BrIf { relative_depth: 0 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 5 } +Instruction: LocalGet { local_index: 4 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Sub +Instruction: LocalTee { local_index: 8 } +Instruction: I32Const { value: -4 } +Instruction: I32And +Instruction: LocalTee { local_index: 7 } +Instruction: I32Add +Instruction: LocalSet { local_index: 2 } +Instruction: Block { blockty: Empty } +Instruction: LocalGet { local_index: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Add +Instruction: LocalTee { local_index: 3 } +Instruction: I32Const { value: 3 } +Instruction: I32And +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 7 } +Instruction: I32Const { value: 0 } +Instruction: I32LeS +Instruction: BrIf { relative_depth: 1 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: 3 } +Instruction: I32Shl +Instruction: LocalTee { local_index: 4 } +Instruction: I32Const { value: 24 } +Instruction: I32And +Instruction: LocalSet { local_index: 9 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32Const { value: -4 } +Instruction: I32And +Instruction: LocalTee { local_index: 6 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: I32Const { value: 0 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Sub +Instruction: I32Const { value: 24 } +Instruction: I32And +Instruction: LocalSet { local_index: 4 } +Instruction: LocalGet { local_index: 6 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalSet { local_index: 6 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 5 } +Instruction: LocalGet { local_index: 6 } +Instruction: LocalGet { local_index: 9 } +Instruction: I32ShrU +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalTee { local_index: 6 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Shl +Instruction: I32Or +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: LocalTee { local_index: 5 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32LtU +Instruction: BrIf { relative_depth: 0 } +Instruction: End +Instruction: Br { relative_depth: 1 } +Instruction: End +Instruction: LocalGet { local_index: 7 } +Instruction: I32Const { value: 0 } +Instruction: I32LeS +Instruction: BrIf { relative_depth: 0 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalSet { local_index: 1 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 5 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 5 } +Instruction: I32Const { value: 4 } +Instruction: I32Add +Instruction: LocalTee { local_index: 5 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32LtU +Instruction: BrIf { relative_depth: 0 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 8 } +Instruction: I32Const { value: 3 } +Instruction: I32And +Instruction: LocalSet { local_index: 4 } +Instruction: LocalGet { local_index: 3 } +Instruction: LocalGet { local_index: 7 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: End +Instruction: LocalGet { local_index: 4 } +Instruction: If { blockty: Empty } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 4 } +Instruction: I32Add +Instruction: LocalSet { local_index: 3 } +Instruction: Loop { blockty: Empty } +Instruction: LocalGet { local_index: 2 } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } +Instruction: LocalGet { local_index: 1 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalSet { local_index: 1 } +Instruction: LocalGet { local_index: 2 } +Instruction: I32Const { value: 1 } +Instruction: I32Add +Instruction: LocalTee { local_index: 2 } +Instruction: LocalGet { local_index: 3 } +Instruction: I32LtU +Instruction: BrIf { relative_depth: 0 } +Instruction: End +Instruction: End +Instruction: LocalGet { local_index: 0 } +Instruction: End +Checking EI version: 1.3 ... OK +Packing ../output/linked-list-repeat.mxsc.json ... +Contract size: 6615 bytes. +analyze this via wasm +analyze this via wasm diff --git a/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs b/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs index 40dfcba638..cc7d8959ff 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs +++ b/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs @@ -1,8 +1,9 @@ #![no_std] +use benchmark_common::ExampleStruct; + multiversx_sc::imports!(); -use benchmark_common::ExampleStruct; pub mod linked_list_repeat_proxy; #[multiversx_sc::contract] @@ -38,7 +39,8 @@ pub trait LinkedListRepeat: benchmark_common::BenchmarkCommon { #[storage_mapper("benchmark")] fn bench(&self) -> LinkedListMapper; - #[endpoint] + #[view] + // #[endpoint] fn add_struct(&self, num_repeats: usize, value: ExampleStruct) { let mut bench = self.bench_struct(); for i in 0..num_repeats { diff --git a/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs index 1e79aa533a..9e22454e98 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench => bench - add_struct => add_struct + bench___view => bench + add_struct___view => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct => bench_struct + bench_struct___view => bench_struct ) } From e5bfff759fc02dedba5cc9e9cb7147f7e2af8e35 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Tue, 18 Jun 2024 01:15:16 +0300 Subject: [PATCH 02/28] detect write op --- .../mappers/queue-repeat/wasm/src/lib.rs | 4 +- .../mappers/set-repeat/wasm/src/lib.rs | 4 +- .../mappers/vec-repeat/wasm/src/lib.rs | 4 +- contracts/examples/adder/src/adder.rs | 24 +++- contracts/examples/adder/wasm/src/lib.rs | 4 +- .../src/parse/attributes/endpoint_attr.rs | 2 +- framework/derive/src/parse/endpoint_parse.rs | 8 +- .../src/contract/sc_config/wasm_build.rs | 5 + .../meta-lib/src/tools/wasm_extractor.rs | 110 +++++++++++++++++- 9 files changed, 148 insertions(+), 17 deletions(-) diff --git a/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs index 887fb0c6e6..c254f43e57 100644 --- a/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench => bench + bench___view => bench add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct => bench_struct + bench_struct___view => bench_struct ) } diff --git a/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs index 7a1a61db74..79d7ac9f8a 100644 --- a/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench => bench + bench___view => bench add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct => bench_struct + bench_struct___view => bench_struct ) } diff --git a/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs index 6f915470d8..4a56536d8a 100644 --- a/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench => bench + bench___view => bench add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct => bench_struct + bench_struct___view => bench_struct ) } diff --git a/contracts/examples/adder/src/adder.rs b/contracts/examples/adder/src/adder.rs index 307f4112f5..18426a514f 100644 --- a/contracts/examples/adder/src/adder.rs +++ b/contracts/examples/adder/src/adder.rs @@ -1,3 +1,25 @@ +// 0 true, +// 1 true, +// 2 true, +// 3 true, +// 4 false, +// 5 true, +// 6 true, +// 7 true, +// 8 true, +// 9 true, +//10 true, +//11 true, +//12 true, +//13 true, +//14 false, +//15 true, +//16 true, +//17 false, +//18 true, +//19 false, +//20 true, + #![no_std] use multiversx_sc::imports::*; @@ -23,7 +45,7 @@ pub trait Adder { } /// Add desired amount to the storage variable. - #[endpoint] + #[view] fn add(&self, value: BigUint) { self.sum().update(|sum| *sum += value); } diff --git a/contracts/examples/adder/wasm/src/lib.rs b/contracts/examples/adder/wasm/src/lib.rs index 19ea33c7e1..f61318cdc4 100644 --- a/contracts/examples/adder/wasm/src/lib.rs +++ b/contracts/examples/adder/wasm/src/lib.rs @@ -20,8 +20,8 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - getSum => sum - add => add + getSum___view => sum + add___view => add ) } diff --git a/framework/derive/src/parse/attributes/endpoint_attr.rs b/framework/derive/src/parse/attributes/endpoint_attr.rs index 678675b202..4b742f5116 100644 --- a/framework/derive/src/parse/attributes/endpoint_attr.rs +++ b/framework/derive/src/parse/attributes/endpoint_attr.rs @@ -57,7 +57,7 @@ pub struct ViewAttribute { pub view_name: Option, } -impl ViewAttribute { +impl ViewAttribute { pub fn parse(attr: &syn::Attribute) -> Option { match is_attr_with_one_opt_token_tree_arg(attr, ATTR_VIEW) { None => None, diff --git a/framework/derive/src/parse/endpoint_parse.rs b/framework/derive/src/parse/endpoint_parse.rs index 5edc30ad08..1262e47571 100644 --- a/framework/derive/src/parse/endpoint_parse.rs +++ b/framework/derive/src/parse/endpoint_parse.rs @@ -133,8 +133,12 @@ pub fn process_view_attribute( .map(|view_attribute| { check_single_role(&*method); let view_ident = match view_attribute.view_name { - Some(ident) => ident, - None => method.name.clone(), + Some(ident) => { + format_ident!("{}___view", ident) + }, + None => { + format_ident!("{}___view", method.name.clone()) + }, }; method.public_role = PublicRole::Endpoint(EndpointMetadata { public_name: view_ident, diff --git a/framework/meta-lib/src/contract/sc_config/wasm_build.rs b/framework/meta-lib/src/contract/sc_config/wasm_build.rs index 5b318da9a0..49ac6bb2d7 100644 --- a/framework/meta-lib/src/contract/sc_config/wasm_build.rs +++ b/framework/meta-lib/src/contract/sc_config/wasm_build.rs @@ -93,6 +93,11 @@ impl ContractVariant { print_pack_mxsc_file(&output_mxsc_path); print_contract_size(compiled_bytes.len()); let mut abi = ContractAbiJson::from(&self.abi); + for endpoint in &abi.endpoints { + if endpoint.name.contains("__view") { + println!("analyze this via wasm"); + } + } let build_info = core::mem::take(&mut abi.build_info).unwrap(); let ei_check_json = EiCheckJson::new(&self.settings.check_ei, wasm_info.ei_check); let report = ReportInfoJson::new(&wasm_info, ei_check_json, compiled_bytes.len()); diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index 50d5b78aff..4c0d171ac8 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -1,7 +1,9 @@ use colored::Colorize; -use std::fs; +use semver::Op; +use std::{collections::HashMap, fs}; use wasmparser::{ - BinaryReaderError, DataSectionReader, FunctionBody, ImportSectionReader, Parser, Payload, + BinaryReaderError, DataSectionReader, ExportSectionReader, FunctionBody, ImportSectionReader, + Operator, Parser, Payload, }; use crate::ei::EIVersion; @@ -12,6 +14,12 @@ const PANIC_WITH_MESSAGE: &[u8; 16] = b"panic occurred: "; const PANIC_WITHOUT_MESSAGE: &[u8; 14] = b"panic occurred"; const ERROR_FAIL_ALLOCATOR: &[u8; 27] = b"memory allocation forbidden"; const MEMORY_GROW_OPCODE: u8 = 0x40; +const WRITE_OP: [&str; 1] = [ + // "mBufferAppend", + // "mBufferAppendBytes", + // "mBufferSetBytes", + "mBufferStorageStore", +]; pub struct WasmInfo { pub imports: Vec, @@ -50,12 +58,15 @@ fn populate_wasm_info( let mut ei_check = false; let mut memory_grow_flag = false; let mut has_panic = "none"; + let mut function_names: HashMap = HashMap::new(); + let mut read_functions: Vec = Vec::new(); - let parser = Parser::new(0); + let mut parser = Parser::new(0); for payload in parser.parse_all(&wasm_data) { match payload? { Payload::ImportSection(import_section) => { - imports = extract_imports(import_section, extract_imports_enabled); + imports = + extract_imports(import_section, extract_imports_enabled, &mut read_functions); ei_check = is_ei_valid(imports.clone(), check_ei); }, Payload::DataSection(data_section) => { @@ -67,12 +78,38 @@ fn populate_wasm_info( } }, Payload::CodeSectionEntry(code_section) => { - memory_grow_flag = is_mem_grow(code_section); + memory_grow_flag = is_mem_grow(code_section.clone()); + }, + Payload::ExportSection(export_section) => { + parse_export_section(export_section, &mut function_names); + // println!("{:#?}", function_names); }, _ => (), } } + parser = Parser::new(0); + for payload in parser.parse_all(&wasm_data) { + if let Payload::CodeSectionEntry(body) = payload? { + analyze_function_body(body, &mut read_functions); + } + } + + // println!("{:#?}", read_functions); + for (index, name) in function_names { + let i: usize = index.try_into().unwrap(); + if !read_functions[i] { + println!( + "{} >> {}", + "Write storage in VIEW endpoint entitled " + .to_string() + .red() + .bold(), + name.red().bold() + ); + } + } + let report = ReportCreator { path, has_allocator: allocator_trigger, @@ -88,6 +125,63 @@ fn populate_wasm_info( }) } +fn parse_export_section( + export_section: ExportSectionReader, + function_names: &mut HashMap, +) { + for export in export_section { + let export = export.expect("Failed to read export section"); + if let wasmparser::ExternalKind::Func = export.kind { + if export.name.to_string().ends_with("__view") { + function_names.insert(export.index, export.name.to_string()); + } + } + } +} + +fn analyze_function_body(body: FunctionBody, functions: &mut Vec) { + // Implement your function body analysis here + // For example, you can parse the locals and instructions + // let locals_reader = body + // .get_locals_reader() + // .expect("Failed to get locals reader"); + let mut instructions_reader = body + .get_operators_reader() + .expect("Failed to get operators reader"); + + // println!("Function has {} locals", locals_reader.get_count()); + + let mut value = true; + while let Ok(op) = instructions_reader.read() { + match op { + Operator::Call { function_index } => { + let function_usize: usize = function_index.try_into().unwrap(); + if function_usize >= functions.len() { + functions.push(true); + return; + } + + value &= functions[function_usize]; + + if !value { + functions.push(value); + return; + } + }, + Operator::I32Load { memarg } => { + if memarg.offset > 0 { + functions.push(false); + return; + } + }, + _ => (), + } + } + + functions.push(value); + // println!("===================="); +} + fn is_fail_allocator_triggered(data_section: DataSectionReader) -> bool { for data_fragment in data_section.into_iter().flatten() { if data_fragment @@ -140,6 +234,7 @@ fn is_panic_without_message_triggered(data_section: DataSectionReader) -> bool { pub fn extract_imports( import_section: ImportSectionReader, import_extraction_enabled: bool, + write_or_read_functions: &mut Vec, ) -> Vec { if !import_extraction_enabled { return Vec::new(); @@ -148,6 +243,11 @@ pub fn extract_imports( let mut import_names = Vec::new(); for import in import_section.into_iter().flatten() { import_names.push(import.name.to_string()); + if WRITE_OP.contains(&import.name) { + write_or_read_functions.push(false); + } else { + write_or_read_functions.push(true); + } } import_names.sort(); From a71bd3e625df61364f00a1d6984c3fd182de6224 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Thu, 20 Jun 2024 15:56:17 +0300 Subject: [PATCH 03/28] remove alter of the view endpoint name --- contracts/examples/adder/src/adder.rs | 22 ------------- contracts/examples/adder/wasm/src/lib.rs | 4 +-- framework/derive/src/parse/endpoint_parse.rs | 8 ++--- .../src/contract/sc_config/wasm_build.rs | 32 ++++++++++++++++--- .../meta-lib/src/tools/wasm_extractor.rs | 22 ++++++------- 5 files changed, 40 insertions(+), 48 deletions(-) diff --git a/contracts/examples/adder/src/adder.rs b/contracts/examples/adder/src/adder.rs index 18426a514f..77358e4b7b 100644 --- a/contracts/examples/adder/src/adder.rs +++ b/contracts/examples/adder/src/adder.rs @@ -1,25 +1,3 @@ -// 0 true, -// 1 true, -// 2 true, -// 3 true, -// 4 false, -// 5 true, -// 6 true, -// 7 true, -// 8 true, -// 9 true, -//10 true, -//11 true, -//12 true, -//13 true, -//14 false, -//15 true, -//16 true, -//17 false, -//18 true, -//19 false, -//20 true, - #![no_std] use multiversx_sc::imports::*; diff --git a/contracts/examples/adder/wasm/src/lib.rs b/contracts/examples/adder/wasm/src/lib.rs index f61318cdc4..19ea33c7e1 100644 --- a/contracts/examples/adder/wasm/src/lib.rs +++ b/contracts/examples/adder/wasm/src/lib.rs @@ -20,8 +20,8 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - getSum___view => sum - add___view => add + getSum => sum + add => add ) } diff --git a/framework/derive/src/parse/endpoint_parse.rs b/framework/derive/src/parse/endpoint_parse.rs index 1262e47571..5edc30ad08 100644 --- a/framework/derive/src/parse/endpoint_parse.rs +++ b/framework/derive/src/parse/endpoint_parse.rs @@ -133,12 +133,8 @@ pub fn process_view_attribute( .map(|view_attribute| { check_single_role(&*method); let view_ident = match view_attribute.view_name { - Some(ident) => { - format_ident!("{}___view", ident) - }, - None => { - format_ident!("{}___view", method.name.clone()) - }, + Some(ident) => ident, + None => method.name.clone(), }; method.public_role = PublicRole::Endpoint(EndpointMetadata { public_name: view_ident, diff --git a/framework/meta-lib/src/contract/sc_config/wasm_build.rs b/framework/meta-lib/src/contract/sc_config/wasm_build.rs index 49ac6bb2d7..e7a9bec5ed 100644 --- a/framework/meta-lib/src/contract/sc_config/wasm_build.rs +++ b/framework/meta-lib/src/contract/sc_config/wasm_build.rs @@ -93,9 +93,14 @@ impl ContractVariant { print_pack_mxsc_file(&output_mxsc_path); print_contract_size(compiled_bytes.len()); let mut abi = ContractAbiJson::from(&self.abi); + let mut view_endpoints = Vec::new(); for endpoint in &abi.endpoints { - if endpoint.name.contains("__view") { - println!("analyze this via wasm"); + match endpoint.mutability { + crate::abi_json::EndpointMutabilityAbiJson::Readonly => { + view_endpoints.push(&endpoint.name) + }, + crate::abi_json::EndpointMutabilityAbiJson::Mutable => (), + crate::abi_json::EndpointMutabilityAbiJson::Pure => (), } } let build_info = core::mem::take(&mut abi.build_info).unwrap(); @@ -135,11 +140,24 @@ impl ContractVariant { fn extract_wasm_info(&self, build_args: &BuildArgs, output_path: &str) -> WasmInfo { let output_wasm_path = format!("{output_path}/{}", self.wasm_output_name(build_args)); + let abi = ContractAbiJson::from(&self.abi); + let mut view_endpoints = Vec::new(); + for endpoint in &abi.endpoints { + match endpoint.mutability { + crate::abi_json::EndpointMutabilityAbiJson::Readonly => { + view_endpoints.push(endpoint.name.clone()) + }, + crate::abi_json::EndpointMutabilityAbiJson::Mutable => (), + crate::abi_json::EndpointMutabilityAbiJson::Pure => (), + } + } + if !build_args.extract_imports { return WasmInfo::extract_wasm_info( &output_wasm_path, build_args.extract_imports, &self.settings.check_ei, + view_endpoints, ) .expect("error occured while extracting imports from .wasm "); } @@ -151,9 +169,13 @@ impl ContractVariant { ); print_extract_imports(&output_imports_json_path); - let wasm_data = - WasmInfo::extract_wasm_info(&output_wasm_path, true, &self.settings.check_ei) - .expect("error occured while extracting imports from .wasm "); + let wasm_data = WasmInfo::extract_wasm_info( + &output_wasm_path, + true, + &self.settings.check_ei, + view_endpoints, + ) + .expect("error occured while extracting imports from .wasm "); write_imports_output( output_imports_json_path.as_str(), diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index 4c0d171ac8..fa466440da 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -1,5 +1,4 @@ use colored::Colorize; -use semver::Op; use std::{collections::HashMap, fs}; use wasmparser::{ BinaryReaderError, DataSectionReader, ExportSectionReader, FunctionBody, ImportSectionReader, @@ -14,12 +13,7 @@ const PANIC_WITH_MESSAGE: &[u8; 16] = b"panic occurred: "; const PANIC_WITHOUT_MESSAGE: &[u8; 14] = b"panic occurred"; const ERROR_FAIL_ALLOCATOR: &[u8; 27] = b"memory allocation forbidden"; const MEMORY_GROW_OPCODE: u8 = 0x40; -const WRITE_OP: [&str; 1] = [ - // "mBufferAppend", - // "mBufferAppendBytes", - // "mBufferSetBytes", - "mBufferStorageStore", -]; +const WRITE_OP: [&str; 1] = ["mBufferStorageStore"]; pub struct WasmInfo { pub imports: Vec, @@ -34,6 +28,7 @@ impl WasmInfo { output_wasm_path: &str, extract_imports_enabled: bool, check_ei: &Option, + view_endpoints: Vec, ) -> Result { let wasm_data = fs::read(output_wasm_path) .expect("error occured while extracting information from .wasm: file not found"); @@ -43,6 +38,7 @@ impl WasmInfo { wasm_data, extract_imports_enabled, check_ei, + view_endpoints, ) } } @@ -52,6 +48,7 @@ fn populate_wasm_info( wasm_data: Vec, extract_imports_enabled: bool, check_ei: &Option, + view_endpoints: Vec, ) -> Result { let mut imports = Vec::new(); let mut allocator_trigger = false; @@ -81,8 +78,7 @@ fn populate_wasm_info( memory_grow_flag = is_mem_grow(code_section.clone()); }, Payload::ExportSection(export_section) => { - parse_export_section(export_section, &mut function_names); - // println!("{:#?}", function_names); + parse_export_section(export_section, &mut function_names, view_endpoints.clone()); }, _ => (), } @@ -95,13 +91,12 @@ fn populate_wasm_info( } } - // println!("{:#?}", read_functions); for (index, name) in function_names { let i: usize = index.try_into().unwrap(); if !read_functions[i] { println!( - "{} >> {}", - "Write storage in VIEW endpoint entitled " + "{} {}", + "Write storage operation in VIEW endpoint:" .to_string() .red() .bold(), @@ -128,11 +123,12 @@ fn populate_wasm_info( fn parse_export_section( export_section: ExportSectionReader, function_names: &mut HashMap, + view_endpoints: Vec, ) { for export in export_section { let export = export.expect("Failed to read export section"); if let wasmparser::ExternalKind::Func = export.kind { - if export.name.to_string().ends_with("__view") { + if view_endpoints.contains(&export.name.to_string()) { function_names.insert(export.index, export.name.to_string()); } } From 22ea5901960d2c0905476aed63aac42fb211cc90 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Thu, 29 Aug 2024 21:08:08 +0300 Subject: [PATCH 04/28] write op detect - revert contracts --- .../benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs | 6 +++--- contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs | 4 ++-- contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs | 4 ++-- contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs index 9e22454e98..1e79aa533a 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/linked-list-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench___view => bench - add_struct___view => add_struct + bench => bench + add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct___view => bench_struct + bench_struct => bench_struct ) } diff --git a/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs index c254f43e57..887fb0c6e6 100644 --- a/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/queue-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench___view => bench + bench => bench add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct___view => bench_struct + bench_struct => bench_struct ) } diff --git a/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs index 79d7ac9f8a..7a1a61db74 100644 --- a/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/set-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench___view => bench + bench => bench add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct___view => bench_struct + bench_struct => bench_struct ) } diff --git a/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs b/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs index 4a56536d8a..6f915470d8 100644 --- a/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs +++ b/contracts/benchmarks/mappers/vec-repeat/wasm/src/lib.rs @@ -21,11 +21,11 @@ multiversx_sc_wasm_adapter::endpoints! { add => add count => count remove => remove - bench___view => bench + bench => bench add_struct => add_struct count_struct => count_struct remove_struct => remove_struct - bench_struct___view => bench_struct + bench_struct => bench_struct ) } From 7515c2f308ccf218e76ca0d302c4560bbd3c24cb Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Tue, 10 Sep 2024 18:47:50 +0300 Subject: [PATCH 05/28] detect write in storage in view endpoint --- .../meta-lib/src/tools/wasm_extractor.rs | 123 ++++++++++-------- 1 file changed, 69 insertions(+), 54 deletions(-) diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index fa466440da..a348a40e30 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -1,5 +1,8 @@ use colored::Colorize; -use std::{collections::HashMap, fs}; +use std::{ + collections::{HashMap, HashSet}, + fs, +}; use wasmparser::{ BinaryReaderError, DataSectionReader, ExportSectionReader, FunctionBody, ImportSectionReader, Operator, Parser, Payload, @@ -55,19 +58,24 @@ fn populate_wasm_info( let mut ei_check = false; let mut memory_grow_flag = false; let mut has_panic = "none"; - let mut function_names: HashMap = HashMap::new(); - let mut read_functions: Vec = Vec::new(); + let mut call_graph: HashMap> = HashMap::new(); + let mut views_data: HashMap = HashMap::new(); + let mut write_functions: Vec = Vec::new(); let mut parser = Parser::new(0); for payload in parser.parse_all(&wasm_data) { match payload? { Payload::ImportSection(import_section) => { - imports = - extract_imports(import_section, extract_imports_enabled, &mut read_functions); - ei_check = is_ei_valid(imports.clone(), check_ei); + imports = extract_imports( + import_section, + extract_imports_enabled, + &mut call_graph, + &mut write_functions, + ); + ei_check = is_ei_valid(&imports, check_ei); }, Payload::DataSection(data_section) => { - allocator_trigger = is_fail_allocator_triggered(data_section.clone()); + allocator_trigger = is_fail_allocator_triggered(&data_section); if is_panic_with_message_triggered(data_section.clone()) { has_panic = WITH_MESSAGE; } else if is_panic_without_message_triggered(data_section) { @@ -75,10 +83,10 @@ fn populate_wasm_info( } }, Payload::CodeSectionEntry(code_section) => { - memory_grow_flag = is_mem_grow(code_section.clone()); + memory_grow_flag = is_mem_grow(&code_section); }, Payload::ExportSection(export_section) => { - parse_export_section(export_section, &mut function_names, view_endpoints.clone()); + views_data = parse_export_section(export_section, &view_endpoints); }, _ => (), } @@ -87,13 +95,16 @@ fn populate_wasm_info( parser = Parser::new(0); for payload in parser.parse_all(&wasm_data) { if let Payload::CodeSectionEntry(body) = payload? { - analyze_function_body(body, &mut read_functions); + create_call_graph(body, &mut call_graph); } } + let mut visited: HashSet = HashSet::new(); + for (index, _name) in &views_data { + mark_write(*index, &call_graph, &mut write_functions, &mut visited); + } - for (index, name) in function_names { - let i: usize = index.try_into().unwrap(); - if !read_functions[i] { + for (index, name) in views_data { + if write_functions.contains(&index) { println!( "{} {}", "Write storage operation in VIEW endpoint:" @@ -122,64 +133,68 @@ fn populate_wasm_info( fn parse_export_section( export_section: ExportSectionReader, - function_names: &mut HashMap, - view_endpoints: Vec, -) { + view_endpoints: &Vec, +) -> HashMap { + let mut views_data: HashMap = HashMap::new(); for export in export_section { let export = export.expect("Failed to read export section"); if let wasmparser::ExternalKind::Func = export.kind { if view_endpoints.contains(&export.name.to_string()) { - function_names.insert(export.index, export.name.to_string()); + views_data.insert(export.index.try_into().unwrap(), export.name.to_string()); + } + } + } + views_data +} + +fn mark_write( + func: usize, + call_graph: &HashMap>, + write_functions: &mut Vec, + visited: &mut HashSet, +) { + // Return early to prevent cycles. + if visited.contains(&func) { + return; + } + + visited.insert(func); + + if let Some(callees) = call_graph.get(&func) { + for &callee in callees { + if write_functions.contains(&callee) { + write_functions.push(func); + } else { + mark_write(callee, call_graph, write_functions, visited); + if write_functions.contains(&callee) { + write_functions.push(func); + } } } } } -fn analyze_function_body(body: FunctionBody, functions: &mut Vec) { - // Implement your function body analysis here - // For example, you can parse the locals and instructions - // let locals_reader = body - // .get_locals_reader() - // .expect("Failed to get locals reader"); +fn create_call_graph(body: FunctionBody, call_graph: &mut HashMap>) { let mut instructions_reader = body .get_operators_reader() .expect("Failed to get operators reader"); - // println!("Function has {} locals", locals_reader.get_count()); - - let mut value = true; + let mut call_functions = Vec::new(); while let Ok(op) = instructions_reader.read() { match op { Operator::Call { function_index } => { let function_usize: usize = function_index.try_into().unwrap(); - if function_usize >= functions.len() { - functions.push(true); - return; - } - - value &= functions[function_usize]; - - if !value { - functions.push(value); - return; - } - }, - Operator::I32Load { memarg } => { - if memarg.offset > 0 { - functions.push(false); - return; - } + call_functions.push(function_usize); }, _ => (), } } - functions.push(value); - // println!("===================="); + call_graph.insert(call_graph.len(), call_functions); } -fn is_fail_allocator_triggered(data_section: DataSectionReader) -> bool { - for data_fragment in data_section.into_iter().flatten() { +fn is_fail_allocator_triggered(data_section: &DataSectionReader) -> bool { + for data_fragment in data_section.clone().into_iter().flatten() { if data_fragment .data .windows(ERROR_FAIL_ALLOCATOR.len()) @@ -230,19 +245,19 @@ fn is_panic_without_message_triggered(data_section: DataSectionReader) -> bool { pub fn extract_imports( import_section: ImportSectionReader, import_extraction_enabled: bool, - write_or_read_functions: &mut Vec, + call_graph: &mut HashMap>, + write_functions: &mut Vec, ) -> Vec { if !import_extraction_enabled { return Vec::new(); } let mut import_names = Vec::new(); - for import in import_section.into_iter().flatten() { + for (index, import) in import_section.into_iter().flatten().enumerate() { import_names.push(import.name.to_string()); + call_graph.insert(index, vec![]); if WRITE_OP.contains(&import.name) { - write_or_read_functions.push(false); - } else { - write_or_read_functions.push(true); + write_functions.push(index); } } @@ -251,7 +266,7 @@ pub fn extract_imports( import_names } -fn is_ei_valid(imports: Vec, check_ei: &Option) -> bool { +fn is_ei_valid(imports: &Vec, check_ei: &Option) -> bool { if let Some(ei) = check_ei { let mut num_errors = 0; for import in imports { @@ -268,7 +283,7 @@ fn is_ei_valid(imports: Vec, check_ei: &Option) -> bool { false } -fn is_mem_grow(code_section: FunctionBody) -> bool { +fn is_mem_grow(code_section: &FunctionBody) -> bool { let mut code = code_section.get_binary_reader(); while code.bytes_remaining() > 0 { if code.read_u8().unwrap() == MEMORY_GROW_OPCODE { From e166376c5d1bf468e69c36b49261fe4f26173525 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Thu, 12 Sep 2024 18:39:05 +0300 Subject: [PATCH 06/28] detect write op in view storage - cleanup --- .../mappers/linked-list-repeat/file.txt | 2150 ----------------- .../src/linked_list_repeat.rs | 6 +- contracts/examples/adder/src/adder.rs | 2 +- .../src/parse/attributes/endpoint_attr.rs | 2 +- 4 files changed, 4 insertions(+), 2156 deletions(-) delete mode 100644 contracts/benchmarks/mappers/linked-list-repeat/file.txt diff --git a/contracts/benchmarks/mappers/linked-list-repeat/file.txt b/contracts/benchmarks/mappers/linked-list-repeat/file.txt deleted file mode 100644 index 799122fd71..0000000000 --- a/contracts/benchmarks/mappers/linked-list-repeat/file.txt +++ /dev/null @@ -1,2150 +0,0 @@ - /home/bibi/Desktop/mx-sdk-rs/contracts/benchmarks/mappers/linked-list-repeat - -Found 1 contract crates. - -(1/1) -In /home/bibi/Desktop/mx-sdk-rs/contracts/benchmarks/mappers/linked-list-repeat/meta -Calling `cargo run build` -Using workspace target directory: /home/bibi/Desktop/mx-sdk-rs/target ... -Building linked-list-repeat.wasm in /home/bibi/Desktop/mx-sdk-rs/contracts/benchmarks/mappers/linked-list-repeat/wasm ... -RUSTFLAGS="-C link-arg=-s -C link-arg=-zstack-size=131072" cargo build --target=wasm32-unknown-unknown --release --target-dir /home/bibi/Desktop/mx-sdk-rs/target -Copying /home/bibi/Desktop/mx-sdk-rs/target/wasm32-unknown-unknown/release/linked_list_repeat_wasm.wasm to ../output/linked-list-repeat.wasm ... -Calling wasm-opt on ../output/linked-list-repeat.wasm ... -Extracting imports to ../output/linked-list-repeat.imports.json ... -FailAllocator used while memory allocation is accessible in code. Contract may fail unexpectedly when memory allocation is attempted -Instruction: Call { function_index: 24 } -Call instruction: calls function index 24 -Instruction: I32Const { value: 131268 } -Instruction: I32Const { value: 131268 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: I32Const { value: 1 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: End -Instruction: Call { function_index: 2 } -Call instruction: calls function index 2 -Instruction: LocalTee { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 3 } -Call instruction: calls function index 3 -Instruction: Drop -Instruction: LocalGet { local_index: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 4 } -Call instruction: calls function index 4 -Instruction: I32Const { value: 0 } -Instruction: I32GtS -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 96 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Eqz -Instruction: If { blockty: Type(I64) } -Instruction: I64Const { value: 0 } -Instruction: Else -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: Call { function_index: 28 } -Call instruction: calls function index 28 -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: Call { function_index: 25 } -Call instruction: calls function index 25 -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } -Instruction: Call { function_index: 23 } -Call instruction: calls function index 23 -Instruction: LocalSet { local_index: 3 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } -Instruction: Call { function_index: 25 } -Call instruction: calls function index 25 -Instruction: LocalSet { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } -Instruction: LocalSet { local_index: 6 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } -Instruction: Call { function_index: 23 } -Call instruction: calls function index 23 -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 5 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 6 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 3 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 66 } -Call instruction: calls function index 66 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: If { blockty: Type(I32) } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: Call { function_index: 25 } -Call instruction: calls function index 25 -Instruction: LocalSet { local_index: 3 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: LocalTee { local_index: 6 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalSet { local_index: 7 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalTee { local_index: 8 } -Instruction: Call { function_index: 31 } -Call instruction: calls function index 31 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 3 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 66 } -Call instruction: calls function index 66 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 33 } -Call instruction: calls function index 33 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 1 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: I32Const { value: 4 } -Instruction: Call { function_index: 47 } -Call instruction: calls function index 47 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 24 } -Call instruction: calls function index 24 -Instruction: LocalTee { local_index: 0 } -Instruction: Call { function_index: 17 } -Call instruction: calls function index 17 -Instruction: Drop -Instruction: LocalGet { local_index: 0 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 36 } -Call instruction: calls function index 36 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 1 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: Call { function_index: 24 } -Call instruction: calls function index 24 -Instruction: LocalTee { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 5 } -Call instruction: calls function index 5 -Instruction: Drop -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 38 } -Call instruction: calls function index 38 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 7 } -Call instruction: calls function index 7 -Instruction: LocalTee { local_index: 3 } -Instruction: I32Const { value: 24 } -Instruction: I32Shl -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: I32Const { value: 8 } -Instruction: I32Shl -Instruction: I32Or -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 8 } -Instruction: I32ShrU -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 24 } -Instruction: I32ShrU -Instruction: I32Or -Instruction: I32Or -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: I32Const { value: 4 } -Instruction: Call { function_index: 73 } -Call instruction: calls function index 73 -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 24 } -Call instruction: calls function index 24 -Instruction: LocalTee { local_index: 1 } -Instruction: Call { function_index: 6 } -Call instruction: calls function index 6 -Instruction: Drop -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 7 } -Call instruction: calls function index 7 -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 0 } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 24 } -Call instruction: calls function index 24 -Instruction: LocalTee { local_index: 0 } -Instruction: Call { function_index: 8 } -Call instruction: calls function index 8 -Instruction: Drop -Instruction: LocalGet { local_index: 0 } -Instruction: End -Instruction: I32Const { value: 131086 } -Instruction: I32Const { value: 23 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: Call { function_index: 24 } -Call instruction: calls function index 24 -Instruction: LocalTee { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 16 } -Call instruction: calls function index 16 -Instruction: Drop -Instruction: LocalGet { local_index: 2 } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 40 } -Call instruction: calls function index 40 -Instruction: LocalTee { local_index: 3 } -Instruction: Call { function_index: 7 } -Call instruction: calls function index 7 -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 0 } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 28, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: LocalTee { local_index: 3 } -Instruction: Call { function_index: 33 } -Call instruction: calls function index 33 -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 44 } -Call instruction: calls function index 44 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I64Const { value: 0 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: I32Const { value: 8 } -Instruction: Call { function_index: 47 } -Call instruction: calls function index 47 -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 11 } -Call instruction: calls function index 11 -Instruction: LocalTee { local_index: 0 } -Instruction: I64Const { value: 4294967296 } -Instruction: I64GeU -Instruction: If { blockty: Empty } -Instruction: I32Const { value: 131189 } -Instruction: I32Const { value: 11 } -Instruction: I32Const { value: 131072 } -Instruction: I32Const { value: 14 } -Instruction: Call { function_index: 41 } -Call instruction: calls function index 41 -Instruction: Unreachable -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32WrapI64 -Instruction: End -Instruction: Call { function_index: 12 } -Call instruction: calls function index 12 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Eq -Instruction: If { blockty: Empty } -Instruction: Return -Instruction: End -Instruction: I32Const { value: 131112 } -Instruction: I32Const { value: 25 } -Instruction: Call { function_index: 13 } -Call instruction: calls function index 13 -Instruction: Unreachable -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 53 } -Call instruction: calls function index 53 -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 2 } -Call instruction: calls function index 2 -Instruction: LocalTee { local_index: 1 } -Instruction: Call { function_index: 18 } -Call instruction: calls function index 18 -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Eqz -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 1 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: I32Const { value: 4 } -Instruction: Call { function_index: 74 } -Call instruction: calls function index 74 -Instruction: I32Const { value: 131162 } -Instruction: I32Const { value: 22 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: LocalTee { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 9 } -Call instruction: calls function index 9 -Instruction: Drop -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 10 } -Call instruction: calls function index 10 -Instruction: Unreachable -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 14 } -Call instruction: calls function index 14 -Instruction: I32Eqz -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 15 } -Call instruction: calls function index 15 -Instruction: I32Const { value: 0 } -Instruction: I32Ne -Instruction: End -Instruction: Block { blockty: Empty } -Instruction: Block { blockty: Empty } -Instruction: Block { blockty: Type(I32) } -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 8, memory: 0 } } -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalTee { local_index: 4 } -Instruction: Call { function_index: 7 } -Call instruction: calls function index 7 -Instruction: LocalTee { local_index: 5 } -Instruction: I32Const { value: 10000 } -Instruction: I32GtU -Instruction: BrIf { relative_depth: 1 } -Instruction: I32Const { value: 141276 } -Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: BrIf { relative_depth: 1 } -Instruction: I32Const { value: 141272 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: I32Const { value: 141276 } -Instruction: I32Const { value: 1 } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Const { value: 0 } -Instruction: I32Const { value: 131272 } -Instruction: LocalGet { local_index: 5 } -Instruction: Call { function_index: 52 } -Call instruction: calls function index 52 -Instruction: Drop -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 1 } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 8, memory: 0 } } -Instruction: End -Instruction: I32Const { value: 1 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Add -Instruction: LocalTee { local_index: 0 } -Instruction: I32Const { value: 141272 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: I32GtU -Instruction: BrIf { relative_depth: 1 } -Instruction: Drop -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32LtU -Instruction: BrIf { relative_depth: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 10000 } -Instruction: I32GtU -Instruction: BrIf { relative_depth: 3 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 131272 } -Instruction: I32Add -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 89 } -Call instruction: calls function index 89 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: -25 } -Instruction: Call { function_index: 6 } -Call instruction: calls function index 6 -Instruction: Drop -Instruction: I32Const { value: -25 } -Instruction: Call { function_index: 7 } -Call instruction: calls function index 7 -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 56 } -Call instruction: calls function index 56 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: Call { function_index: 19 } -Call instruction: calls function index 19 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 58 } -Call instruction: calls function index 58 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 25 } -Call instruction: calls function index 25 -Instruction: LocalTee { local_index: 0 } -Instruction: I32Const { value: 131157 } -Instruction: I32Const { value: 5 } -Instruction: Call { function_index: 9 } -Call instruction: calls function index 9 -Instruction: Drop -Instruction: LocalGet { local_index: 0 } -Instruction: End -Instruction: I32Const { value: 131224 } -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 24 } -Instruction: I32Shl -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: I32Const { value: 8 } -Instruction: I32Shl -Instruction: I32Or -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32ShrU -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 24 } -Instruction: I32ShrU -Instruction: I32Or -Instruction: I32Or -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: I32Const { value: 4 } -Instruction: Call { function_index: 73 } -Call instruction: calls function index 73 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 19 } -Call instruction: calls function index 19 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 25 } -Call instruction: calls function index 25 -Instruction: LocalTee { local_index: 0 } -Instruction: I32Const { value: 131152 } -Instruction: I32Const { value: 5 } -Instruction: Call { function_index: 9 } -Call instruction: calls function index 9 -Instruction: Drop -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 24 } -Instruction: I32Shl -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: I32Const { value: 8 } -Instruction: I32Shl -Instruction: I32Or -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 8 } -Instruction: I32ShrU -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 24 } -Instruction: I32ShrU -Instruction: I32Or -Instruction: I32Or -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: I32Const { value: 4 } -Instruction: Call { function_index: 9 } -Call instruction: calls function index 9 -Instruction: Drop -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: Call { function_index: 59 } -Call instruction: calls function index 59 -Instruction: LocalSet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 38 } -Call instruction: calls function index 38 -Instruction: LocalGet { local_index: 2 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 65 } -Call instruction: calls function index 65 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 56 } -Instruction: I64Shl -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 65280 } -Instruction: I64And -Instruction: I64Const { value: 40 } -Instruction: I64Shl -Instruction: I64Or -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 16711680 } -Instruction: I64And -Instruction: I64Const { value: 24 } -Instruction: I64Shl -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 4278190080 } -Instruction: I64And -Instruction: I64Const { value: 8 } -Instruction: I64Shl -Instruction: I64Or -Instruction: I64Or -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 8 } -Instruction: I64ShrU -Instruction: I64Const { value: 4278190080 } -Instruction: I64And -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 24 } -Instruction: I64ShrU -Instruction: I64Const { value: 16711680 } -Instruction: I64And -Instruction: I64Or -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 40 } -Instruction: I64ShrU -Instruction: I64Const { value: 65280 } -Instruction: I64And -Instruction: LocalGet { local_index: 0 } -Instruction: I64Const { value: 56 } -Instruction: I64ShrU -Instruction: I64Or -Instruction: I64Or -Instruction: I64Or -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: I32Const { value: 8 } -Instruction: Call { function_index: 73 } -Call instruction: calls function index 73 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: Call { function_index: 54 } -Call instruction: calls function index 54 -Instruction: I32Eqz -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 3 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: Call { function_index: 39 } -Call instruction: calls function index 39 -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 36 } -Call instruction: calls function index 36 -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 4 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: I32Eq -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 28, memory: 0 } } -Instruction: If { blockty: Empty } -Instruction: I32Const { value: 141272 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: I32Const { value: 141276 } -Instruction: I32Const { value: 0 } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 32 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: Return -Instruction: End -Instruction: I32Const { value: 131072 } -Instruction: I32Const { value: 14 } -Instruction: Call { function_index: 50 } -Call instruction: calls function index 50 -Instruction: Unreachable -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 3 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: Call { function_index: 39 } -Call instruction: calls function index 39 -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 36 } -Call instruction: calls function index 36 -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 72 } -Call instruction: calls function index 72 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 32 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalTee { local_index: 3 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Block { blockty: Empty } -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 58 } -Call instruction: calls function index 58 -Instruction: LocalTee { local_index: 1 } -Instruction: Call { function_index: 54 } -Call instruction: calls function index 54 -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: I32Const { value: 0 } -Instruction: LocalSet { local_index: 1 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: LocalTee { local_index: 3 } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 39 } -Call instruction: calls function index 39 -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 3 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 4 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: Call { function_index: 49 } -Call instruction: calls function index 49 -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: I32Ne -Instruction: BrIf { relative_depth: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 28, memory: 0 } } -Instruction: I32Eqz -Instruction: BrIf { relative_depth: 0 } -Instruction: I32Const { value: 141272 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: I32Const { value: 141276 } -Instruction: I32Const { value: 0 } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 32 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: Return -Instruction: End -Instruction: I32Const { value: 131072 } -Instruction: I32Const { value: 14 } -Instruction: Call { function_index: 50 } -Call instruction: calls function index 50 -Instruction: Unreachable -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 80 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: -64 } -Instruction: I32Sub -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalTee { local_index: 3 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 68, memory: 0 } } -Instruction: Call { function_index: 29 } -Call instruction: calls function index 29 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Const { value: 56 } -Instruction: Call { function_index: 89 } -Call instruction: calls function index 89 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 2 } -Instruction: GlobalSet { global_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I64Const { value: 0 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: I32Const { value: 8 } -Instruction: Call { function_index: 74 } -Call instruction: calls function index 74 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 9 } -Call instruction: calls function index 9 -Instruction: Drop -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 53 } -Call instruction: calls function index 53 -Instruction: If { blockty: Empty } -Instruction: I32Const { value: 131137 } -Instruction: I32Const { value: 15 } -Instruction: Call { function_index: 50 } -Call instruction: calls function index 50 -Instruction: Unreachable -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Add -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: End -Instruction: I32Const { value: 131200 } -Instruction: I32Const { value: 12 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: End -Instruction: I32Const { value: 131212 } -Instruction: I32Const { value: 9 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: End -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 2 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: Call { function_index: 45 } -Call instruction: calls function index 45 -Instruction: LocalSet { local_index: 6 } -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 40 } -Call instruction: calls function index 40 -Instruction: LocalSet { local_index: 7 } -Instruction: Call { function_index: 76 } -Call instruction: calls function index 76 -Instruction: LocalSet { local_index: 2 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 6 } -Instruction: I32Ne -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 7 } -Instruction: Call { function_index: 25 } -Call instruction: calls function index 25 -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 24 } -Instruction: I32Shl -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: I32Const { value: 8 } -Instruction: I32Shl -Instruction: I32Or -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 8 } -Instruction: I32ShrU -Instruction: I32Const { value: 65280 } -Instruction: I32And -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 24 } -Instruction: I32ShrU -Instruction: I32Or -Instruction: I32Or -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 5 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: I32Const { value: 4 } -Instruction: Call { function_index: 9 } -Call instruction: calls function index 9 -Instruction: Drop -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalTee { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalTee { local_index: 8 } -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: I32Const { value: 0 } -Instruction: LocalSet { local_index: 4 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: LocalTee { local_index: 9 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } -Instruction: LocalTee { local_index: 4 } -Instruction: Call { function_index: 67 } -Call instruction: calls function index 67 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 4 } -Instruction: LocalGet { local_index: 9 } -Instruction: Call { function_index: 62 } -Call instruction: calls function index 62 -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: Call { function_index: 62 } -Call instruction: calls function index 62 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 8 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 8, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 57 } -Call instruction: calls function index 57 -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: -64 } -Instruction: I32Add -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 40 } -Call instruction: calls function index 40 -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 76 } -Call instruction: calls function index 76 -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: Call { function_index: 69 } -Call instruction: calls function index 69 -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 44 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: Call { function_index: 30 } -Call instruction: calls function index 30 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 44, memory: 0 } } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 48, memory: 0 } } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 26 } -Call instruction: calls function index 26 -Instruction: LocalGet { local_index: 1 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 1 } -Instruction: I64ExtendI32U -Instruction: Call { function_index: 21 } -Call instruction: calls function index 21 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: -64 } -Instruction: I32Sub -Instruction: GlobalSet { global_index: 0 } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: -64 } -Instruction: I32Add -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: Call { function_index: 45 } -Call instruction: calls function index 45 -Instruction: LocalSet { local_index: 5 } -Instruction: Call { function_index: 76 } -Call instruction: calls function index 76 -Instruction: LocalSet { local_index: 1 } -Instruction: Block { blockty: Empty } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 5 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 12 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalTee { local_index: 2 } -Instruction: Call { function_index: 66 } -Call instruction: calls function index 66 -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 28 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 31 } -Call instruction: calls function index 31 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } -Instruction: I32Eqz -Instruction: BrIf { relative_depth: 3 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 44, memory: 0 } } -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 40, memory: 0 } } -Instruction: LocalSet { local_index: 3 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 36, memory: 0 } } -Instruction: LocalTee { local_index: 6 } -Instruction: Call { function_index: 66 } -Call instruction: calls function index 66 -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 2 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 67 } -Call instruction: calls function index 67 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 36, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 62 } -Call instruction: calls function index 62 -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 52, memory: 0 } } -Instruction: End -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 3 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 28 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 67 } -Call instruction: calls function index 67 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 40, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 62 } -Call instruction: calls function index 62 -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 56, memory: 0 } } -Instruction: End -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 6 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: Call { function_index: 55 } -Call instruction: calls function index 55 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 48, memory: 0 } } -Instruction: I32Const { value: 1 } -Instruction: I32Sub -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 48, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Add -Instruction: Call { function_index: 57 } -Call instruction: calls function index 57 -Instruction: End -Instruction: LocalGet { local_index: 5 } -Instruction: I32Const { value: 1 } -Instruction: I32Sub -Instruction: LocalSet { local_index: 5 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: -64 } -Instruction: I32Sub -Instruction: GlobalSet { global_index: 0 } -Instruction: Return -Instruction: End -Instruction: Call { function_index: 81 } -Call instruction: calls function index 81 -Instruction: Call { function_index: 88 } -Call instruction: calls function index 88 -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 76 } -Call instruction: calls function index 76 -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 69 } -Call instruction: calls function index 69 -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 28 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: Call { function_index: 30 } -Call instruction: calls function index 30 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 32, memory: 0 } } -Instruction: Call { function_index: 22 } -Call instruction: calls function index 22 -Instruction: Drop -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 128 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 2 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: Call { function_index: 45 } -Call instruction: calls function index 45 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 32 } -Instruction: I32Add -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 43 } -Call instruction: calls function index 43 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 108 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 56 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalTee { local_index: 11 } -Instruction: I64Store { memarg: MemArg { align: 2, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 40 } -Instruction: I32Add -Instruction: LocalTee { local_index: 5 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 16 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 48 } -Instruction: I32Add -Instruction: LocalTee { local_index: 6 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 24 } -Instruction: I32Add -Instruction: LocalGet { local_index: 11 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 32, memory: 0 } } -Instruction: LocalTee { local_index: 11 } -Instruction: I64Store { memarg: MemArg { align: 2, max_align: 3, offset: 84, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 11 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64ExtendI32U -Instruction: LocalSet { local_index: 12 } -Instruction: I64Const { value: 0 } -Instruction: LocalSet { local_index: 11 } -Instruction: Call { function_index: 75 } -Call instruction: calls function index 75 -Instruction: LocalSet { local_index: 1 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 11 } -Instruction: LocalGet { local_index: 12 } -Instruction: I64Eq -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 80 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 28 } -Call instruction: calls function index 28 -Instruction: LocalGet { local_index: 5 } -Instruction: LocalGet { local_index: 11 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 6 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 96 } -Instruction: I32Add -Instruction: LocalTee { local_index: 7 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 4 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 104 } -Instruction: I32Add -Instruction: LocalTee { local_index: 8 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 11 } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 32, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: -64 } -Instruction: I32Sub -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 76, memory: 0 } } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalTee { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 76, memory: 0 } } -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } -Instruction: LocalTee { local_index: 9 } -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 68, memory: 0 } } -Instruction: I32Const { value: 0 } -Instruction: LocalSet { local_index: 3 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 80 } -Instruction: I32Add -Instruction: LocalTee { local_index: 10 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 72, memory: 0 } } -Instruction: LocalTee { local_index: 3 } -Instruction: Call { function_index: 68 } -Call instruction: calls function index 68 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 116, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 10 } -Instruction: Call { function_index: 64 } -Call instruction: calls function index 64 -Instruction: End -Instruction: LocalGet { local_index: 8 } -Instruction: LocalGet { local_index: 4 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 7 } -Instruction: LocalGet { local_index: 6 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 88 } -Instruction: I32Add -Instruction: LocalGet { local_index: 5 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 32, memory: 0 } } -Instruction: I64Store { memarg: MemArg { align: 3, max_align: 3, offset: 80, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 120, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 0 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 116, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 112, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 80 } -Instruction: I32Add -Instruction: Call { function_index: 64 } -Call instruction: calls function index 64 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 9 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 72, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: -64 } -Instruction: I32Sub -Instruction: Call { function_index: 57 } -Call instruction: calls function index 57 -Instruction: LocalGet { local_index: 11 } -Instruction: I64Const { value: 1 } -Instruction: I64Add -Instruction: LocalSet { local_index: 11 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 128 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 160 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 43 } -Call instruction: calls function index 43 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 75 } -Call instruction: calls function index 75 -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 36, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 40 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 36 } -Instruction: I32Add -Instruction: Call { function_index: 71 } -Call instruction: calls function index 71 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 28, memory: 0 } } -Instruction: LocalSet { local_index: 3 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 24, memory: 0 } } -Instruction: LocalSet { local_index: 4 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 20, memory: 0 } } -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 16, memory: 0 } } -Instruction: LocalSet { local_index: 6 } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 8, memory: 0 } } -Instruction: LocalSet { local_index: 10 } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 0, memory: 0 } } -Instruction: LocalSet { local_index: 11 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 104 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 40 } -Instruction: I32Add -Instruction: Call { function_index: 27 } -Call instruction: calls function index 27 -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 104, memory: 0 } } -Instruction: I64Eqz -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 112, memory: 0 } } -Instruction: LocalSet { local_index: 12 } -Instruction: I32Const { value: 0 } -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 140, memory: 0 } } -Instruction: LocalSet { local_index: 7 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 136, memory: 0 } } -Instruction: LocalSet { local_index: 8 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 132, memory: 0 } } -Instruction: LocalSet { local_index: 9 } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 120, memory: 0 } } -Instruction: LocalSet { local_index: 13 } -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 128, memory: 0 } } -Instruction: LocalGet { local_index: 6 } -Instruction: Call { function_index: 26 } -Call instruction: calls function index 26 -Instruction: I32Eqz -Instruction: LocalGet { local_index: 11 } -Instruction: LocalGet { local_index: 12 } -Instruction: I64Ne -Instruction: I32Or -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 9 } -Instruction: LocalGet { local_index: 5 } -Instruction: Call { function_index: 51 } -Call instruction: calls function index 51 -Instruction: I32Eqz -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 8 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 26 } -Call instruction: calls function index 26 -Instruction: I32Eqz -Instruction: LocalGet { local_index: 10 } -Instruction: LocalGet { local_index: 13 } -Instruction: I64Ne -Instruction: I32Or -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 7 } -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 51 } -Call instruction: calls function index 51 -Instruction: LocalSet { local_index: 2 } -Instruction: End -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 1 } -Instruction: I64ExtendI32U -Instruction: Call { function_index: 21 } -Call instruction: calls function index 21 -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 160 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 96 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 1 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: Call { function_index: 45 } -Call instruction: calls function index 45 -Instruction: LocalSet { local_index: 5 } -Instruction: Call { function_index: 75 } -Call instruction: calls function index 75 -Instruction: LocalSet { local_index: 1 } -Instruction: Block { blockty: Empty } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 5 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 12, memory: 0 } } -Instruction: LocalTee { local_index: 2 } -Instruction: Call { function_index: 66 } -Call instruction: calls function index 66 -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 24 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 29 } -Call instruction: calls function index 29 -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 24, memory: 0 } } -Instruction: I64Eqz -Instruction: BrIf { relative_depth: 3 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 72, memory: 0 } } -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 68, memory: 0 } } -Instruction: LocalSet { local_index: 3 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } -Instruction: LocalTee { local_index: 6 } -Instruction: Call { function_index: 66 } -Call instruction: calls function index 66 -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 80 } -Instruction: I32Add -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 70 } -Call instruction: calls function index 70 -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 2 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: Call { function_index: 68 } -Call instruction: calls function index 68 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 60, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 64 } -Call instruction: calls function index 64 -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 84, memory: 0 } } -Instruction: End -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 3 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 24 } -Instruction: I32Add -Instruction: LocalTee { local_index: 4 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: Call { function_index: 68 } -Call instruction: calls function index 68 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 64, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 4 } -Instruction: Call { function_index: 64 } -Call instruction: calls function index 64 -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 88, memory: 0 } } -Instruction: End -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 6 } -Instruction: Call { function_index: 63 } -Call instruction: calls function index 63 -Instruction: Call { function_index: 55 } -Call instruction: calls function index 55 -Instruction: LocalGet { local_index: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 80, memory: 0 } } -Instruction: I32Const { value: 1 } -Instruction: I32Sub -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 80, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 80 } -Instruction: I32Add -Instruction: Call { function_index: 57 } -Call instruction: calls function index 57 -Instruction: End -Instruction: LocalGet { local_index: 5 } -Instruction: I32Const { value: 1 } -Instruction: I32Sub -Instruction: LocalSet { local_index: 5 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 96 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: Return -Instruction: End -Instruction: Call { function_index: 81 } -Call instruction: calls function index 81 -Instruction: Unreachable -Instruction: End -Instruction: GlobalGet { global_index: 0 } -Instruction: I32Const { value: 128 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 0 } -Instruction: GlobalSet { global_index: 0 } -Instruction: Call { function_index: 20 } -Call instruction: calls function index 20 -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 46 } -Call instruction: calls function index 46 -Instruction: LocalGet { local_index: 0 } -Instruction: Call { function_index: 75 } -Call instruction: calls function index 75 -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 4, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: Call { function_index: 71 } -Call instruction: calls function index 71 -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 72 } -Instruction: I32Add -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 8 } -Instruction: I32Add -Instruction: Call { function_index: 27 } -Call instruction: calls function index 27 -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 72, memory: 0 } } -Instruction: I64Eqz -Instruction: I32Eqz -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 108, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 88, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 104, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 100, memory: 0 } } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 96, memory: 0 } } -Instruction: I32Const { value: 131224 } -Instruction: I32Const { value: 0 } -Instruction: Call { function_index: 42 } -Call instruction: calls function index 42 -Instruction: LocalTee { local_index: 1 } -Instruction: Call { function_index: 38 } -Call instruction: calls function index 38 -Instruction: LocalGet { local_index: 0 } -Instruction: I64Load { memarg: MemArg { align: 3, max_align: 3, offset: 80, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 65 } -Call instruction: calls function index 65 -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 37 } -Call instruction: calls function index 37 -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 38 } -Call instruction: calls function index 38 -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 65 } -Call instruction: calls function index 65 -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 37 } -Call instruction: calls function index 37 -Instruction: LocalGet { local_index: 1 } -Instruction: Call { function_index: 22 } -Call instruction: calls function index 22 -Instruction: Drop -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 128 } -Instruction: I32Add -Instruction: GlobalSet { global_index: 0 } -Instruction: End -Instruction: End -Instruction: I32Const { value: 131224 } -Instruction: I32Const { value: 14 } -Instruction: Call { function_index: 13 } -Call instruction: calls function index 13 -Instruction: Unreachable -Instruction: End -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalTee { local_index: 4 } -Instruction: I32Const { value: 16 } -Instruction: I32LtU -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalSet { local_index: 2 } -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: I32Const { value: 0 } -Instruction: LocalGet { local_index: 0 } -Instruction: I32Sub -Instruction: I32Const { value: 3 } -Instruction: I32And -Instruction: LocalTee { local_index: 3 } -Instruction: I32Add -Instruction: LocalSet { local_index: 5 } -Instruction: LocalGet { local_index: 3 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 0 } -Instruction: LocalSet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalSet { local_index: 6 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 6 } -Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 6 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalSet { local_index: 6 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalTee { local_index: 2 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32LtU -Instruction: BrIf { relative_depth: 0 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 5 } -Instruction: LocalGet { local_index: 4 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Sub -Instruction: LocalTee { local_index: 8 } -Instruction: I32Const { value: -4 } -Instruction: I32And -Instruction: LocalTee { local_index: 7 } -Instruction: I32Add -Instruction: LocalSet { local_index: 2 } -Instruction: Block { blockty: Empty } -Instruction: LocalGet { local_index: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Add -Instruction: LocalTee { local_index: 3 } -Instruction: I32Const { value: 3 } -Instruction: I32And -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 7 } -Instruction: I32Const { value: 0 } -Instruction: I32LeS -Instruction: BrIf { relative_depth: 1 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: 3 } -Instruction: I32Shl -Instruction: LocalTee { local_index: 4 } -Instruction: I32Const { value: 24 } -Instruction: I32And -Instruction: LocalSet { local_index: 9 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32Const { value: -4 } -Instruction: I32And -Instruction: LocalTee { local_index: 6 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: I32Const { value: 0 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Sub -Instruction: I32Const { value: 24 } -Instruction: I32And -Instruction: LocalSet { local_index: 4 } -Instruction: LocalGet { local_index: 6 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalSet { local_index: 6 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 5 } -Instruction: LocalGet { local_index: 6 } -Instruction: LocalGet { local_index: 9 } -Instruction: I32ShrU -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalTee { local_index: 6 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Shl -Instruction: I32Or -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: LocalTee { local_index: 5 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32LtU -Instruction: BrIf { relative_depth: 0 } -Instruction: End -Instruction: Br { relative_depth: 1 } -Instruction: End -Instruction: LocalGet { local_index: 7 } -Instruction: I32Const { value: 0 } -Instruction: I32LeS -Instruction: BrIf { relative_depth: 0 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalSet { local_index: 1 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 5 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: I32Store { memarg: MemArg { align: 2, max_align: 2, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 5 } -Instruction: I32Const { value: 4 } -Instruction: I32Add -Instruction: LocalTee { local_index: 5 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32LtU -Instruction: BrIf { relative_depth: 0 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 8 } -Instruction: I32Const { value: 3 } -Instruction: I32And -Instruction: LocalSet { local_index: 4 } -Instruction: LocalGet { local_index: 3 } -Instruction: LocalGet { local_index: 7 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: End -Instruction: LocalGet { local_index: 4 } -Instruction: If { blockty: Empty } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 4 } -Instruction: I32Add -Instruction: LocalSet { local_index: 3 } -Instruction: Loop { blockty: Empty } -Instruction: LocalGet { local_index: 2 } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Load8U { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: I32Store8 { memarg: MemArg { align: 0, max_align: 0, offset: 0, memory: 0 } } -Instruction: LocalGet { local_index: 1 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalSet { local_index: 1 } -Instruction: LocalGet { local_index: 2 } -Instruction: I32Const { value: 1 } -Instruction: I32Add -Instruction: LocalTee { local_index: 2 } -Instruction: LocalGet { local_index: 3 } -Instruction: I32LtU -Instruction: BrIf { relative_depth: 0 } -Instruction: End -Instruction: End -Instruction: LocalGet { local_index: 0 } -Instruction: End -Checking EI version: 1.3 ... OK -Packing ../output/linked-list-repeat.mxsc.json ... -Contract size: 6615 bytes. -analyze this via wasm -analyze this via wasm diff --git a/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs b/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs index cc7d8959ff..40dfcba638 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs +++ b/contracts/benchmarks/mappers/linked-list-repeat/src/linked_list_repeat.rs @@ -1,9 +1,8 @@ #![no_std] -use benchmark_common::ExampleStruct; - multiversx_sc::imports!(); +use benchmark_common::ExampleStruct; pub mod linked_list_repeat_proxy; #[multiversx_sc::contract] @@ -39,8 +38,7 @@ pub trait LinkedListRepeat: benchmark_common::BenchmarkCommon { #[storage_mapper("benchmark")] fn bench(&self) -> LinkedListMapper; - #[view] - // #[endpoint] + #[endpoint] fn add_struct(&self, num_repeats: usize, value: ExampleStruct) { let mut bench = self.bench_struct(); for i in 0..num_repeats { diff --git a/contracts/examples/adder/src/adder.rs b/contracts/examples/adder/src/adder.rs index 77358e4b7b..307f4112f5 100644 --- a/contracts/examples/adder/src/adder.rs +++ b/contracts/examples/adder/src/adder.rs @@ -23,7 +23,7 @@ pub trait Adder { } /// Add desired amount to the storage variable. - #[view] + #[endpoint] fn add(&self, value: BigUint) { self.sum().update(|sum| *sum += value); } diff --git a/framework/derive/src/parse/attributes/endpoint_attr.rs b/framework/derive/src/parse/attributes/endpoint_attr.rs index 4b742f5116..678675b202 100644 --- a/framework/derive/src/parse/attributes/endpoint_attr.rs +++ b/framework/derive/src/parse/attributes/endpoint_attr.rs @@ -57,7 +57,7 @@ pub struct ViewAttribute { pub view_name: Option, } -impl ViewAttribute { +impl ViewAttribute { pub fn parse(attr: &syn::Attribute) -> Option { match is_attr_with_one_opt_token_tree_arg(attr, ATTR_VIEW) { None => None, From 9e9bba15bf5d4aa7ec1807be56a43a8e219048ee Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Fri, 13 Sep 2024 14:20:19 +0300 Subject: [PATCH 07/28] detect write op in view storage - fix clippy --- .../meta-lib/src/tools/wasm_extractor.rs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index a348a40e30..4cd80507d4 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -75,7 +75,7 @@ fn populate_wasm_info( ei_check = is_ei_valid(&imports, check_ei); }, Payload::DataSection(data_section) => { - allocator_trigger = is_fail_allocator_triggered(&data_section); + allocator_trigger = is_fail_allocator_triggered(data_section.clone()); if is_panic_with_message_triggered(data_section.clone()) { has_panic = WITH_MESSAGE; } else if is_panic_without_message_triggered(data_section) { @@ -99,8 +99,8 @@ fn populate_wasm_info( } } let mut visited: HashSet = HashSet::new(); - for (index, _name) in &views_data { - mark_write(*index, &call_graph, &mut write_functions, &mut visited); + for key in views_data.keys() { + mark_write(*key, &call_graph, &mut write_functions, &mut visited); } for (index, name) in views_data { @@ -133,7 +133,7 @@ fn populate_wasm_info( fn parse_export_section( export_section: ExportSectionReader, - view_endpoints: &Vec, + view_endpoints: &[String], ) -> HashMap { let mut views_data: HashMap = HashMap::new(); for export in export_section { @@ -181,20 +181,17 @@ fn create_call_graph(body: FunctionBody, call_graph: &mut HashMap { - let function_usize: usize = function_index.try_into().unwrap(); - call_functions.push(function_usize); - }, - _ => (), + if let Operator::Call { function_index } = op { + let function_usize: usize = function_index.try_into().unwrap(); + call_functions.push(function_usize); } } call_graph.insert(call_graph.len(), call_functions); } -fn is_fail_allocator_triggered(data_section: &DataSectionReader) -> bool { - for data_fragment in data_section.clone().into_iter().flatten() { +fn is_fail_allocator_triggered(data_section: DataSectionReader) -> bool { + for data_fragment in data_section.into_iter().flatten() { if data_fragment .data .windows(ERROR_FAIL_ALLOCATOR.len()) @@ -266,7 +263,7 @@ pub fn extract_imports( import_names } -fn is_ei_valid(imports: &Vec, check_ei: &Option) -> bool { +fn is_ei_valid(imports: &[String], check_ei: &Option) -> bool { if let Some(ei) = check_ei { let mut num_errors = 0; for import in imports { From d145b73eba13d4b2bb095ab10ae5fcc576c054bd Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Fri, 13 Sep 2024 19:11:46 +0300 Subject: [PATCH 08/28] detect write op in view storage - refactor: removed has_format, changed data structure for view_endpoints, impl default for WasmInfo and ReportCreator --- .../src/contract/sc_config/wasm_build.rs | 20 +-- .../meta-lib/src/tools/report_creator.rs | 10 ++ .../meta-lib/src/tools/wasm_extractor.rs | 143 ++++++++---------- 3 files changed, 83 insertions(+), 90 deletions(-) diff --git a/framework/meta-lib/src/contract/sc_config/wasm_build.rs b/framework/meta-lib/src/contract/sc_config/wasm_build.rs index e7a9bec5ed..4311bd0979 100644 --- a/framework/meta-lib/src/contract/sc_config/wasm_build.rs +++ b/framework/meta-lib/src/contract/sc_config/wasm_build.rs @@ -1,4 +1,4 @@ -use std::{ffi::OsStr, fs, process::Command}; +use std::{collections::HashMap, ffi::OsStr, fs, process::Command}; use super::ContractVariant; use crate::{ @@ -95,12 +95,8 @@ impl ContractVariant { let mut abi = ContractAbiJson::from(&self.abi); let mut view_endpoints = Vec::new(); for endpoint in &abi.endpoints { - match endpoint.mutability { - crate::abi_json::EndpointMutabilityAbiJson::Readonly => { - view_endpoints.push(&endpoint.name) - }, - crate::abi_json::EndpointMutabilityAbiJson::Mutable => (), - crate::abi_json::EndpointMutabilityAbiJson::Pure => (), + if let crate::abi_json::EndpointMutabilityAbiJson::Readonly = endpoint.mutability { + view_endpoints.push(&endpoint.name) } } let build_info = core::mem::take(&mut abi.build_info).unwrap(); @@ -141,14 +137,10 @@ impl ContractVariant { let output_wasm_path = format!("{output_path}/{}", self.wasm_output_name(build_args)); let abi = ContractAbiJson::from(&self.abi); - let mut view_endpoints = Vec::new(); + let mut view_endpoints: HashMap<&str, usize> = HashMap::new(); for endpoint in &abi.endpoints { - match endpoint.mutability { - crate::abi_json::EndpointMutabilityAbiJson::Readonly => { - view_endpoints.push(endpoint.name.clone()) - }, - crate::abi_json::EndpointMutabilityAbiJson::Mutable => (), - crate::abi_json::EndpointMutabilityAbiJson::Pure => (), + if let crate::abi_json::EndpointMutabilityAbiJson::Readonly = endpoint.mutability { + view_endpoints.insert(&endpoint.name, 0); } } diff --git a/framework/meta-lib/src/tools/report_creator.rs b/framework/meta-lib/src/tools/report_creator.rs index 37af10fa4e..60de81dc31 100644 --- a/framework/meta-lib/src/tools/report_creator.rs +++ b/framework/meta-lib/src/tools/report_creator.rs @@ -8,3 +8,13 @@ pub struct ReportCreator { } impl ReportCreator {} + +impl Default for ReportCreator { + fn default() -> Self { + ReportCreator { + path: String::new(), + has_allocator: false, + has_panic: "none".to_string(), + } + } +} diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index 4cd80507d4..63dad6b3ad 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -12,18 +12,21 @@ use crate::ei::EIVersion; use super::report_creator::{ReportCreator, WITHOUT_MESSAGE, WITH_MESSAGE}; +type CallGraph = HashMap>; + const PANIC_WITH_MESSAGE: &[u8; 16] = b"panic occurred: "; const PANIC_WITHOUT_MESSAGE: &[u8; 14] = b"panic occurred"; const ERROR_FAIL_ALLOCATOR: &[u8; 27] = b"memory allocation forbidden"; const MEMORY_GROW_OPCODE: u8 = 0x40; const WRITE_OP: [&str; 1] = ["mBufferStorageStore"]; +#[derive(Default)] pub struct WasmInfo { pub imports: Vec, pub ei_check: bool, pub memory_grow_flag: bool, - pub has_format: bool, pub report: ReportCreator, + pub call_graph: CallGraph, } impl WasmInfo { @@ -31,7 +34,7 @@ impl WasmInfo { output_wasm_path: &str, extract_imports_enabled: bool, check_ei: &Option, - view_endpoints: Vec, + view_endpoints: HashMap<&str, usize>, ) -> Result { let wasm_data = fs::read(output_wasm_path) .expect("error occured while extracting information from .wasm: file not found"); @@ -51,60 +54,67 @@ fn populate_wasm_info( wasm_data: Vec, extract_imports_enabled: bool, check_ei: &Option, - view_endpoints: Vec, + mut view_endpoints: HashMap<&str, usize>, ) -> Result { - let mut imports = Vec::new(); - let mut allocator_trigger = false; - let mut ei_check = false; - let mut memory_grow_flag = false; - let mut has_panic = "none"; - let mut call_graph: HashMap> = HashMap::new(); - let mut views_data: HashMap = HashMap::new(); - let mut write_functions: Vec = Vec::new(); - - let mut parser = Parser::new(0); + let mut wasm_info = WasmInfo::default(); + let mut write_functions: HashSet = HashSet::new(); + + let parser = Parser::new(0); for payload in parser.parse_all(&wasm_data) { match payload? { Payload::ImportSection(import_section) => { - imports = extract_imports( - import_section, - extract_imports_enabled, - &mut call_graph, - &mut write_functions, - ); - ei_check = is_ei_valid(&imports, check_ei); + write_functions = + process_imports(import_section, extract_imports_enabled, &mut wasm_info); + wasm_info.ei_check = is_ei_valid(&wasm_info.imports, check_ei); }, Payload::DataSection(data_section) => { - allocator_trigger = is_fail_allocator_triggered(data_section.clone()); + wasm_info.report.has_allocator = is_fail_allocator_triggered(data_section.clone()); if is_panic_with_message_triggered(data_section.clone()) { - has_panic = WITH_MESSAGE; + wasm_info.report.has_panic = WITH_MESSAGE.to_owned(); } else if is_panic_without_message_triggered(data_section) { - has_panic = WITHOUT_MESSAGE; + wasm_info.report.has_panic = WITHOUT_MESSAGE.to_owned(); } }, Payload::CodeSectionEntry(code_section) => { - memory_grow_flag = is_mem_grow(&code_section); + wasm_info.memory_grow_flag = is_mem_grow(&code_section); + create_call_graph(code_section, &mut wasm_info.call_graph); }, Payload::ExportSection(export_section) => { - views_data = parse_export_section(export_section, &view_endpoints); + parse_export_section(export_section, &mut view_endpoints); }, _ => (), } } - parser = Parser::new(0); - for payload in parser.parse_all(&wasm_data) { - if let Payload::CodeSectionEntry(body) = payload? { - create_call_graph(body, &mut call_graph); - } - } + detect_write_operations_in_views(&view_endpoints, &wasm_info.call_graph, &mut write_functions); + + let report = ReportCreator { + path, + has_allocator: wasm_info.report.has_allocator, + has_panic: wasm_info.report.has_panic, + }; + + Ok(WasmInfo { + imports: wasm_info.imports, + ei_check: wasm_info.ei_check, + memory_grow_flag: wasm_info.memory_grow_flag, + call_graph: wasm_info.call_graph, + report, + }) +} + +fn detect_write_operations_in_views( + views_data: &HashMap<&str, usize>, + call_graph: &CallGraph, + write_functions: &mut HashSet, +) { let mut visited: HashSet = HashSet::new(); - for key in views_data.keys() { - mark_write(*key, &call_graph, &mut write_functions, &mut visited); + for index in views_data.values() { + mark_write(*index, call_graph, write_functions, &mut visited); } - for (index, name) in views_data { - if write_functions.contains(&index) { + for (name, index) in views_data { + if write_functions.contains(index) { println!( "{} {}", "Write storage operation in VIEW endpoint:" @@ -115,42 +125,26 @@ fn populate_wasm_info( ); } } - - let report = ReportCreator { - path, - has_allocator: allocator_trigger, - has_panic: has_panic.to_string(), - }; - - Ok(WasmInfo { - imports, - ei_check, - memory_grow_flag, - has_format: true, - report, - }) } fn parse_export_section( export_section: ExportSectionReader, - view_endpoints: &[String], -) -> HashMap { - let mut views_data: HashMap = HashMap::new(); + view_endpoints: &mut HashMap<&str, usize>, +) { for export in export_section { let export = export.expect("Failed to read export section"); if let wasmparser::ExternalKind::Func = export.kind { - if view_endpoints.contains(&export.name.to_string()) { - views_data.insert(export.index.try_into().unwrap(), export.name.to_string()); + if let Some(endpoint_index) = view_endpoints.get_mut(export.name) { + *endpoint_index = export.index.try_into().unwrap(); } } } - views_data } fn mark_write( func: usize, - call_graph: &HashMap>, - write_functions: &mut Vec, + call_graph: &CallGraph, + write_functions: &mut HashSet, visited: &mut HashSet, ) { // Return early to prevent cycles. @@ -163,27 +157,27 @@ fn mark_write( if let Some(callees) = call_graph.get(&func) { for &callee in callees { if write_functions.contains(&callee) { - write_functions.push(func); + write_functions.insert(func); } else { mark_write(callee, call_graph, write_functions, visited); if write_functions.contains(&callee) { - write_functions.push(func); + write_functions.insert(func); } } } } } -fn create_call_graph(body: FunctionBody, call_graph: &mut HashMap>) { +fn create_call_graph(body: FunctionBody, call_graph: &mut CallGraph) { let mut instructions_reader = body .get_operators_reader() .expect("Failed to get operators reader"); - let mut call_functions = Vec::new(); + let mut call_functions = HashSet::new(); while let Ok(op) = instructions_reader.read() { if let Operator::Call { function_index } = op { let function_usize: usize = function_index.try_into().unwrap(); - call_functions.push(function_usize); + call_functions.insert(function_usize); } } @@ -239,28 +233,25 @@ fn is_panic_without_message_triggered(data_section: DataSectionReader) -> bool { false } -pub fn extract_imports( +pub fn process_imports( import_section: ImportSectionReader, import_extraction_enabled: bool, - call_graph: &mut HashMap>, - write_functions: &mut Vec, -) -> Vec { - if !import_extraction_enabled { - return Vec::new(); - } - - let mut import_names = Vec::new(); + wasm_info: &mut WasmInfo, +) -> HashSet { + let mut write_functions = HashSet::new(); for (index, import) in import_section.into_iter().flatten().enumerate() { - import_names.push(import.name.to_string()); - call_graph.insert(index, vec![]); + if import_extraction_enabled { + wasm_info.imports.push(import.name.to_string()); + } + wasm_info.call_graph.insert(index, HashSet::new()); if WRITE_OP.contains(&import.name) { - write_functions.push(index); + write_functions.insert(index); } } - import_names.sort(); + wasm_info.imports.sort(); - import_names + write_functions } fn is_ei_valid(imports: &[String], check_ei: &Option) -> bool { From 6616577997850059e2f6d7bfd5ed4f0d25fdcc0b Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Fri, 13 Sep 2024 19:28:49 +0300 Subject: [PATCH 09/28] detect write op in view storage - fix clippy --- framework/meta-lib/src/tools/wasm_extractor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index 63dad6b3ad..3f58ef1fac 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -70,9 +70,9 @@ fn populate_wasm_info( Payload::DataSection(data_section) => { wasm_info.report.has_allocator = is_fail_allocator_triggered(data_section.clone()); if is_panic_with_message_triggered(data_section.clone()) { - wasm_info.report.has_panic = WITH_MESSAGE.to_owned(); + WITH_MESSAGE.clone_into(&mut wasm_info.report.has_panic); } else if is_panic_without_message_triggered(data_section) { - wasm_info.report.has_panic = WITHOUT_MESSAGE.to_owned(); + WITHOUT_MESSAGE.clone_into(&mut wasm_info.report.has_panic); } }, Payload::CodeSectionEntry(code_section) => { From f962003084c8d7d56b3ad5834d646a4a882e4469 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Tue, 8 Oct 2024 13:22:30 +0300 Subject: [PATCH 10/28] detect write op in view storage - apply changes requested from review --- .../src/contract/sc_config/wasm_build.rs | 6 - .../meta-lib/src/tools/report_creator.rs | 2 +- .../meta-lib/src/tools/wasm_extractor.rs | 38 ++- .../meta-lib/src/tools/wasm_extractor_test.rs | 229 +++++++++++++++++- 4 files changed, 249 insertions(+), 26 deletions(-) diff --git a/framework/meta-lib/src/contract/sc_config/wasm_build.rs b/framework/meta-lib/src/contract/sc_config/wasm_build.rs index 4311bd0979..051e07d61a 100644 --- a/framework/meta-lib/src/contract/sc_config/wasm_build.rs +++ b/framework/meta-lib/src/contract/sc_config/wasm_build.rs @@ -93,12 +93,6 @@ impl ContractVariant { print_pack_mxsc_file(&output_mxsc_path); print_contract_size(compiled_bytes.len()); let mut abi = ContractAbiJson::from(&self.abi); - let mut view_endpoints = Vec::new(); - for endpoint in &abi.endpoints { - if let crate::abi_json::EndpointMutabilityAbiJson::Readonly = endpoint.mutability { - view_endpoints.push(&endpoint.name) - } - } let build_info = core::mem::take(&mut abi.build_info).unwrap(); let ei_check_json = EiCheckJson::new(&self.settings.check_ei, wasm_info.ei_check); let report = ReportInfoJson::new(&wasm_info, ei_check_json, compiled_bytes.len()); diff --git a/framework/meta-lib/src/tools/report_creator.rs b/framework/meta-lib/src/tools/report_creator.rs index 8af70ae386..c45739c594 100644 --- a/framework/meta-lib/src/tools/report_creator.rs +++ b/framework/meta-lib/src/tools/report_creator.rs @@ -13,7 +13,7 @@ impl Default for ReportCreator { ReportCreator { path: String::new(), has_allocator: false, - has_panic: "none".to_string(), + has_panic: PanicReport::None, } } } diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index b9ccc13891..36d6df037e 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -10,12 +10,19 @@ use wasmparser::{ use crate::ei::EIVersion; -use super::{panic_report::PanicReport, report_creator::ReportCreator}; +use super::report_creator::ReportCreator; type CallGraph = HashMap>; const ERROR_FAIL_ALLOCATOR: &[u8; 27] = b"memory allocation forbidden"; -const WRITE_OP: [&str; 1] = ["mBufferStorageStore"]; +const WRITE_OP: &[&str] = &[ + "mBufferStorageStore", + "storageStore", + "int64storageStore", + "bigIntStorageStoreUnsigned", + "smallIntStorageStoreUnsigned", + "smallIntStorageStoreSigned", +]; #[derive(Default)] pub struct WasmInfo { @@ -24,6 +31,7 @@ pub struct WasmInfo { pub memory_grow_flag: bool, pub report: ReportCreator, pub call_graph: CallGraph, + pub write_index_functions: HashSet, } impl WasmInfo { @@ -49,24 +57,23 @@ impl WasmInfo { pub(crate) fn populate_wasm_info( path: String, wasm_data: Vec, - extract_imports_enabled: bool, + import_extraction_enabled: bool, check_ei: &Option, mut view_endpoints: HashMap<&str, usize>, ) -> Result { let mut wasm_info = WasmInfo::default(); - let mut write_functions: HashSet = HashSet::new(); let parser = Parser::new(0); for payload in parser.parse_all(&wasm_data) { match payload? { Payload::ImportSection(import_section) => { - write_functions = - process_imports(import_section, extract_imports_enabled, &mut wasm_info); + wasm_info.write_index_functions = + process_imports(import_section, import_extraction_enabled, &mut wasm_info); wasm_info.ei_check |= is_ei_valid(&wasm_info.imports, check_ei); }, Payload::DataSection(data_section) => { - allocator_trigger |= is_fail_allocator_triggered(data_section.clone()); - has_panic.max_severity(data_section); + wasm_info.report.has_allocator |= is_fail_allocator_triggered(data_section.clone()); + wasm_info.report.has_panic.max_severity(data_section); }, Payload::CodeSectionEntry(code_section) => { wasm_info.memory_grow_flag |= is_mem_grow(&code_section); @@ -79,7 +86,11 @@ pub(crate) fn populate_wasm_info( } } - detect_write_operations_in_views(&view_endpoints, &wasm_info.call_graph, &mut write_functions); + detect_write_operations_in_views( + &view_endpoints, + &wasm_info.call_graph, + &mut wasm_info.write_index_functions, + ); let report = ReportCreator { path, @@ -93,13 +104,14 @@ pub(crate) fn populate_wasm_info( memory_grow_flag: wasm_info.memory_grow_flag, call_graph: wasm_info.call_graph, report, + write_index_functions: wasm_info.write_index_functions, }) } -fn detect_write_operations_in_views( - views_data: &HashMap<&str, usize>, - call_graph: &CallGraph, - write_functions: &mut HashSet, +fn detect_write_operations_in_views<'a>( + views_data: &'a HashMap<&'a str, usize>, + call_graph: &'a CallGraph, + write_functions: &'a mut HashSet, ) { let mut visited: HashSet = HashSet::new(); for index in views_data.values() { diff --git a/framework/meta-lib/src/tools/wasm_extractor_test.rs b/framework/meta-lib/src/tools/wasm_extractor_test.rs index 030cddc503..953acbfda8 100644 --- a/framework/meta-lib/src/tools/wasm_extractor_test.rs +++ b/framework/meta-lib/src/tools/wasm_extractor_test.rs @@ -1,9 +1,161 @@ #[cfg(test)] pub mod tests { + use std::collections::{HashMap, HashSet}; + use wat::Parser; use crate::tools::{panic_report::PanicReport, wasm_extractor::populate_wasm_info}; + const ADDER_WITH_ERR_IN_VIEW: &str = r#" +(module $adder_wasm.wasm + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func (param i32 i32 i32) (result i32))) + (type (;4;) (func)) + (type (;5;) (func (param i32))) + (type (;6;) (func (param i32 i32 i32))) + (type (;7;) (func (param i32) (result i32))) + (import "env" "bigIntGetUnsignedArgument" (func $bigIntGetUnsignedArgument (;0;) (type 0))) + (import "env" "getNumArguments" (func $getNumArguments (;1;) (type 1))) + (import "env" "signalError" (func $signalError (;2;) (type 0))) + (import "env" "mBufferFromBigIntUnsigned" (func $mBufferFromBigIntUnsigned (;3;) (type 2))) + (import "env" "mBufferStorageStore" (func $mBufferStorageStore (;4;) (type 2))) + (import "env" "mBufferStorageLoad" (func $mBufferStorageLoad (;5;) (type 2))) + (import "env" "mBufferToBigIntUnsigned" (func $mBufferToBigIntUnsigned (;6;) (type 2))) + (import "env" "mBufferSetBytes" (func $mBufferSetBytes (;7;) (type 3))) + (import "env" "checkNoPayment" (func $checkNoPayment (;8;) (type 4))) + (import "env" "bigIntFinishUnsigned" (func $bigIntFinishUnsigned (;9;) (type 5))) + (import "env" "bigIntAdd" (func $bigIntAdd (;10;) (type 6))) + (func $_ZN13multiversx_sc2io16arg_nested_tuple15load_single_arg17hcaef680f5560198bE (;11;) (type 1) (result i32) + (local i32) + i32.const 0 + call $_ZN26multiversx_sc_wasm_adapter3api13managed_types19static_var_api_node11next_handle17h315bf8f89178ffe1E + local.tee 0 + call $bigIntGetUnsignedArgument + local.get 0 + ) + (func $_ZN26multiversx_sc_wasm_adapter3api13managed_types19static_var_api_node11next_handle17h315bf8f89178ffe1E (;12;) (type 1) (result i32) + (local i32) + i32.const 0 + i32.const 0 + i32.load offset=131100 + i32.const -1 + i32.add + local.tee 0 + i32.store offset=131100 + local.get 0 + ) + (func $_ZN13multiversx_sc2io16arg_nested_tuple22check_num_arguments_eq17h8cbbe81aa680cf46E (;13;) (type 5) (param i32) + block ;; label = @1 + call $getNumArguments + local.get 0 + i32.ne + br_if 0 (;@1;) + return + end + i32.const 131072 + i32.const 25 + call $signalError + unreachable + ) + (func $_ZN13multiversx_sc7storage7mappers19single_value_mapper31SingleValueMapper$LT$SA$C$T$GT$3set17h00fe05a7d5154b39E (;14;) (type 0) (param i32 i32) + (local i32) + call $_ZN26multiversx_sc_wasm_adapter3api13managed_types19static_var_api_node11next_handle17h315bf8f89178ffe1E + local.tee 2 + local.get 1 + call $mBufferFromBigIntUnsigned + drop + local.get 0 + local.get 2 + call $mBufferStorageStore + drop + ) + (func $_ZN13multiversx_sc7storage7mappers19single_value_mapper35SingleValueMapper$LT$SA$C$T$C$A$GT$3get17hb9977d4c8d45f0d8E (;15;) (type 7) (param i32) (result i32) + (local i32) + local.get 0 + call $_ZN26multiversx_sc_wasm_adapter3api13managed_types19static_var_api_node11next_handle17h315bf8f89178ffe1E + local.tee 1 + call $mBufferStorageLoad + drop + local.get 1 + call $_ZN26multiversx_sc_wasm_adapter3api13managed_types19static_var_api_node11next_handle17h315bf8f89178ffe1E + local.tee 0 + call $mBufferToBigIntUnsigned + drop + local.get 0 + ) + (func $_ZN34_$LT$C$u20$as$u20$adder..Adder$GT$3sum17h7cc7cc0602a1f97fE (;16;) (type 1) (result i32) + (local i32) + call $_ZN26multiversx_sc_wasm_adapter3api13managed_types19static_var_api_node11next_handle17h315bf8f89178ffe1E + local.tee 0 + i32.const 131097 + i32.const 3 + call $mBufferSetBytes + drop + local.get 0 + ) + (func $init (;17;) (type 4) + (local i32) + call $checkNoPayment + i32.const 1 + call $_ZN13multiversx_sc2io16arg_nested_tuple22check_num_arguments_eq17h8cbbe81aa680cf46E + call $_ZN13multiversx_sc2io16arg_nested_tuple15load_single_arg17hcaef680f5560198bE + local.set 0 + call $_ZN34_$LT$C$u20$as$u20$adder..Adder$GT$3sum17h7cc7cc0602a1f97fE + local.get 0 + call $_ZN13multiversx_sc7storage7mappers19single_value_mapper31SingleValueMapper$LT$SA$C$T$GT$3set17h00fe05a7d5154b39E + ) + (func $getSum (;18;) (type 4) + call $checkNoPayment + i32.const 0 + call $_ZN13multiversx_sc2io16arg_nested_tuple22check_num_arguments_eq17h8cbbe81aa680cf46E + call $_ZN34_$LT$C$u20$as$u20$adder..Adder$GT$3sum17h7cc7cc0602a1f97fE + call $_ZN13multiversx_sc7storage7mappers19single_value_mapper35SingleValueMapper$LT$SA$C$T$C$A$GT$3get17hb9977d4c8d45f0d8E + call $bigIntFinishUnsigned + ) + (func $add (;19;) (type 4) + (local i32 i32 i32) + call $checkNoPayment + i32.const 1 + call $_ZN13multiversx_sc2io16arg_nested_tuple22check_num_arguments_eq17h8cbbe81aa680cf46E + call $_ZN13multiversx_sc2io16arg_nested_tuple15load_single_arg17hcaef680f5560198bE + local.set 0 + call $_ZN34_$LT$C$u20$as$u20$adder..Adder$GT$3sum17h7cc7cc0602a1f97fE + local.tee 1 + call $_ZN13multiversx_sc7storage7mappers19single_value_mapper35SingleValueMapper$LT$SA$C$T$C$A$GT$3get17hb9977d4c8d45f0d8E + local.tee 2 + local.get 2 + local.get 0 + call $bigIntAdd + local.get 1 + local.get 2 + call $_ZN13multiversx_sc7storage7mappers19single_value_mapper31SingleValueMapper$LT$SA$C$T$GT$3set17h00fe05a7d5154b39E + ) + (func $callBack (;20;) (type 4)) + (table (;0;) 1 1 funcref) + (memory (;0;) 3) + (global $__stack_pointer (;0;) (mut i32) i32.const 131072) + (global (;1;) i32 i32.const 131104) + (global (;2;) i32 i32.const 131104) + (export "memory" (memory 0)) + (export "init" (func $init)) + (export "getSum" (func $getSum)) + (export "add" (func $add)) + (export "callBack" (func $callBack)) + (export "upgrade" (func $init)) + (export "__data_end" (global 1)) + (export "__heap_base" (global 2)) + (data $.rodata (;0;) (i32.const 131072) "wrong number of argumentssum") + (data $.data (;1;) (i32.const 131100) "8\ff\ff\ff") + (@producers + (language "Rust" "") + (processed-by "rustc" "1.80.1 (3f5fd8dd4 2024-08-06)") + ) + (@custom "target_features" (after data) "\02+\0fmutable-globals+\08sign-ext") +) +"#; + const EMPTY_WITH_FAIL_ALLOCATOR: &str = r#" (module $empty_wasm.wasm (type (;0;) (func (result i32))) @@ -256,8 +408,14 @@ pub mod tests { #[test] fn test_empty() { if let Ok(content) = Parser::new().parse_bytes(None, EMPTY_DBG_WAT.as_bytes()) { - let wasm_info = populate_wasm_info(String::new(), content.to_vec(), false, &None) - .expect("Unable to parse WASM content."); + let wasm_info = populate_wasm_info( + String::new(), + content.to_vec(), + false, + &None, + HashMap::new(), + ) + .expect("Unable to parse WASM content."); assert!(!wasm_info.memory_grow_flag); assert!(!wasm_info.report.has_allocator); assert_eq!( @@ -270,8 +428,14 @@ pub mod tests { #[test] fn test_empty_with_mem_grow() { if let Ok(content) = Parser::new().parse_bytes(None, EMPTY_WITH_MEM_GROW.as_bytes()) { - let wasm_info = populate_wasm_info(String::new(), content.to_vec(), false, &None) - .expect("Unable to parse WASM content."); + let wasm_info = populate_wasm_info( + String::new(), + content.to_vec(), + false, + &None, + HashMap::new(), + ) + .expect("Unable to parse WASM content."); assert!(wasm_info.memory_grow_flag); assert!(!wasm_info.report.has_allocator); assert_eq!( @@ -284,8 +448,14 @@ pub mod tests { #[test] fn test_empty_with_fail_allocator() { if let Ok(content) = Parser::new().parse_bytes(None, EMPTY_WITH_FAIL_ALLOCATOR.as_bytes()) { - let wasm_info = populate_wasm_info(String::new(), content.to_vec(), false, &None) - .expect("Unable to parse WASM content."); + let wasm_info = populate_wasm_info( + String::new(), + content.to_vec(), + false, + &None, + HashMap::new(), + ) + .expect("Unable to parse WASM content."); assert!(!wasm_info.memory_grow_flag); assert!(wasm_info.report.has_allocator); assert_eq!( @@ -294,4 +464,51 @@ pub mod tests { ); } } + + #[test] + fn test_adder_with_write_op_in_view() { + let view_endpoints: HashMap<&str, usize> = HashMap::from([("sum", 0), ("add", 0)]); + + let expected_write_index_functions: HashSet = HashSet::from([4, 19, 14]); + let expected_call_graph: HashMap> = HashMap::from([ + (0, HashSet::new()), + (1, HashSet::new()), + (2, HashSet::new()), + (3, HashSet::new()), + (4, HashSet::new()), + (5, HashSet::new()), + (6, HashSet::new()), + (7, HashSet::new()), + (8, HashSet::new()), + (9, HashSet::new()), + (10, HashSet::new()), + (11, HashSet::from([12, 0])), + (12, HashSet::new()), + (13, HashSet::from([1, 2])), + (14, HashSet::from([12, 3, 4])), + (15, HashSet::from([12, 5, 6])), + (16, HashSet::from([12, 7])), + (17, HashSet::from([8, 13, 11, 16, 14])), + (18, HashSet::from([8, 13, 16, 15, 9])), + (19, HashSet::from([8, 13, 11, 16, 15, 10, 14])), + (20, HashSet::new()), + ]); + + if let Ok(content) = Parser::new().parse_bytes(None, ADDER_WITH_ERR_IN_VIEW.as_bytes()) { + let wasm_info = populate_wasm_info( + String::new(), + content.to_vec(), + false, + &None, + view_endpoints, + ) + .expect("Unable to parse WASM content."); + + assert_eq!( + expected_write_index_functions, + wasm_info.write_index_functions + ); + assert_eq!(expected_call_graph, wasm_info.call_graph); + } + } } From ed23f0c319d887274e50c2161b21e2ef58fbcf80 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Tue, 8 Oct 2024 18:08:31 +0300 Subject: [PATCH 11/28] detect write op in view storage - refactor wasm_extractor --- .../src/contract/sc_config/wasm_build.rs | 12 +- .../meta-lib/src/tools/wasm_extractor.rs | 202 +++++++++--------- .../meta-lib/src/tools/wasm_extractor_test.rs | 40 ++-- 3 files changed, 120 insertions(+), 134 deletions(-) diff --git a/framework/meta-lib/src/contract/sc_config/wasm_build.rs b/framework/meta-lib/src/contract/sc_config/wasm_build.rs index 051e07d61a..17312dbb04 100644 --- a/framework/meta-lib/src/contract/sc_config/wasm_build.rs +++ b/framework/meta-lib/src/contract/sc_config/wasm_build.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, ffi::OsStr, fs, process::Command}; +use std::{ffi::OsStr, fs, process::Command}; use super::ContractVariant; use crate::{ @@ -131,10 +131,10 @@ impl ContractVariant { let output_wasm_path = format!("{output_path}/{}", self.wasm_output_name(build_args)); let abi = ContractAbiJson::from(&self.abi); - let mut view_endpoints: HashMap<&str, usize> = HashMap::new(); + let mut view_endpoints: Vec<&str> = Vec::new(); for endpoint in &abi.endpoints { if let crate::abi_json::EndpointMutabilityAbiJson::Readonly = endpoint.mutability { - view_endpoints.insert(&endpoint.name, 0); + view_endpoints.push(&endpoint.name); } } @@ -144,8 +144,7 @@ impl ContractVariant { build_args.extract_imports, &self.settings.check_ei, view_endpoints, - ) - .expect("error occured while extracting imports from .wasm "); + ); } let output_imports_json_path = format!( @@ -160,8 +159,7 @@ impl ContractVariant { true, &self.settings.check_ei, view_endpoints, - ) - .expect("error occured while extracting imports from .wasm "); + ); write_imports_output( output_imports_json_path.as_str(), diff --git a/framework/meta-lib/src/tools/wasm_extractor.rs b/framework/meta-lib/src/tools/wasm_extractor.rs index 36d6df037e..eba84b4ada 100644 --- a/framework/meta-lib/src/tools/wasm_extractor.rs +++ b/framework/meta-lib/src/tools/wasm_extractor.rs @@ -32,6 +32,7 @@ pub struct WasmInfo { pub report: ReportCreator, pub call_graph: CallGraph, pub write_index_functions: HashSet, + pub view_endpoints: HashMap, } impl WasmInfo { @@ -39,18 +40,96 @@ impl WasmInfo { output_wasm_path: &str, extract_imports_enabled: bool, check_ei: &Option, - view_endpoints: HashMap<&str, usize>, - ) -> Result { + view_endpoints: Vec<&str>, + ) -> WasmInfo { let wasm_data = fs::read(output_wasm_path) .expect("error occured while extracting information from .wasm: file not found"); - populate_wasm_info( + let wasm_info = populate_wasm_info( output_wasm_path.to_string(), wasm_data, extract_imports_enabled, check_ei, view_endpoints, - ) + ); + + wasm_info.expect("error occured while extracting information from .wasm file") + } + + fn create_call_graph(&mut self, body: FunctionBody) { + let mut instructions_reader = body + .get_operators_reader() + .expect("Failed to get operators reader"); + + let mut call_functions = HashSet::new(); + while let Ok(op) = instructions_reader.read() { + if let Operator::Call { function_index } = op { + let function_usize: usize = function_index.try_into().unwrap(); + call_functions.insert(function_usize); + } + } + + self.call_graph + .insert(self.call_graph.len(), call_functions); + } + + pub fn process_imports( + &mut self, + import_section: ImportSectionReader, + import_extraction_enabled: bool, + ) { + for (index, import) in import_section.into_iter().flatten().enumerate() { + if import_extraction_enabled { + self.imports.push(import.name.to_string()); + } + self.call_graph.insert(index, HashSet::new()); + if WRITE_OP.contains(&import.name) { + self.write_index_functions.insert(index); + } + } + + self.imports.sort(); + } + + pub fn detect_write_operations_in_views(&mut self) { + let mut visited: HashSet = HashSet::new(); + for index in self.view_endpoints.values() { + mark_write( + *index, + &self.call_graph, + &mut self.write_index_functions, + &mut visited, + ); + } + + for (name, index) in &self.view_endpoints { + if self.write_index_functions.contains(index) { + println!( + "{} {}", + "Write storage operation in VIEW endpoint:" + .to_string() + .red() + .bold(), + name.red().bold() + ); + } + } + } + + fn parse_export_section( + &mut self, + export_section: ExportSectionReader, + view_endpoints: &[&str], + ) { + for export in export_section { + let export = export.expect("Failed to read export section"); + if let wasmparser::ExternalKind::Func = export.kind { + if view_endpoints.contains(&export.name) { + self.view_endpoints + .insert(export.name.to_owned(), export.index.try_into().unwrap()); + } + } + } } } @@ -59,7 +138,7 @@ pub(crate) fn populate_wasm_info( wasm_data: Vec, import_extraction_enabled: bool, check_ei: &Option, - mut view_endpoints: HashMap<&str, usize>, + view_endpoints: Vec<&str>, ) -> Result { let mut wasm_info = WasmInfo::default(); @@ -67,8 +146,7 @@ pub(crate) fn populate_wasm_info( for payload in parser.parse_all(&wasm_data) { match payload? { Payload::ImportSection(import_section) => { - wasm_info.write_index_functions = - process_imports(import_section, import_extraction_enabled, &mut wasm_info); + wasm_info.process_imports(import_section, import_extraction_enabled); wasm_info.ei_check |= is_ei_valid(&wasm_info.imports, check_ei); }, Payload::DataSection(data_section) => { @@ -77,20 +155,16 @@ pub(crate) fn populate_wasm_info( }, Payload::CodeSectionEntry(code_section) => { wasm_info.memory_grow_flag |= is_mem_grow(&code_section); - create_call_graph(code_section, &mut wasm_info.call_graph); + wasm_info.create_call_graph(code_section); }, Payload::ExportSection(export_section) => { - parse_export_section(export_section, &mut view_endpoints); + wasm_info.parse_export_section(export_section, &view_endpoints); }, _ => (), } } - detect_write_operations_in_views( - &view_endpoints, - &wasm_info.call_graph, - &mut wasm_info.write_index_functions, - ); + wasm_info.detect_write_operations_in_views(); let report = ReportCreator { path, @@ -105,45 +179,29 @@ pub(crate) fn populate_wasm_info( call_graph: wasm_info.call_graph, report, write_index_functions: wasm_info.write_index_functions, + view_endpoints: wasm_info.view_endpoints, }) } -fn detect_write_operations_in_views<'a>( - views_data: &'a HashMap<&'a str, usize>, - call_graph: &'a CallGraph, - write_functions: &'a mut HashSet, -) { - let mut visited: HashSet = HashSet::new(); - for index in views_data.values() { - mark_write(*index, call_graph, write_functions, &mut visited); - } - - for (name, index) in views_data { - if write_functions.contains(index) { +fn is_fail_allocator_triggered(data_section: DataSectionReader) -> bool { + for data_fragment in data_section.into_iter().flatten() { + if data_fragment + .data + .windows(ERROR_FAIL_ALLOCATOR.len()) + .any(|data| data == ERROR_FAIL_ALLOCATOR) + { println!( - "{} {}", - "Write storage operation in VIEW endpoint:" + "{}", + "FailAllocator used while memory allocation is accessible in code. Contract may fail unexpectedly when memory allocation is attempted" .to_string() .red() - .bold(), - name.red().bold() + .bold() ); + return true; } } -} -fn parse_export_section( - export_section: ExportSectionReader, - view_endpoints: &mut HashMap<&str, usize>, -) { - for export in export_section { - let export = export.expect("Failed to read export section"); - if let wasmparser::ExternalKind::Func = export.kind { - if let Some(endpoint_index) = view_endpoints.get_mut(export.name) { - *endpoint_index = export.index.try_into().unwrap(); - } - } - } + false } fn mark_write( @@ -173,64 +231,6 @@ fn mark_write( } } -fn create_call_graph(body: FunctionBody, call_graph: &mut CallGraph) { - let mut instructions_reader = body - .get_operators_reader() - .expect("Failed to get operators reader"); - - let mut call_functions = HashSet::new(); - while let Ok(op) = instructions_reader.read() { - if let Operator::Call { function_index } = op { - let function_usize: usize = function_index.try_into().unwrap(); - call_functions.insert(function_usize); - } - } - - call_graph.insert(call_graph.len(), call_functions); -} - -fn is_fail_allocator_triggered(data_section: DataSectionReader) -> bool { - for data_fragment in data_section.into_iter().flatten() { - if data_fragment - .data - .windows(ERROR_FAIL_ALLOCATOR.len()) - .any(|data| data == ERROR_FAIL_ALLOCATOR) - { - println!( - "{}", - "FailAllocator used while memory allocation is accessible in code. Contract may fail unexpectedly when memory allocation is attempted" - .to_string() - .red() - .bold() - ); - return true; - } - } - - false -} - -pub fn process_imports( - import_section: ImportSectionReader, - import_extraction_enabled: bool, - wasm_info: &mut WasmInfo, -) -> HashSet { - let mut write_functions = HashSet::new(); - for (index, import) in import_section.into_iter().flatten().enumerate() { - if import_extraction_enabled { - wasm_info.imports.push(import.name.to_string()); - } - wasm_info.call_graph.insert(index, HashSet::new()); - if WRITE_OP.contains(&import.name) { - write_functions.insert(index); - } - } - - wasm_info.imports.sort(); - - write_functions -} - fn is_ei_valid(imports: &[String], check_ei: &Option) -> bool { if let Some(ei) = check_ei { let mut num_errors = 0; diff --git a/framework/meta-lib/src/tools/wasm_extractor_test.rs b/framework/meta-lib/src/tools/wasm_extractor_test.rs index 953acbfda8..c307323a31 100644 --- a/framework/meta-lib/src/tools/wasm_extractor_test.rs +++ b/framework/meta-lib/src/tools/wasm_extractor_test.rs @@ -4,7 +4,7 @@ pub mod tests { use wat::Parser; - use crate::tools::{panic_report::PanicReport, wasm_extractor::populate_wasm_info}; + use crate::tools::{panic_report::PanicReport, wasm_extractor::populate_wasm_info, WasmInfo}; const ADDER_WITH_ERR_IN_VIEW: &str = r#" (module $adder_wasm.wasm @@ -408,14 +408,9 @@ pub mod tests { #[test] fn test_empty() { if let Ok(content) = Parser::new().parse_bytes(None, EMPTY_DBG_WAT.as_bytes()) { - let wasm_info = populate_wasm_info( - String::new(), - content.to_vec(), - false, - &None, - HashMap::new(), - ) - .expect("Unable to parse WASM content."); + let wasm_info = + populate_wasm_info(String::new(), content.to_vec(), false, &None, Vec::new()) + .expect("Unable to parse WASM content."); assert!(!wasm_info.memory_grow_flag); assert!(!wasm_info.report.has_allocator); assert_eq!( @@ -428,14 +423,9 @@ pub mod tests { #[test] fn test_empty_with_mem_grow() { if let Ok(content) = Parser::new().parse_bytes(None, EMPTY_WITH_MEM_GROW.as_bytes()) { - let wasm_info = populate_wasm_info( - String::new(), - content.to_vec(), - false, - &None, - HashMap::new(), - ) - .expect("Unable to parse WASM content."); + let wasm_info = + populate_wasm_info(String::new(), content.to_vec(), false, &None, Vec::new()) + .expect("Unable to parse WASM content."); assert!(wasm_info.memory_grow_flag); assert!(!wasm_info.report.has_allocator); assert_eq!( @@ -448,14 +438,9 @@ pub mod tests { #[test] fn test_empty_with_fail_allocator() { if let Ok(content) = Parser::new().parse_bytes(None, EMPTY_WITH_FAIL_ALLOCATOR.as_bytes()) { - let wasm_info = populate_wasm_info( - String::new(), - content.to_vec(), - false, - &None, - HashMap::new(), - ) - .expect("Unable to parse WASM content."); + let wasm_info = + populate_wasm_info(String::new(), content.to_vec(), false, &None, Vec::new()) + .expect("Unable to parse WASM content."); assert!(!wasm_info.memory_grow_flag); assert!(wasm_info.report.has_allocator); assert_eq!( @@ -467,8 +452,10 @@ pub mod tests { #[test] fn test_adder_with_write_op_in_view() { - let view_endpoints: HashMap<&str, usize> = HashMap::from([("sum", 0), ("add", 0)]); + let view_endpoints: Vec<&str> = Vec::from(["getSum", "add"]); + let expected_view_index: HashMap = + HashMap::from([("getSum".to_string(), 18), ("add".to_string(), 19)]); let expected_write_index_functions: HashSet = HashSet::from([4, 19, 14]); let expected_call_graph: HashMap> = HashMap::from([ (0, HashSet::new()), @@ -509,6 +496,7 @@ pub mod tests { wasm_info.write_index_functions ); assert_eq!(expected_call_graph, wasm_info.call_graph); + assert_eq!(expected_view_index, wasm_info.view_endpoints); } } } From 80959ed33d5e2eaffc7e59c7fcf565d2df56eca8 Mon Sep 17 00:00:00 2001 From: BiancaIalangi Date: Tue, 8 Oct 2024 18:16:15 +0300 Subject: [PATCH 12/28] detect write op in view storage - clippy --- framework/meta-lib/src/tools/wasm_extractor_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/meta-lib/src/tools/wasm_extractor_test.rs b/framework/meta-lib/src/tools/wasm_extractor_test.rs index c307323a31..346d0d855e 100644 --- a/framework/meta-lib/src/tools/wasm_extractor_test.rs +++ b/framework/meta-lib/src/tools/wasm_extractor_test.rs @@ -4,7 +4,7 @@ pub mod tests { use wat::Parser; - use crate::tools::{panic_report::PanicReport, wasm_extractor::populate_wasm_info, WasmInfo}; + use crate::tools::{panic_report::PanicReport, wasm_extractor::populate_wasm_info}; const ADDER_WITH_ERR_IN_VIEW: &str = r#" (module $adder_wasm.wasm From 981898c9191b26cbde12ff5da21fb06eeb032728 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 9 Oct 2024 00:09:07 +0300 Subject: [PATCH 13/28] unified syntax - ReturnsResultOrError + tests --- .../scenarios/interactor_trace.scen.json | 4 +- .../scenarios/st-adder.scen.json | 4 +- .../feature-tests/scenario-tester/src/lib.rs | 4 +- .../src/scenario_tester_proxy.rs | 3 +- .../tests/st_blackbox_raw_steps_test.rs | 2 +- .../scenario-tester/tests/st_blackbox_test.rs | 38 ++++++++ .../tests/st_blackbox_upgrade_test.rs | 2 +- .../scenario/src/facade/result_handlers.rs | 2 + .../result_handlers/returns_result_or_err.rs | 89 +++++++++++++++++++ .../scenario/model/transaction/tx_error.rs | 21 ----- 10 files changed, 142 insertions(+), 27 deletions(-) create mode 100644 framework/scenario/src/facade/result_handlers/returns_result_or_err.rs delete mode 100644 framework/scenario/src/scenario/model/transaction/tx_error.rs diff --git a/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json b/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json index 07fd7f68ca..b5d3ed5b15 100644 --- a/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json +++ b/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json @@ -36,7 +36,9 @@ "gasLimit": "70,000,000" }, "expect": { - "out": [], + "out": [ + "str:init-result" + ], "status": "0" } }, diff --git a/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json b/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json index 94ba305ed2..c2e6570007 100644 --- a/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json +++ b/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json @@ -32,7 +32,9 @@ "gasPrice": "0" }, "expect": { - "out": [], + "out": [ + "str:init-result" + ], "status": "", "logs": "*", "gas": "*", diff --git a/contracts/feature-tests/scenario-tester/src/lib.rs b/contracts/feature-tests/scenario-tester/src/lib.rs index 97c352adeb..d5d2fd37e4 100644 --- a/contracts/feature-tests/scenario-tester/src/lib.rs +++ b/contracts/feature-tests/scenario-tester/src/lib.rs @@ -12,9 +12,11 @@ pub trait ScenarioTester { #[storage_mapper("sum")] fn sum(&self) -> SingleValueMapper; + /// Return value for testing reasons. #[init] - fn init(&self, initial_value: BigUint) { + fn init(&self, initial_value: BigUint) -> &'static str { self.sum().set(initial_value); + "init-result" } #[upgrade] diff --git a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs index 66976893c2..f5aae69fed 100644 --- a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs +++ b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs @@ -43,12 +43,13 @@ where From: TxFrom, Gas: TxGas, { + /// Return value for testing reasons. pub fn init< Arg0: ProxyArg>, >( self, initial_value: Arg0, - ) -> TxTypedDeploy { + ) -> TxTypedDeploy { self.wrapped_tx .payment(NotPayable) .raw_deploy() diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs index 68ac9b8d39..adc3ffa34e 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs @@ -25,7 +25,7 @@ fn scenario_tester_blackbox_raw() { .from("address:owner") .code(scenario_tester_code) .argument("5") - .expect(TxExpect::ok().no_result()), + .expect(TxExpect::ok().result("str:init-result")), ) .sc_query( ScQueryStep::new() diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs index d3f78692e8..9686dbcc32 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -286,3 +286,41 @@ fn st_blackbox_tx_hash() { assert_eq!(tx_hash.as_array(), &[22u8; 32]); } + +#[test] +fn st_blackbox_returns_result_or_error() { + let mut world = world(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .balance(100) + .account(OTHER_ADDRESS) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + let (result, check_tx_hash) = world + .tx() + .from(OWNER_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .init(5u32) + .code(CODE_PATH) + .new_address(ST_ADDRESS) + .tx_hash([33u8; 32]) + .returns( + ReturnsResultOrError::new() + .returns(ReturnsNewAddress) + .returns(ReturnsResultAs::::new()) + .returns(ReturnsTxHash), + ) + .returns(ReturnsTxHash) + .run(); + + assert_eq!(check_tx_hash.as_array(), &[33u8; 32]); + let (new_address, out_value, also_check_tx_hash) = result.unwrap(); + assert_eq!(new_address, ST_ADDRESS.to_address()); + assert_eq!(out_value, "init-result"); + assert_eq!(also_check_tx_hash.as_array(), &[33u8; 32]); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs index 3242739239..2fd12feaec 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs @@ -29,7 +29,7 @@ fn st_blackbox_upgrade() { .code(&st_code) .argument("5") .gas_limit("5,000,000") - .expect(TxExpect::ok().no_result()), + .expect(TxExpect::ok().result("str:init-result")), ) .sc_call( ScCallStep::new() diff --git a/framework/scenario/src/facade/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs index 88e90d0cd5..7a5f0e779b 100644 --- a/framework/scenario/src/facade/result_handlers.rs +++ b/framework/scenario/src/facade/result_handlers.rs @@ -6,6 +6,7 @@ mod returns_logs; mod returns_message; mod returns_new_bech32_address; mod returns_new_token_identifier; +mod returns_result_or_err; mod returns_status; mod returns_tx_hash; mod with_tx_raw_response; @@ -18,6 +19,7 @@ pub use returns_logs::ReturnsLogs; pub use returns_message::ReturnsMessage; pub use returns_new_bech32_address::ReturnsNewBech32Address; pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; +pub use returns_result_or_err::ReturnsResultOrError; pub use returns_status::ReturnsStatus; pub use returns_tx_hash::ReturnsTxHash; pub use with_tx_raw_response::WithRawTxResponse; diff --git a/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs b/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs new file mode 100644 index 0000000000..7e3f3c245d --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs @@ -0,0 +1,89 @@ +use std::marker::PhantomData; + +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + OriginalResultMarker, RHList, RHListAppendRet, RHListExec, RHListItem, RHListItemExec, + TxEnv, + }, +}; + +use crate::scenario_model::{TxResponse, TxResponseStatus}; + +/// Indicates that a `Result` will be returned, either with the handled result, +/// according to the inner result handlers, or with an error in case of a failed transaction. +pub struct ReturnsResultOrError +where + Env: TxEnv, + Ok: RHList, +{ + _phantom_env: PhantomData, + _phantom_original: PhantomData, + pub ok_t: Ok, +} + +impl Default for ReturnsResultOrError> +where + Env: TxEnv, +{ + fn default() -> Self { + ReturnsResultOrError { + _phantom_env: PhantomData, + _phantom_original: PhantomData, + ok_t: OriginalResultMarker::new(), + } + } +} + +impl ReturnsResultOrError> +where + Env: TxEnv, +{ + pub fn new() -> Self { + ReturnsResultOrError::default() + } +} + +impl ReturnsResultOrError +where + Env: TxEnv, + Ok: RHListExec, +{ + pub fn returns(self, item: RH) -> ReturnsResultOrError + where + RH: RHListItem, + Ok: RHListAppendRet, + { + ReturnsResultOrError { + _phantom_env: PhantomData, + _phantom_original: PhantomData, + ok_t: self.ok_t.append_ret(item), + } + } +} + +impl RHListItem for ReturnsResultOrError +where + Env: TxEnv, + Ok: RHListExec, + Ok::ListReturns: NestedTupleFlatten, +{ + type Returns = Result<::Unpacked, TxResponseStatus>; +} + +impl RHListItemExec + for ReturnsResultOrError +where + Env: TxEnv, + Ok: RHListExec, + Ok::ListReturns: NestedTupleFlatten, +{ + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + if raw_result.tx_error.is_success() { + let tuple_result = self.ok_t.list_process_result(raw_result); + Ok(tuple_result.flatten_unpack()) + } else { + Err(raw_result.tx_error.clone()) + } + } +} diff --git a/framework/scenario/src/scenario/model/transaction/tx_error.rs b/framework/scenario/src/scenario/model/transaction/tx_error.rs deleted file mode 100644 index d0a2b5a3e4..0000000000 --- a/framework/scenario/src/scenario/model/transaction/tx_error.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[derive(Debug, Default, Clone)] -pub struct TxResponseStatus { - pub status: u64, - pub message: String, -} - -impl TxResponseStatus { - pub fn is_success(&self) -> bool { - self.status == 0 - } -} - -impl std::fmt::Display for TxResponseStatus { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.is_success() { - write!(f, "transaction successful") - } else { - write!(f, "transaction error: {}", self.message) - } - } -} From da9a6572826ee206a9f09a12d71887aed27de8df Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 9 Oct 2024 00:34:14 +0300 Subject: [PATCH 14/28] unified syntax - ReturnsResultOrError expect fix + tests --- .../feature-tests/scenario-tester/src/lib.rs | 5 ++ .../src/scenario_tester_proxy.rs | 9 ++++ .../scenario-tester/tests/st_blackbox_test.rs | 48 ++++++++++++++++++- .../scenario-tester/wasm/src/lib.rs | 5 +- .../result_handlers/returns_result_or_err.rs | 10 +++- .../model/transaction/tx_response_status.rs | 2 +- 6 files changed, 73 insertions(+), 6 deletions(-) diff --git a/contracts/feature-tests/scenario-tester/src/lib.rs b/contracts/feature-tests/scenario-tester/src/lib.rs index d5d2fd37e4..ba80b21abd 100644 --- a/contracts/feature-tests/scenario-tester/src/lib.rs +++ b/contracts/feature-tests/scenario-tester/src/lib.rs @@ -40,4 +40,9 @@ pub trait ScenarioTester { let value_plus_one = &value + 1u32; (value, value_plus_one).into() } + + #[view] + fn sc_panic(&self) { + sc_panic!("sc_panic! example"); + } } diff --git a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs index f5aae69fed..25eb71225c 100644 --- a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs +++ b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs @@ -140,4 +140,13 @@ where .argument(&value) .original_result() } + + pub fn sc_panic( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("sc_panic") + .original_result() + } } diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs index 9686dbcc32..26d907bdfc 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -1,4 +1,4 @@ -use multiversx_sc_scenario::imports::*; +use multiversx_sc_scenario::{imports::*, scenario_model::TxResponseStatus}; use scenario_tester::*; @@ -301,6 +301,7 @@ fn st_blackbox_returns_result_or_error() { .esdt_balance(TOKEN_ID, 500) .commit(); + // deploy let (result, check_tx_hash) = world .tx() .from(OWNER_ADDRESS) @@ -323,4 +324,49 @@ fn st_blackbox_returns_result_or_error() { assert_eq!(new_address, ST_ADDRESS.to_address()); assert_eq!(out_value, "init-result"); assert_eq!(also_check_tx_hash.as_array(), &[33u8; 32]); + + // query - ok + let result = world + .query() + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .sum() + .returns(ReturnsResultOrError::new().returns(ReturnsResultUnmanaged)) + .run(); + assert_eq!(result, Ok(RustBigUint::from(5u32))); + + // query - error + let result = world + .query() + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .sc_panic() + .returns(ReturnsResultOrError::new()) + .run(); + + assert_eq!(result, Err(TxResponseStatus::new(4, "sc_panic! example"))); + + // call - ok + let result = world + .tx() + .from(OWNER_ADDRESS) + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .add(1u32) + .returns(ReturnsResultOrError::new()) + .run(); + + assert_eq!(result, Ok(())); + + // call - error + let result = world + .tx() + .from(OWNER_ADDRESS) + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .sc_panic() + .returns(ReturnsResultOrError::new()) + .run(); + + assert_eq!(result, Err(TxResponseStatus::new(4, "sc_panic! example"))); } diff --git a/contracts/feature-tests/scenario-tester/wasm/src/lib.rs b/contracts/feature-tests/scenario-tester/wasm/src/lib.rs index 7976698233..b1360c1d95 100644 --- a/contracts/feature-tests/scenario-tester/wasm/src/lib.rs +++ b/contracts/feature-tests/scenario-tester/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 4 +// Endpoints: 5 // Async Callback (empty): 1 -// Total number of exported functions: 7 +// Total number of exported functions: 8 #![no_std] @@ -24,6 +24,7 @@ multiversx_sc_wasm_adapter::endpoints! { add => add multi_param => multi_param multi_return => multi_return + sc_panic => sc_panic ) } diff --git a/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs b/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs index 7e3f3c245d..d4562eb349 100644 --- a/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs +++ b/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs @@ -8,7 +8,7 @@ use multiversx_sc::{ }, }; -use crate::scenario_model::{TxResponse, TxResponseStatus}; +use crate::scenario_model::{CheckValue, TxExpect, TxResponse, TxResponseStatus}; /// Indicates that a `Result` will be returned, either with the handled result, /// according to the inner result handlers, or with an error in case of a failed transaction. @@ -74,10 +74,16 @@ where impl RHListItemExec for ReturnsResultOrError where - Env: TxEnv, + Env: TxEnv, Ok: RHListExec, Ok::ListReturns: NestedTupleFlatten, { + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + prev.status = CheckValue::Star; + prev.message = CheckValue::Star; + prev + } + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { if raw_result.tx_error.is_success() { let tuple_result = self.ok_t.list_process_result(raw_result); diff --git a/framework/scenario/src/scenario/model/transaction/tx_response_status.rs b/framework/scenario/src/scenario/model/transaction/tx_response_status.rs index e7902047c6..bdfb888b56 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_response_status.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_response_status.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] /// The status of a transaction. pub struct TxResponseStatus { /// The status of the transaction. From 30b8e2e0fb7202972feaab5061d8ce986de2f2de Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 9 Oct 2024 14:46:07 +0300 Subject: [PATCH 15/28] sc-meta support for framework deps as path or git --- framework/meta/src/cmd/info.rs | 3 +- framework/meta/src/cmd/print_util.rs | 33 +++++++++++++ framework/meta/src/cmd/upgrade.rs | 1 - .../meta/src/cmd/upgrade/upgrade_print.rs | 39 +++++---------- .../meta/src/cmd/upgrade/upgrade_selector.rs | 2 +- .../folder_structure/relevant_directory.rs | 49 +++++++++++++------ .../meta/src/folder_structure/version_req.rs | 27 ++++++++++ 7 files changed, 110 insertions(+), 44 deletions(-) diff --git a/framework/meta/src/cmd/info.rs b/framework/meta/src/cmd/info.rs index 2d36399474..6d51ccd39f 100644 --- a/framework/meta/src/cmd/info.rs +++ b/framework/meta/src/cmd/info.rs @@ -1,10 +1,11 @@ -use super::upgrade::print_tree_dir_metadata; use crate::{ cli::InfoArgs, folder_structure::{dir_pretty_print, RelevantDirectories}, version_history::LAST_UPGRADE_VERSION, }; +use super::print_util::print_tree_dir_metadata; + pub fn call_info(args: &InfoArgs) { let path = if let Some(some_path) = &args.path { some_path.as_str() diff --git a/framework/meta/src/cmd/print_util.rs b/framework/meta/src/cmd/print_util.rs index 7b3e0be9b8..e93099f348 100644 --- a/framework/meta/src/cmd/print_util.rs +++ b/framework/meta/src/cmd/print_util.rs @@ -1,6 +1,9 @@ use colored::Colorize; +use multiversx_sc_meta_lib::version::FrameworkVersion; use std::path::Path; +use crate::folder_structure::{DependencyReference, DirectoryType, RelevantDirectory}; + pub fn print_all_count(num_contract_crates: usize) { println!( "\n{}", @@ -24,3 +27,33 @@ pub fn print_all_command(meta_path: &Path, cargo_run_args: &[String]) { cargo_run_args.join(" "), ); } + +pub fn print_tree_dir_metadata(dir: &RelevantDirectory, last_version: &FrameworkVersion) { + match dir.dir_type { + DirectoryType::Contract => print!(" {}", "[contract]".blue()), + DirectoryType::Lib => print!(" {}", "[lib]".magenta()), + } + + match &dir.version { + DependencyReference::Version(version_req) => { + let version_string = format!("[{}]", version_req.semver); + if version_req.semver == *last_version { + print!(" {}", version_string.green()); + } else { + print!(" {}", version_string.red()); + }; + }, + DependencyReference::Git(git_reference) => { + let git_string = format!( + "[git: {} rev: {}]", + git_reference.git.truecolor(255, 127, 0), + git_reference.rev.truecolor(255, 127, 0) + ); + print!(" {}", git_string.truecolor(255, 198, 0)); + }, + DependencyReference::Path(path_buf) => { + let git_string = format!("[path: {}]", path_buf.truecolor(255, 127, 0)); + print!(" {}", git_string.truecolor(255, 198, 0)); + }, + } +} diff --git a/framework/meta/src/cmd/upgrade.rs b/framework/meta/src/cmd/upgrade.rs index ab14b75075..b4b9a28904 100644 --- a/framework/meta/src/cmd/upgrade.rs +++ b/framework/meta/src/cmd/upgrade.rs @@ -8,5 +8,4 @@ mod upgrade_print; mod upgrade_selector; mod upgrade_settings; -pub use upgrade_print::print_tree_dir_metadata; pub use upgrade_selector::upgrade_sc; diff --git a/framework/meta/src/cmd/upgrade/upgrade_print.rs b/framework/meta/src/cmd/upgrade/upgrade_print.rs index 51d66f9333..6c6360c14a 100644 --- a/framework/meta/src/cmd/upgrade/upgrade_print.rs +++ b/framework/meta/src/cmd/upgrade/upgrade_print.rs @@ -1,8 +1,5 @@ use crate::{ - folder_structure::{ - DirectoryType::{Contract, Lib}, - RelevantDirectory, - }, + folder_structure::{DependencyReference, RelevantDirectory}, version::FrameworkVersion, }; use colored::Colorize; @@ -82,20 +79,6 @@ pub fn print_postprocessing_after_39_1(path: &Path) { ); } -pub fn print_tree_dir_metadata(dir: &RelevantDirectory, last_version: &FrameworkVersion) { - match dir.dir_type { - Contract => print!(" {}", "[contract]".blue()), - Lib => print!(" {}", "[lib]".magenta()), - } - - let version_string = format!("[{}]", dir.version.semver); - if dir.version.semver == *last_version { - print!(" {}", version_string.green()); - } else { - print!(" {}", version_string.red()); - }; -} - pub fn print_cargo_dep_remove(path: &Path, dep_name: &str) { println!( "{}/dependencies/{}", @@ -113,15 +96,17 @@ pub fn print_cargo_dep_add(path: &Path, dep_name: &str) { } pub fn print_cargo_check(dir: &RelevantDirectory) { - println!( - "\n{}", - format!( - "Running cargo check after upgrading to version {} in {}\n", - dir.version.semver, - dir.path.display(), - ) - .purple() - ); + if let DependencyReference::Version(version_req) = &dir.version { + println!( + "\n{}", + format!( + "Running cargo check after upgrading to version {} in {}\n", + version_req.semver, + dir.path.display(), + ) + .purple() + ); + } } pub fn print_cargo_check_fail() { diff --git a/framework/meta/src/cmd/upgrade/upgrade_selector.rs b/framework/meta/src/cmd/upgrade/upgrade_selector.rs index 0f958b176e..5031339220 100644 --- a/framework/meta/src/cmd/upgrade/upgrade_selector.rs +++ b/framework/meta/src/cmd/upgrade/upgrade_selector.rs @@ -1,6 +1,6 @@ use crate::{ cli::UpgradeArgs, - cmd::upgrade::upgrade_settings::UpgradeSettings, + cmd::{print_util::print_tree_dir_metadata, upgrade::upgrade_settings::UpgradeSettings}, folder_structure::{dir_pretty_print, RelevantDirectories, RelevantDirectory}, version::FrameworkVersion, version_history::{versions_iter, CHECK_AFTER_UPGRADE_TO, LAST_UPGRADE_VERSION, VERSIONS}, diff --git a/framework/meta/src/folder_structure/relevant_directory.rs b/framework/meta/src/folder_structure/relevant_directory.rs index be0c4ce0ac..a42a7dd27a 100644 --- a/framework/meta/src/folder_structure/relevant_directory.rs +++ b/framework/meta/src/folder_structure/relevant_directory.rs @@ -6,7 +6,7 @@ use std::{ }; use toml::Value; -use super::version_req::VersionReq; +use super::{version_req::VersionReq, DependencyReference, GitReference}; /// Used for retrieving crate versions. pub const FRAMEWORK_CRATE_NAMES: &[&str] = &[ @@ -35,7 +35,7 @@ pub enum DirectoryType { #[derive(Debug, Clone)] pub struct RelevantDirectory { pub path: PathBuf, - pub version: VersionReq, + pub version: DependencyReference, pub upgrade_in_progress: Option<(FrameworkVersion, FrameworkVersion)>, pub dir_type: DirectoryType, } @@ -89,7 +89,7 @@ impl RelevantDirectories { pub fn count_for_version(&self, version: &FrameworkVersion) -> usize { self.0 .iter() - .filter(|dir| dir.version.semver == *version) + .filter(|dir| dir.version.is_framework_version(version)) .count() } @@ -99,13 +99,13 @@ impl RelevantDirectories { ) -> impl Iterator { self.0 .iter() - .filter(move |dir| dir.version.semver == *version) + .filter(move |dir| dir.version.is_framework_version(version)) } /// Marks all appropriate directories as ready for upgrade. pub fn start_upgrade(&mut self, from_version: FrameworkVersion, to_version: FrameworkVersion) { for dir in self.0.iter_mut() { - if dir.version.semver == from_version { + if dir.version.is_framework_version(&from_version) { dir.upgrade_in_progress = Some((from_version.clone(), to_version.clone())); } } @@ -116,7 +116,9 @@ impl RelevantDirectories { pub fn finish_upgrade(&mut self) { for dir in self.0.iter_mut() { if let Some((_, to_version)) = &dir.upgrade_in_progress { - dir.version.semver = to_version.clone(); + if let DependencyReference::Version(version_req) = &mut dir.version { + version_req.semver = to_version.clone(); + } dir.upgrade_in_progress = None; } } @@ -136,7 +138,7 @@ fn populate_directories(path: &Path, ignore: &[String], result: &mut Vec bool { } } -fn find_framework_version_string(cargo_toml_contents: &CargoTomlContents) -> Option { +fn find_framework_toml_dependency( + cargo_toml_contents: &CargoTomlContents, +) -> Option { for &crate_name in FRAMEWORK_CRATE_NAMES { - if let Some(old_base) = cargo_toml_contents.dependency(crate_name) { - if let Some(Value::String(s)) = old_base.get("version") { - return Some(s.clone()); + if let Some(dep_value) = cargo_toml_contents.dependency(crate_name) { + if let Some(Value::String(s)) = dep_value.get("path") { + return Some(DependencyReference::Path(s.clone())); + } + + if let Some(Value::String(git)) = dep_value.get("git") { + let rev = dep_value + .get("rev") + .and_then(|v| v.as_str()) + .unwrap_or_default(); + return Some(DependencyReference::Git(GitReference { + git: git.clone(), + rev: rev.to_owned(), + })); + } + + if let Some(Value::String(s)) = dep_value.get("version") { + return Some(DependencyReference::Version(VersionReq::from_string( + s.clone(), + ))); } } } @@ -200,10 +221,10 @@ impl RelevantDirectory { } } -fn find_framework_version(dir_path: &Path) -> Option { +fn find_framework_dependency(dir_path: &Path) -> Option { if let Some(cargo_toml_contents) = load_cargo_toml_contents(dir_path) { - if let Some(version) = find_framework_version_string(&cargo_toml_contents) { - return Some(VersionReq::from_string(version)); + if let Some(dep_ref) = find_framework_toml_dependency(&cargo_toml_contents) { + return Some(dep_ref); } } diff --git a/framework/meta/src/folder_structure/version_req.rs b/framework/meta/src/folder_structure/version_req.rs index bbfa752a12..8d7863920d 100644 --- a/framework/meta/src/folder_structure/version_req.rs +++ b/framework/meta/src/folder_structure/version_req.rs @@ -3,6 +3,24 @@ use crate::{ version_history::{find_version_by_str, LAST_VERSION}, }; +/// Models how a dependency is expressed in Cargo.toml. +#[derive(Debug, Clone)] +pub enum DependencyReference { + Version(VersionReq), + Git(GitReference), + Path(String), +} + +impl DependencyReference { + pub fn is_framework_version(&self, version: &FrameworkVersion) -> bool { + if let DependencyReference::Version(version_req) = self { + &version_req.semver == version + } else { + false + } + } +} + /// Crate version requirements, as expressed in Cargo.toml. A very crude version. /// /// TODO: replace with semver::VersionReq at some point. @@ -36,3 +54,12 @@ impl VersionReq { } } } + +/// A dependency reference to a git commit. We mostly use git commits when referencing git. +/// +/// TODO: add support for `branch` and `tag`. +#[derive(Debug, Clone)] +pub struct GitReference { + pub git: String, + pub rev: String, +} From 85957f48feaff670fdadb97447c7fd4c454b7ddd Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 12:27:57 +0300 Subject: [PATCH 16/28] abi - title --- .../abi-tester/abi_tester_expected_main.abi.json | 1 + .../feature-tests/abi-tester/src/abi_tester.rs | 1 + framework/base/src/abi/endpoint_abi.rs | 6 ++++-- framework/base/src/external_view_contract.rs | 1 + framework/derive/src/generate/abi_gen.rs | 6 ++++++ framework/derive/src/model/method.rs | 1 + .../src/parse/{attributes/mod.rs => attributes.rs} | 2 +- .../derive/src/parse/attributes/attr_names.rs | 1 + framework/derive/src/parse/attributes/doc_attr.rs | 13 +++++++++++++ framework/derive/src/parse/endpoint_parse.rs | 14 +++++++++++++- framework/derive/src/parse/method_parse.rs | 4 +++- .../meta-lib/src/abi_json/endpoint_abi_json.rs | 5 +++++ .../scenario/tests/contract_without_macros.rs | 4 ++++ 13 files changed, 54 insertions(+), 5 deletions(-) rename framework/derive/src/parse/{attributes/mod.rs => attributes.rs} (93%) diff --git a/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json b/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json index 60edcce7f1..8748ff67aa 100644 --- a/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json +++ b/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json @@ -110,6 +110,7 @@ }, { "name": "multi_result_3", + "title": "result-3", "mutability": "mutable", "inputs": [], "outputs": [ diff --git a/contracts/feature-tests/abi-tester/src/abi_tester.rs b/contracts/feature-tests/abi-tester/src/abi_tester.rs index f5ce735a8c..9405fa28a0 100644 --- a/contracts/feature-tests/abi-tester/src/abi_tester.rs +++ b/contracts/feature-tests/abi-tester/src/abi_tester.rs @@ -58,6 +58,7 @@ pub trait AbiTester { fn take_managed_type(&self, _arg: AbiManagedType) {} #[endpoint] + #[title("result-3")] #[output_name("multi-result-1")] #[output_name("multi-result-2")] #[output_name("multi-result-3")] diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index 03e098d0e9..d8a50f18f0 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -1,7 +1,6 @@ use super::*; use alloc::{ - string::{String, ToString}, - vec::Vec, + borrow::ToOwned, string::{String, ToString}, vec::Vec }; #[derive(Clone, Debug)] @@ -42,6 +41,7 @@ pub struct EndpointAbi { pub docs: Vec, pub name: String, pub rust_method_name: String, + pub title: Option, pub only_owner: bool, pub only_admin: bool, pub labels: Vec, @@ -62,6 +62,7 @@ impl EndpointAbi { docs: &[&str], name: &str, rust_method_name: &str, + title: Option<&str>, only_owner: bool, only_admin: bool, mutability: EndpointMutabilityAbi, @@ -80,6 +81,7 @@ impl EndpointAbi { endpoint_type, mutability, payable_in_tokens: payable_in_tokens.iter().map(|s| s.to_string()).collect(), + title: title.map(|title| title.to_owned()), inputs: Vec::new(), outputs: Vec::new(), allow_multiple_var_args, diff --git a/framework/base/src/external_view_contract.rs b/framework/base/src/external_view_contract.rs index 2b01176176..7a1e0722a7 100644 --- a/framework/base/src/external_view_contract.rs +++ b/framework/base/src/external_view_contract.rs @@ -39,6 +39,7 @@ pub fn external_view_contract_constructor_abi() -> EndpointAbi { ], "init", EXTERNAL_VIEW_CONSTRUCTOR_FLAG, + None, false, false, EndpointMutabilityAbi::Mutable, diff --git a/framework/derive/src/generate/abi_gen.rs b/framework/derive/src/generate/abi_gen.rs index 5d5a73934c..db727cf7c4 100644 --- a/framework/derive/src/generate/abi_gen.rs +++ b/framework/derive/src/generate/abi_gen.rs @@ -15,6 +15,11 @@ fn generate_endpoint_snippet( ) -> proc_macro2::TokenStream { let endpoint_docs = &m.docs; let rust_method_name = m.name.to_string(); + let title_tokens = if let Some(title) = &m.title { + quote! { Some(#title) } + } else { + quote! { None } + }; let payable_in_tokens = m.payable_metadata().abi_strings(); let input_snippets: Vec = m @@ -58,6 +63,7 @@ fn generate_endpoint_snippet( &[ #(#endpoint_docs),* ], #endpoint_name, #rust_method_name, + #title_tokens, #only_owner, #only_admin, #mutability_tokens, diff --git a/framework/derive/src/model/method.rs b/framework/derive/src/model/method.rs index 22acf8eb78..8a4e8ec5eb 100644 --- a/framework/derive/src/model/method.rs +++ b/framework/derive/src/model/method.rs @@ -40,6 +40,7 @@ pub struct Method { pub generics: syn::Generics, pub unprocessed_attributes: Vec, pub method_args: Vec, + pub title: Option, pub output_names: Vec, pub label_names: Vec, pub return_type: syn::ReturnType, diff --git a/framework/derive/src/parse/attributes/mod.rs b/framework/derive/src/parse/attributes.rs similarity index 93% rename from framework/derive/src/parse/attributes/mod.rs rename to framework/derive/src/parse/attributes.rs index e58c1a912e..a5f9906db9 100644 --- a/framework/derive/src/parse/attributes/mod.rs +++ b/framework/derive/src/parse/attributes.rs @@ -11,7 +11,7 @@ mod trait_prop_names; mod util; pub use argument_attr::*; -pub use doc_attr::{extract_doc, extract_macro_attributes, OutputNameAttribute}; +pub use doc_attr::{extract_doc, extract_macro_attributes, OutputNameAttribute, TitleAttribute}; pub use endpoint_attr::*; pub use event_attr::*; pub use label_attr::*; diff --git a/framework/derive/src/parse/attributes/attr_names.rs b/framework/derive/src/parse/attributes/attr_names.rs index 29784fc1c3..5a976e185c 100644 --- a/framework/derive/src/parse/attributes/attr_names.rs +++ b/framework/derive/src/parse/attributes/attr_names.rs @@ -2,6 +2,7 @@ pub(super) static ATTR_PAYABLE: &str = "payable"; pub(super) static ATTR_ONLY_OWNER: &str = "only_owner"; pub(super) static ATTR_ONLY_ADMIN: &str = "only_admin"; pub(super) static ATTR_ONLY_USER_ACCOUNT: &str = "only_user_account"; +pub(super) static ATTR_TITLE: &str = "title"; pub(super) static ATTR_OUTPUT_NAME: &str = "output_name"; pub(super) static ATTR_PAYMENT: &str = "payment"; // synonymous with `payment_amount` pub(super) static ATTR_PAYMENT_AMOUNT: &str = "payment_amount"; diff --git a/framework/derive/src/parse/attributes/doc_attr.rs b/framework/derive/src/parse/attributes/doc_attr.rs index 5c5ed4d41b..c9fc871eef 100644 --- a/framework/derive/src/parse/attributes/doc_attr.rs +++ b/framework/derive/src/parse/attributes/doc_attr.rs @@ -81,3 +81,16 @@ impl OutputNameAttribute { }) } } + + +pub struct TitleAttribute { + pub title: String, +} + +impl TitleAttribute { + pub fn parse(attr: &syn::Attribute) -> Option { + is_attr_one_string_arg(attr, ATTR_TITLE).map(|arg_str| TitleAttribute { + title: arg_str, + }) + } +} diff --git a/framework/derive/src/parse/endpoint_parse.rs b/framework/derive/src/parse/endpoint_parse.rs index 5edc30ad08..26fb612ea6 100644 --- a/framework/derive/src/parse/endpoint_parse.rs +++ b/framework/derive/src/parse/endpoint_parse.rs @@ -8,7 +8,7 @@ use super::{ is_allow_multiple_var_args, is_callback_raw, is_init, is_only_admin, is_only_owner, is_only_user_account, is_upgrade, CallbackAttribute, EndpointAttribute, ExternalViewAttribute, LabelAttribute, OutputNameAttribute, PromisesCallbackAttribute, - ViewAttribute, + TitleAttribute, ViewAttribute, }, MethodAttributesPass1, }; @@ -224,6 +224,18 @@ pub fn process_output_names_attribute(attr: &syn::Attribute, method: &mut Method .is_some() } +pub fn process_title_attribute(attr: &syn::Attribute, method: &mut Method) -> bool { + TitleAttribute::parse(attr) + .map(|title_attr| { + assert!( + method.title.is_none(), + "only one title attribute allowed per method" + ); + method.title = Some(title_attr.title); + }) + .is_some() +} + pub fn process_label_names_attribute(attr: &syn::Attribute, method: &mut Method) -> bool { LabelAttribute::parse(attr) .map(|label_attr| { diff --git a/framework/derive/src/parse/method_parse.rs b/framework/derive/src/parse/method_parse.rs index 481638068a..e299912cdd 100644 --- a/framework/derive/src/parse/method_parse.rs +++ b/framework/derive/src/parse/method_parse.rs @@ -13,7 +13,7 @@ use super::{ process_init_attribute, process_label_names_attribute, process_only_admin_attribute, process_only_owner_attribute, process_only_user_account_attribute, process_output_names_attribute, process_payable_attribute, process_promises_callback_attribute, - process_upgrade_attribute, process_view_attribute, + process_title_attribute, process_upgrade_attribute, process_view_attribute, }; pub struct MethodAttributesPass1 { pub method_name: String, @@ -56,6 +56,7 @@ pub fn process_method(m: &syn::TraitItemFn, trait_attributes: &TraitProperties) generics: m.sig.generics.clone(), unprocessed_attributes: Vec::new(), method_args, + title: None, output_names: Vec::new(), label_names: Vec::new(), return_type: m.sig.output.clone(), @@ -131,6 +132,7 @@ fn process_attribute_second_pass( || process_storage_mapper_from_address_attribute(attr, method) || process_storage_is_empty_attribute(attr, method) || process_storage_clear_attribute(attr, method) + || process_title_attribute(attr, method) || process_output_names_attribute(attr, method) || process_label_names_attribute(attr, method) } diff --git a/framework/meta-lib/src/abi_json/endpoint_abi_json.rs b/framework/meta-lib/src/abi_json/endpoint_abi_json.rs index b6bd041713..0537718e4a 100644 --- a/framework/meta-lib/src/abi_json/endpoint_abi_json.rs +++ b/framework/meta-lib/src/abi_json/endpoint_abi_json.rs @@ -93,6 +93,10 @@ pub struct EndpointAbiJson { pub docs: Vec, pub name: String, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(rename = "onlyOwner")] #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] @@ -128,6 +132,7 @@ impl From<&EndpointAbi> for EndpointAbiJson { EndpointAbiJson { docs: abi.docs.iter().map(|d| d.to_string()).collect(), name: abi.name.to_string(), + title: abi.title.clone(), only_owner: if abi.only_owner { Some(true) } else { None }, only_admin: if abi.only_admin { Some(true) } else { None }, mutability: match abi.mutability { diff --git a/framework/scenario/tests/contract_without_macros.rs b/framework/scenario/tests/contract_without_macros.rs index a08f1a4bbd..7515365023 100644 --- a/framework/scenario/tests/contract_without_macros.rs +++ b/framework/scenario/tests/contract_without_macros.rs @@ -390,6 +390,7 @@ mod sample_adder { &[], "getSum", "sum", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Readonly, @@ -411,6 +412,7 @@ mod sample_adder { &[], "init", "init", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, @@ -426,6 +428,7 @@ mod sample_adder { &[], "upgrade", "upgrade", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, @@ -441,6 +444,7 @@ mod sample_adder { &["Add desired amount to the storage variable."], "add", "add", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, From 7e9d1e9f47a8193045ec1afdf015b604cf5fdb38 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 12:31:35 +0300 Subject: [PATCH 17/28] unified syntax - ReturnsHandledOrError rename --- .../scenario-tester/tests/st_blackbox_test.rs | 10 +++---- .../scenario/src/facade/result_handlers.rs | 4 +-- ...lt_or_err.rs => returns_handled_or_err.rs} | 28 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) rename framework/scenario/src/facade/result_handlers/{returns_result_or_err.rs => returns_handled_or_err.rs} (67%) diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs index 26d907bdfc..00c669e9f5 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -311,7 +311,7 @@ fn st_blackbox_returns_result_or_error() { .new_address(ST_ADDRESS) .tx_hash([33u8; 32]) .returns( - ReturnsResultOrError::new() + ReturnsHandledOrError::new() .returns(ReturnsNewAddress) .returns(ReturnsResultAs::::new()) .returns(ReturnsTxHash), @@ -331,7 +331,7 @@ fn st_blackbox_returns_result_or_error() { .to(ST_ADDRESS) .typed(scenario_tester_proxy::ScenarioTesterProxy) .sum() - .returns(ReturnsResultOrError::new().returns(ReturnsResultUnmanaged)) + .returns(ReturnsHandledOrError::new().returns(ReturnsResultUnmanaged)) .run(); assert_eq!(result, Ok(RustBigUint::from(5u32))); @@ -341,7 +341,7 @@ fn st_blackbox_returns_result_or_error() { .to(ST_ADDRESS) .typed(scenario_tester_proxy::ScenarioTesterProxy) .sc_panic() - .returns(ReturnsResultOrError::new()) + .returns(ReturnsHandledOrError::new()) .run(); assert_eq!(result, Err(TxResponseStatus::new(4, "sc_panic! example"))); @@ -353,7 +353,7 @@ fn st_blackbox_returns_result_or_error() { .to(ST_ADDRESS) .typed(scenario_tester_proxy::ScenarioTesterProxy) .add(1u32) - .returns(ReturnsResultOrError::new()) + .returns(ReturnsHandledOrError::new()) .run(); assert_eq!(result, Ok(())); @@ -365,7 +365,7 @@ fn st_blackbox_returns_result_or_error() { .to(ST_ADDRESS) .typed(scenario_tester_proxy::ScenarioTesterProxy) .sc_panic() - .returns(ReturnsResultOrError::new()) + .returns(ReturnsHandledOrError::new()) .run(); assert_eq!(result, Err(TxResponseStatus::new(4, "sc_panic! example"))); diff --git a/framework/scenario/src/facade/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs index 7a5f0e779b..fe3ad47902 100644 --- a/framework/scenario/src/facade/result_handlers.rs +++ b/framework/scenario/src/facade/result_handlers.rs @@ -6,7 +6,7 @@ mod returns_logs; mod returns_message; mod returns_new_bech32_address; mod returns_new_token_identifier; -mod returns_result_or_err; +mod returns_handled_or_err; mod returns_status; mod returns_tx_hash; mod with_tx_raw_response; @@ -19,7 +19,7 @@ pub use returns_logs::ReturnsLogs; pub use returns_message::ReturnsMessage; pub use returns_new_bech32_address::ReturnsNewBech32Address; pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; -pub use returns_result_or_err::ReturnsResultOrError; +pub use returns_handled_or_err::ReturnsHandledOrError; pub use returns_status::ReturnsStatus; pub use returns_tx_hash::ReturnsTxHash; pub use with_tx_raw_response::WithRawTxResponse; diff --git a/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs b/framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs similarity index 67% rename from framework/scenario/src/facade/result_handlers/returns_result_or_err.rs rename to framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs index d4562eb349..6b3cffdb49 100644 --- a/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs +++ b/framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs @@ -12,57 +12,57 @@ use crate::scenario_model::{CheckValue, TxExpect, TxResponse, TxResponseStatus}; /// Indicates that a `Result` will be returned, either with the handled result, /// according to the inner result handlers, or with an error in case of a failed transaction. -pub struct ReturnsResultOrError +pub struct ReturnsHandledOrError where Env: TxEnv, Ok: RHList, { _phantom_env: PhantomData, _phantom_original: PhantomData, - pub ok_t: Ok, + pub nested_handlers: Ok, } -impl Default for ReturnsResultOrError> +impl Default for ReturnsHandledOrError> where Env: TxEnv, { fn default() -> Self { - ReturnsResultOrError { + ReturnsHandledOrError { _phantom_env: PhantomData, _phantom_original: PhantomData, - ok_t: OriginalResultMarker::new(), + nested_handlers: OriginalResultMarker::new(), } } } -impl ReturnsResultOrError> +impl ReturnsHandledOrError> where Env: TxEnv, { pub fn new() -> Self { - ReturnsResultOrError::default() + ReturnsHandledOrError::default() } } -impl ReturnsResultOrError +impl ReturnsHandledOrError where Env: TxEnv, Ok: RHListExec, { - pub fn returns(self, item: RH) -> ReturnsResultOrError + pub fn returns(self, item: RH) -> ReturnsHandledOrError where RH: RHListItem, Ok: RHListAppendRet, { - ReturnsResultOrError { + ReturnsHandledOrError { _phantom_env: PhantomData, _phantom_original: PhantomData, - ok_t: self.ok_t.append_ret(item), + nested_handlers: self.nested_handlers.append_ret(item), } } } -impl RHListItem for ReturnsResultOrError +impl RHListItem for ReturnsHandledOrError where Env: TxEnv, Ok: RHListExec, @@ -72,7 +72,7 @@ where } impl RHListItemExec - for ReturnsResultOrError + for ReturnsHandledOrError where Env: TxEnv, Ok: RHListExec, @@ -86,7 +86,7 @@ where fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { if raw_result.tx_error.is_success() { - let tuple_result = self.ok_t.list_process_result(raw_result); + let tuple_result = self.nested_handlers.list_process_result(raw_result); Ok(tuple_result.flatten_unpack()) } else { Err(raw_result.tx_error.clone()) From 8e417446d32ea88eea7d13d5b3c24d293ecffc8b Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 12:32:41 +0300 Subject: [PATCH 18/28] cleanup --- .../scenario/src/facade/result_handlers.rs | 4 +-- .../result_handlers/returns_handled_or_err.rs | 35 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/framework/scenario/src/facade/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs index fe3ad47902..454f235b22 100644 --- a/framework/scenario/src/facade/result_handlers.rs +++ b/framework/scenario/src/facade/result_handlers.rs @@ -2,11 +2,11 @@ mod expect_error; mod expect_message; mod expect_status; mod expect_value; +mod returns_handled_or_err; mod returns_logs; mod returns_message; mod returns_new_bech32_address; mod returns_new_token_identifier; -mod returns_handled_or_err; mod returns_status; mod returns_tx_hash; mod with_tx_raw_response; @@ -15,11 +15,11 @@ pub use expect_error::ExpectError; pub use expect_message::ExpectMessage; pub use expect_status::ExpectStatus; pub use expect_value::ExpectValue; +pub use returns_handled_or_err::ReturnsHandledOrError; pub use returns_logs::ReturnsLogs; pub use returns_message::ReturnsMessage; pub use returns_new_bech32_address::ReturnsNewBech32Address; pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; -pub use returns_handled_or_err::ReturnsHandledOrError; pub use returns_status::ReturnsStatus; pub use returns_tx_hash::ReturnsTxHash; pub use with_tx_raw_response::WithRawTxResponse; diff --git a/framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs b/framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs index 6b3cffdb49..12dede24ff 100644 --- a/framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs +++ b/framework/scenario/src/facade/result_handlers/returns_handled_or_err.rs @@ -11,15 +11,15 @@ use multiversx_sc::{ use crate::scenario_model::{CheckValue, TxExpect, TxResponse, TxResponseStatus}; /// Indicates that a `Result` will be returned, either with the handled result, -/// according to the inner result handlers, or with an error in case of a failed transaction. -pub struct ReturnsHandledOrError +/// according to the nested result handlers, or with an error in case of a failed transaction. +pub struct ReturnsHandledOrError where Env: TxEnv, - Ok: RHList, + NHList: RHList, { _phantom_env: PhantomData, _phantom_original: PhantomData, - pub nested_handlers: Ok, + pub nested_handlers: NHList, } impl Default for ReturnsHandledOrError> @@ -44,15 +44,15 @@ where } } -impl ReturnsHandledOrError +impl ReturnsHandledOrError where Env: TxEnv, - Ok: RHListExec, + NHList: RHListExec, { - pub fn returns(self, item: RH) -> ReturnsHandledOrError + pub fn returns(self, item: RH) -> ReturnsHandledOrError where - RH: RHListItem, - Ok: RHListAppendRet, + RH: RHListItem, + NHList: RHListAppendRet, { ReturnsHandledOrError { _phantom_env: PhantomData, @@ -62,21 +62,22 @@ where } } -impl RHListItem for ReturnsHandledOrError +impl RHListItem + for ReturnsHandledOrError where Env: TxEnv, - Ok: RHListExec, - Ok::ListReturns: NestedTupleFlatten, + NHList: RHListExec, + NHList::ListReturns: NestedTupleFlatten, { - type Returns = Result<::Unpacked, TxResponseStatus>; + type Returns = Result<::Unpacked, TxResponseStatus>; } -impl RHListItemExec - for ReturnsHandledOrError +impl RHListItemExec + for ReturnsHandledOrError where Env: TxEnv, - Ok: RHListExec, - Ok::ListReturns: NestedTupleFlatten, + NHList: RHListExec, + NHList::ListReturns: NestedTupleFlatten, { fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { prev.status = CheckValue::Star; From 06d4bf5fb8901cc7893d44753b6fab539c6fc047 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 13:26:15 +0300 Subject: [PATCH 19/28] abi - title in a few contracts --- contracts/core/price-aggregator/src/lib.rs | 1 + contracts/core/wegld-swap/src/wegld.rs | 2 ++ .../examples/crowdfunding-esdt/src/crowdfunding_esdt.rs | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/contracts/core/price-aggregator/src/lib.rs b/contracts/core/price-aggregator/src/lib.rs index 1dbed54848..9d9443dcb5 100644 --- a/contracts/core/price-aggregator/src/lib.rs +++ b/contracts/core/price-aggregator/src/lib.rs @@ -358,6 +358,7 @@ pub trait PriceAggregator: } #[view(getOracles)] + #[title("oracles")] fn get_oracles(&self) -> MultiValueEncoded { let mut result = MultiValueEncoded::new(); for key in self.oracle_status().keys() { diff --git a/contracts/core/wegld-swap/src/wegld.rs b/contracts/core/wegld-swap/src/wegld.rs index 4a38cab09e..23a4493494 100644 --- a/contracts/core/wegld-swap/src/wegld.rs +++ b/contracts/core/wegld-swap/src/wegld.rs @@ -55,12 +55,14 @@ pub trait EgldEsdtSwap: multiversx_sc_modules::pause::PauseModule { } #[view(getLockedEgldBalance)] + #[title("lockedEgldBalance")] fn get_locked_egld_balance(&self) -> BigUint { self.blockchain() .get_sc_balance(&EgldOrEsdtTokenIdentifier::egld(), 0) } #[view(getWrappedEgldTokenId)] + #[title("wrappedEgldTokenId")] #[storage_mapper("wrappedEgldTokenId")] fn wrapped_egld_token_id(&self) -> SingleValueMapper; } diff --git a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs index 1dea493562..d47e256f08 100644 --- a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs +++ b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs @@ -55,6 +55,7 @@ pub trait Crowdfunding { } #[view(getCurrentFunds)] + #[title("currentFunds")] fn get_current_funds(&self) -> BigUint { let token = self.cf_token_identifier().get(); @@ -106,18 +107,22 @@ pub trait Crowdfunding { // storage #[view(getTarget)] + #[title("target")] #[storage_mapper("target")] fn target(&self) -> SingleValueMapper; #[view(getDeadline)] + #[title("deadline")] #[storage_mapper("deadline")] fn deadline(&self) -> SingleValueMapper; #[view(getDeposit)] + #[title("deposit")] #[storage_mapper("deposit")] fn deposit(&self, donor: &ManagedAddress) -> SingleValueMapper; #[view(getCrowdfundingTokenIdentifier)] + #[title("tokenIdentifier")] #[storage_mapper("tokenIdentifier")] fn cf_token_identifier(&self) -> SingleValueMapper; } From 6b5925f9ae5124dd1ef8475c80f4ecc17610676a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 13:26:47 +0300 Subject: [PATCH 20/28] cleanup --- framework/base/src/abi/endpoint_abi.rs | 4 +++- framework/derive/src/parse/attributes/doc_attr.rs | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index d8a50f18f0..c1d0567643 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -1,6 +1,8 @@ use super::*; use alloc::{ - borrow::ToOwned, string::{String, ToString}, vec::Vec + borrow::ToOwned, + string::{String, ToString}, + vec::Vec, }; #[derive(Clone, Debug)] diff --git a/framework/derive/src/parse/attributes/doc_attr.rs b/framework/derive/src/parse/attributes/doc_attr.rs index c9fc871eef..e9485d6368 100644 --- a/framework/derive/src/parse/attributes/doc_attr.rs +++ b/framework/derive/src/parse/attributes/doc_attr.rs @@ -82,15 +82,12 @@ impl OutputNameAttribute { } } - pub struct TitleAttribute { pub title: String, } impl TitleAttribute { pub fn parse(attr: &syn::Attribute) -> Option { - is_attr_one_string_arg(attr, ATTR_TITLE).map(|arg_str| TitleAttribute { - title: arg_str, - }) + is_attr_one_string_arg(attr, ATTR_TITLE).map(|arg_str| TitleAttribute { title: arg_str }) } } From 3677b9f3997634a575a689243d984e854b73b01a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Sun, 13 Oct 2024 20:47:26 +0300 Subject: [PATCH 21/28] unified syntax - removed need for `prepare_async()` --- .../adder/interact/src/basic_interact.rs | 7 --- framework/snippets-base/src/interactor_tx.rs | 2 +- .../src/interactor_tx/interactor_exec_call.rs | 45 +++++++++++++- .../interactor_tx/interactor_exec_deploy.rs | 60 ++++++++++++++++++- .../interactor_tx/interactor_exec_transf.rs | 31 +++++++++- .../interactor_tx/interactor_exec_upgrade.rs | 53 +++++++++++++++- .../interactor_tx/interactor_prepare_async.rs | 6 ++ .../interactor_tx/interactor_query_call.rs | 37 +++++++++++- framework/snippets/src/imports.rs | 2 +- 9 files changed, 229 insertions(+), 14 deletions(-) diff --git a/contracts/examples/adder/interact/src/basic_interact.rs b/contracts/examples/adder/interact/src/basic_interact.rs index b0a4801a4a..f127e1465b 100644 --- a/contracts/examples/adder/interact/src/basic_interact.rs +++ b/contracts/examples/adder/interact/src/basic_interact.rs @@ -118,7 +118,6 @@ impl AdderInteract { .code(ADDER_CODE_PATH) .code_metadata(CodeMetadata::UPGRADEABLE) .returns(ReturnsNewBech32Address) - .prepare_async() .run() .await; @@ -185,7 +184,6 @@ impl AdderInteract { .from(&self.wallet_address) .to(self.state.current_adder_address()) .egld(NumExpr("0,050000000000000000")) - .prepare_async() .run() .await; } @@ -198,7 +196,6 @@ impl AdderInteract { .gas(6_000_000) .typed(adder_proxy::AdderProxy) .add(value) - .prepare_async() .run() .await; @@ -213,7 +210,6 @@ impl AdderInteract { .typed(adder_proxy::AdderProxy) .sum() .returns(ReturnsResultUnmanaged) - .prepare_async() .run() .await; @@ -239,7 +235,6 @@ impl AdderInteract { .code_metadata(CodeMetadata::UPGRADEABLE) .code(ADDER_CODE_PATH) .returns(ExpectError(code, msg)) - .prepare_async() .run() .await; @@ -255,7 +250,6 @@ impl AdderInteract { .upgrade(new_value) .code_metadata(CodeMetadata::UPGRADEABLE) .code(ADDER_CODE_PATH) - .prepare_async() .run() .await; @@ -266,7 +260,6 @@ impl AdderInteract { .typed(adder_proxy::AdderProxy) .sum() .returns(ReturnsResultUnmanaged) - .prepare_async() .run() .await; diff --git a/framework/snippets-base/src/interactor_tx.rs b/framework/snippets-base/src/interactor_tx.rs index 0521300977..c017699468 100644 --- a/framework/snippets-base/src/interactor_tx.rs +++ b/framework/snippets-base/src/interactor_tx.rs @@ -13,6 +13,6 @@ mod interactor_query_step; pub use interactor_exec_env::InteractorEnvExec; pub use interactor_exec_step::InteractorExecStep; -pub use interactor_prepare_async::InteractorPrepareAsync; +pub use interactor_prepare_async::{InteractorPrepareAsync, InteractorRunAsync}; pub use interactor_query_env::InteractorEnvQuery; pub use interactor_query_step::InteractorQueryStep; diff --git a/framework/snippets-base/src/interactor_tx/interactor_exec_call.rs b/framework/snippets-base/src/interactor_tx/interactor_exec_call.rs index eadd122ed2..000daba91a 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_exec_call.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_exec_call.rs @@ -15,7 +15,50 @@ use multiversx_sdk::gateway::GatewayAsyncService; use crate::InteractorBase; -use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; +use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync, InteractorRunAsync}; + +async fn run_async_call<'w, GatewayProxy, From, To, Payment, Gas, RH>( + tx: Tx< + InteractorEnvExec<'w, GatewayProxy>, + From, + To, + Payment, + Gas, + FunctionCall, + RH, + >, +) -> ::Unpacked +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + let mut step_wrapper = tx.tx_to_step(); + step_wrapper.env.world.sc_call(&mut step_wrapper.step).await; + step_wrapper.process_result() +} + +impl<'w, GatewayProxy, From, To, Payment, Gas, RH> InteractorRunAsync + for Tx, From, To, Payment, Gas, FunctionCall, RH> +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Result = ::Unpacked; + + fn run(self) -> impl std::future::Future { + run_async_call(self) + } +} impl<'w, GatewayProxy, From, To, Payment, Gas, RH> InteractorPrepareAsync for Tx, From, To, Payment, Gas, FunctionCall, RH> diff --git a/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs b/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs index 142325e73a..2adbc7eb94 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs @@ -14,7 +14,65 @@ use multiversx_sdk::gateway::GatewayAsyncService; use crate::InteractorBase; -use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; +use super::{ + interactor_prepare_async::InteractorRunAsync, InteractorEnvExec, InteractorExecStep, + InteractorPrepareAsync, +}; + +async fn run_async_deploy<'w, GatewayProxy, From, Payment, Gas, CodeValue, RH>( + tx: Tx< + InteractorEnvExec<'w, GatewayProxy>, + From, + (), + Payment, + Gas, + DeployCall, Code>, + RH, + >, +) -> ::Unpacked +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + let mut step_wrapper = tx.tx_to_step(); + step_wrapper + .env + .world + .sc_deploy(&mut step_wrapper.step) + .await; + step_wrapper.process_result() +} + +impl<'w, GatewayProxy, From, Payment, Gas, CodeValue, RH> InteractorRunAsync + for Tx< + InteractorEnvExec<'w, GatewayProxy>, + From, + (), + Payment, + Gas, + DeployCall, Code>, + RH, + > +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Result = ::Unpacked; + + fn run(self) -> impl std::future::Future { + run_async_deploy(self) + } +} impl<'w, GatewayProxy, From, Payment, Gas, CodeValue, RH> InteractorPrepareAsync for Tx< diff --git a/framework/snippets-base/src/interactor_tx/interactor_exec_transf.rs b/framework/snippets-base/src/interactor_tx/interactor_exec_transf.rs index bef6fb8032..bb7559ba93 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_exec_transf.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_exec_transf.rs @@ -5,7 +5,36 @@ use multiversx_sc_scenario::{ }; use multiversx_sdk::gateway::GatewayAsyncService; -use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; +use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync, InteractorRunAsync}; + +async fn run_async_transfer<'w, GatewayProxy, From, To, Payment, Gas>( + tx: Tx, From, To, Payment, Gas, (), ()>, +) where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, +{ + let step_wrapper = tx.tx_to_step(); + step_wrapper.env.world.transfer(step_wrapper.step).await; +} + +impl<'w, GatewayProxy, From, To, Payment, Gas> InteractorRunAsync + for Tx, From, To, Payment, Gas, (), ()> +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, +{ + type Result = (); + + fn run(self) -> impl std::future::Future { + run_async_transfer(self) + } +} impl<'w, GatewayProxy, From, To, Payment, Gas> InteractorPrepareAsync for Tx, From, To, Payment, Gas, (), ()> diff --git a/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs b/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs index a99b5e3131..982d9568af 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs @@ -15,7 +15,58 @@ use multiversx_sdk::gateway::GatewayAsyncService; use crate::InteractorBase; -use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; +use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync, InteractorRunAsync}; + +async fn run_async_upgrade<'w, GatewayProxy, From, To, Gas, CodeValue, RH>( + tx: Tx< + InteractorEnvExec<'w, GatewayProxy>, + From, + To, + NotPayable, + Gas, + UpgradeCall, Code>, + RH, + >, +) -> ::Unpacked +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + To: TxToSpecified>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + let mut step_wrapper = tx.tx_to_step(); + step_wrapper.env.world.sc_call(&mut step_wrapper.step).await; + step_wrapper.process_result() +} + +impl<'w, GatewayProxy, From, To, Gas, CodeValue, RH> InteractorRunAsync + for Tx< + InteractorEnvExec<'w, GatewayProxy>, + From, + To, + NotPayable, + Gas, + UpgradeCall, Code>, + RH, + > +where + GatewayProxy: GatewayAsyncService, + From: TxFromSpecified>, + To: TxToSpecified>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Result = ::Unpacked; + + fn run(self) -> impl std::future::Future { + run_async_upgrade(self) + } +} impl<'w, GatewayProxy, From, To, Gas, CodeValue, RH> InteractorPrepareAsync for Tx< diff --git a/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs b/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs index 62131b78a2..8eae3f990e 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs @@ -20,3 +20,9 @@ pub trait InteractorPrepareAsync { fn prepare_async(self) -> Self::Exec; } + +pub trait InteractorRunAsync { + type Result; + + fn run(self) -> impl std::future::Future; +} diff --git a/framework/snippets-base/src/interactor_tx/interactor_query_call.rs b/framework/snippets-base/src/interactor_tx/interactor_query_call.rs index 6491a1e34d..70821b831b 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_query_call.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_query_call.rs @@ -12,7 +12,42 @@ use multiversx_sdk::gateway::GatewayAsyncService; use crate::InteractorBase; -use super::{InteractorEnvQuery, InteractorPrepareAsync, InteractorQueryStep}; +use super::{InteractorEnvQuery, InteractorPrepareAsync, InteractorQueryStep, InteractorRunAsync}; + +async fn run_async_query<'w, GatewayProxy, To, Payment, RH>( + tx: Tx, (), To, Payment, (), FunctionCall, RH>, +) -> ::Unpacked +where + GatewayProxy: GatewayAsyncService, + To: TxToSpecified>, + Payment: TxNoPayment>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + let mut step_wrapper = tx.tx_to_query_step(); + step_wrapper + .env + .world + .sc_query(&mut step_wrapper.step) + .await; + step_wrapper.process_result() +} + +impl<'w, GatewayProxy, To, Payment, RH> InteractorRunAsync + for Tx, (), To, Payment, (), FunctionCall, RH> +where + GatewayProxy: GatewayAsyncService, + To: TxToSpecified>, + Payment: TxNoPayment>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Result = ::Unpacked; + + fn run(self) -> impl std::future::Future { + run_async_query(self) + } +} impl<'w, GatewayProxy, To, Payment, RH> InteractorPrepareAsync for Tx, (), To, Payment, (), FunctionCall, RH> diff --git a/framework/snippets/src/imports.rs b/framework/snippets/src/imports.rs index d92d73307c..fa9f8a7728 100644 --- a/framework/snippets/src/imports.rs +++ b/framework/snippets/src/imports.rs @@ -1,7 +1,7 @@ pub use multiversx_sc_snippets_base::multiversx_sc_scenario::imports::*; pub use multiversx_sc_snippets_base::{ - dns_address_for_name, InteractorBase, InteractorPrepareAsync, StepBuffer, + dns_address_for_name, InteractorBase, InteractorPrepareAsync, InteractorRunAsync, StepBuffer, }; pub use multiversx_sc_snippets_base::sdk::{ From 6857224985abd8acc55d8ac7485beecf1f3dcfe2 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Mon, 14 Oct 2024 09:41:58 +0300 Subject: [PATCH 22/28] clippy fix --- .../snippets-base/src/interactor_tx/interactor_exec_deploy.rs | 1 + .../snippets-base/src/interactor_tx/interactor_exec_upgrade.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs b/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs index 2adbc7eb94..8871a90030 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_exec_deploy.rs @@ -19,6 +19,7 @@ use super::{ InteractorPrepareAsync, }; +#[allow(clippy::type_complexity)] async fn run_async_deploy<'w, GatewayProxy, From, Payment, Gas, CodeValue, RH>( tx: Tx< InteractorEnvExec<'w, GatewayProxy>, diff --git a/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs b/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs index 982d9568af..ab04e94846 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_exec_upgrade.rs @@ -17,6 +17,7 @@ use crate::InteractorBase; use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync, InteractorRunAsync}; +#[allow(clippy::type_complexity)] async fn run_async_upgrade<'w, GatewayProxy, From, To, Gas, CodeValue, RH>( tx: Tx< InteractorEnvExec<'w, GatewayProxy>, From 168179d9d144b45dd177b8630d9caa63cfc3faa8 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Mon, 14 Oct 2024 09:57:45 +0300 Subject: [PATCH 23/28] unified syntax - deprecated `prepare_async()` --- .../examples/multisig/interact/src/multisig_interact.rs | 8 -------- .../multisig/interact/src/multisig_interact_nfts.rs | 5 ----- .../multisig/interact/src/multisig_interact_wegld.rs | 3 --- contracts/examples/ping-pong-egld/dapp/src/interactor.rs | 7 ++----- .../ping-pong-egld/dapp/src/requests/transaction.rs | 7 +------ .../basic-features/interact/src/bf_interact.rs | 3 --- .../interact/src/call_tree_calling_functions.rs | 1 - .../generate_snippets/snippet_sc_functions_gen.rs | 8 ++++---- .../src/interactor_tx/interactor_prepare_async.rs | 4 ++++ framework/snippets-dapp/src/imports.rs | 4 +++- .../src/system_sc_interact.rs | 2 ++ 11 files changed, 16 insertions(+), 36 deletions(-) diff --git a/contracts/examples/multisig/interact/src/multisig_interact.rs b/contracts/examples/multisig/interact/src/multisig_interact.rs index c21a772003..3eb44ed228 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact.rs @@ -145,7 +145,6 @@ impl MultisigInteract { .code(&self.multisig_code) .gas(NumExpr("100,000,000")) .returns(ReturnsNewBech32Address) - .prepare_async() .run() .await; @@ -202,7 +201,6 @@ impl MultisigInteract { .from(&self.wallet_address) .to(self.state.current_multisig_address()) .egld(BigUint::from(50_000_000_000_000_000u64)) // 0,05 or 5 * 10^16 - .prepare_async() .run() .await; } @@ -220,7 +218,6 @@ impl MultisigInteract { .gas(gas_expr) .typed(multisig_proxy::MultisigProxy) .perform_action_endpoint(action_id) - .prepare_async() .run() .await; @@ -273,7 +270,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .quorum_reached(action_id) .returns(ReturnsResult) - .prepare_async() .run() .await } @@ -285,7 +281,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .signed(signer, action_id) .returns(ReturnsResult) - .prepare_async() .run() .await } @@ -340,7 +335,6 @@ impl MultisigInteract { .gas(NumExpr("30,000,000")) .typed(multisig_proxy::MultisigProxy) .dns_register(dns_address, name) - .prepare_async() .run() .await; @@ -355,7 +349,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .quorum() .returns(ReturnsResult) - .prepare_async() .run() .await; @@ -370,7 +363,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .num_board_members() .returns(ReturnsResult) - .prepare_async() .run() .await; diff --git a/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs b/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs index 2efda8e4d6..e46411e776 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs @@ -50,7 +50,6 @@ impl MultisigInteract { .argument(&0u32), ) .returns(ReturnsResult) - .prepare_async() .run() .await; @@ -75,7 +74,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .perform_action_endpoint(action_id) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; self.collection_token_identifier = new_token_id.to_string(); @@ -102,7 +100,6 @@ impl MultisigInteract { .argument(&COLLECTION_TICKER), ) .returns(ReturnsResult) - .prepare_async() .run() .await; @@ -127,7 +124,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .perform_action_endpoint(action_id) .returns(ReturnsNewTokenIdentifier) - .prepare_async() .run() .await; self.collection_token_identifier = new_token_id; @@ -156,7 +152,6 @@ impl MultisigInteract { .argument(&"ESDTRoleNFTCreate"), ) .returns(ReturnsResult) - .prepare_async() .run() .await; diff --git a/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs b/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs index 7774bc02d4..2ed1a93b30 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs @@ -56,7 +56,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .propose_async_call(&self.config.wegld_address, WRAP_AMOUNT, function_call) .returns(ReturnsResult) - .prepare_async() .run() .await; @@ -72,7 +71,6 @@ impl MultisigInteract { .typed(wegld_proxy::EgldEsdtSwapProxy) .wrapped_egld_token_id() .returns(ReturnsResult) - .prepare_async() .run() .await; @@ -104,7 +102,6 @@ impl MultisigInteract { .typed(multisig_proxy::MultisigProxy) .propose_async_call(normalized_to, 0u64, normalized_data) .returns(ReturnsResult) - .prepare_async() .run() .await; diff --git a/contracts/examples/ping-pong-egld/dapp/src/interactor.rs b/contracts/examples/ping-pong-egld/dapp/src/interactor.rs index f8841141c0..ba5ca3f3f8 100644 --- a/contracts/examples/ping-pong-egld/dapp/src/interactor.rs +++ b/contracts/examples/ping-pong-egld/dapp/src/interactor.rs @@ -1,13 +1,10 @@ -use imports::{Address, Bech32Address, BytesValue}; -use multiversx_sc_snippets_dapp::*; +use multiversx_sc_snippets_dapp::imports::*; use serde::{Deserialize, Serialize}; -const GATEWAY: &str = sdk::core::gateway::DEVNET_GATEWAY; +const GATEWAY: &str = multiversx_sc_snippets_dapp::sdk::core::gateway::DEVNET_GATEWAY; const CONTRACT_ADDRESS: &str = "erd1qqqqqqqqqqqqqpgq6tqvj5f59xrgxwrtwy30elgpu7l4zrv6d8ssnjdwxq"; const PING_PONG_CODE: &[u8] = include_bytes!("../ping-pong-egld.wasm"); -use multiversx_sc_snippets_dapp::imports::*; - #[derive(Debug, Default, Serialize, Deserialize)] pub struct Config { gateway: String, diff --git a/contracts/examples/ping-pong-egld/dapp/src/requests/transaction.rs b/contracts/examples/ping-pong-egld/dapp/src/requests/transaction.rs index 3765ee63d6..a7629ea8e9 100644 --- a/contracts/examples/ping-pong-egld/dapp/src/requests/transaction.rs +++ b/contracts/examples/ping-pong-egld/dapp/src/requests/transaction.rs @@ -1,8 +1,5 @@ use crate::interactor::ContractInteract; -use multiversx_sc_snippets_dapp::imports::{ - Bech32Address, BigUint, IgnoreValue, InteractorPrepareAsync, OptionalValue, ReturnsMessage, - ReturnsNewBech32Address, ReturnsStatus, -}; +use multiversx_sc_snippets_dapp::imports::*; use super::proxy; @@ -29,7 +26,6 @@ pub async fn deploy_sc() -> Result { .returns(ReturnsNewBech32Address) .returns(ReturnsStatus) .returns(ReturnsMessage) - .prepare_async() .run() .await; @@ -57,7 +53,6 @@ pub async fn ping() -> Result { .typed(proxy::PingPongProxy) .ping(_data) .egld(BigUint::from(amount)) - .prepare_async() .run() .await; diff --git a/contracts/feature-tests/basic-features/interact/src/bf_interact.rs b/contracts/feature-tests/basic-features/interact/src/bf_interact.rs index b971818f2b..57d5e9bfe0 100644 --- a/contracts/feature-tests/basic-features/interact/src/bf_interact.rs +++ b/contracts/feature-tests/basic-features/interact/src/bf_interact.rs @@ -86,7 +86,6 @@ impl BasicFeaturesInteract { .code(&self.code_expr) .gas(NumExpr("4,000,000")) .returns(ReturnsNewBech32Address) - .prepare_async() .run() .await; @@ -103,7 +102,6 @@ impl BasicFeaturesInteract { .gas(NumExpr("600,000,000")) .typed(basic_features_proxy::BasicFeaturesProxy) .store_bytes(value) - .prepare_async() .run() .await; @@ -118,7 +116,6 @@ impl BasicFeaturesInteract { .typed(basic_features_proxy::BasicFeaturesProxy) .load_bytes() .returns(ReturnsResult) - .prepare_async() .run() .await; diff --git a/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs b/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs index 0cb35bdbec..0bd8797f05 100644 --- a/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs +++ b/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs @@ -124,7 +124,6 @@ impl ComposabilityInteract { .to(&root_addr) .typed(forwarder_queue_proxy::ForwarderQueueProxy) .forward_queued_calls() - .prepare_async() .run() .await; diff --git a/framework/meta-lib/src/contract/generate_snippets/snippet_sc_functions_gen.rs b/framework/meta-lib/src/contract/generate_snippets/snippet_sc_functions_gen.rs index d450decd82..b2b5a23d5b 100644 --- a/framework/meta-lib/src/contract/generate_snippets/snippet_sc_functions_gen.rs +++ b/framework/meta-lib/src/contract/generate_snippets/snippet_sc_functions_gen.rs @@ -65,7 +65,7 @@ fn write_deploy_method_impl(file: &mut File, init_abi: &EndpointAbi, name: &Stri .init({}) .code(&self.contract_code) .returns(ReturnsNewAddress) - .prepare_async() + .run() .await; let new_address_bech32 = bech32::encode(&new_address); @@ -101,7 +101,7 @@ fn write_upgrade_endpoint_impl(file: &mut File, upgrade_abi: &EndpointAbi, name: .code(&self.contract_code) .code_metadata(CodeMetadata::UPGRADEABLE) .returns(ReturnsNewAddress) - .prepare_async() + .run() .await; @@ -214,7 +214,7 @@ fn write_contract_call(file: &mut File, endpoint_abi: &EndpointAbi, name: &Strin .typed(proxy::{}Proxy) .{}({}){} .returns(ReturnsResultUnmanaged) - .prepare_async() + .run() .await; @@ -237,7 +237,7 @@ fn write_contract_query(file: &mut File, endpoint_abi: &EndpointAbi, name: &Stri .typed(proxy::{}Proxy) .{}({}) .returns(ReturnsResultUnmanaged) - .prepare_async() + .run() .await; diff --git a/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs b/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs index 8eae3f990e..fcb8f7a7d9 100644 --- a/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs +++ b/framework/snippets-base/src/interactor_tx/interactor_prepare_async.rs @@ -18,6 +18,10 @@ where pub trait InteractorPrepareAsync { type Exec; + #[deprecated( + since = "0.54.0", + note = "Calling `.prepare_async()` no longer necessary, `.run()` can be called directly." + )] fn prepare_async(self) -> Self::Exec; } diff --git a/framework/snippets-dapp/src/imports.rs b/framework/snippets-dapp/src/imports.rs index 2556622174..0f8f13ba35 100644 --- a/framework/snippets-dapp/src/imports.rs +++ b/framework/snippets-dapp/src/imports.rs @@ -1,9 +1,11 @@ pub use crate::multiversx_sc_scenario::imports::*; pub use multiversx_sc_snippets_base::{ - dns_address_for_name, InteractorBase, InteractorPrepareAsync, StepBuffer, + dns_address_for_name, InteractorBase, InteractorPrepareAsync, InteractorRunAsync, StepBuffer, }; pub use multiversx_sdk_dapp::{core::test_wallets, data::keystore::InsertPassword, wallet::Wallet}; +pub use crate::DappInteractor; + pub use env_logger; diff --git a/tools/interactor-system-func-calls/src/system_sc_interact.rs b/tools/interactor-system-func-calls/src/system_sc_interact.rs index 97d72beb01..10830eb072 100644 --- a/tools/interactor-system-func-calls/src/system_sc_interact.rs +++ b/tools/interactor-system-func-calls/src/system_sc_interact.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] // TODO: move prepare_async calls to a test for backwards compatibility and delete from here + mod system_sc_interact_cli; mod system_sc_interact_config; mod system_sc_interact_state; From 2d15689c82952965dfa2df09edb5fb468a553ec2 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 11 Oct 2024 12:26:28 +0300 Subject: [PATCH 24/28] abi - EndpointAbi builder pattern --- framework/base/src/abi/endpoint_abi.rs | 59 +++++++++++++------ framework/base/src/external_view_contract.rs | 16 ++--- framework/derive/src/generate/abi_gen.rs | 40 +++++++++---- .../scenario/tests/contract_without_macros.rs | 31 +--------- 4 files changed, 77 insertions(+), 69 deletions(-) diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index c1d0567643..2705daca95 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -57,39 +57,64 @@ pub struct EndpointAbi { impl EndpointAbi { /// Used in code generation. - /// - /// TODO: replace with builder pattern to gt rid of the too many arguments. - #[allow(clippy::too_many_arguments)] pub fn new( - docs: &[&str], name: &str, rust_method_name: &str, - title: Option<&str>, - only_owner: bool, - only_admin: bool, mutability: EndpointMutabilityAbi, endpoint_type: EndpointTypeAbi, - payable_in_tokens: &[&str], - labels: &[&str], - allow_multiple_var_args: bool, ) -> Self { EndpointAbi { - docs: docs.iter().map(|s| s.to_string()).collect(), + docs: Vec::new(), name: name.to_string(), rust_method_name: rust_method_name.to_string(), - only_owner, - only_admin, - labels: labels.iter().map(|s| s.to_string()).collect(), + only_owner: false, + only_admin: false, + labels: Vec::new(), endpoint_type, mutability, - payable_in_tokens: payable_in_tokens.iter().map(|s| s.to_string()).collect(), - title: title.map(|title| title.to_owned()), + payable_in_tokens: Vec::new(), + title: None, inputs: Vec::new(), outputs: Vec::new(), - allow_multiple_var_args, + allow_multiple_var_args: false, } } + pub fn with_docs(mut self, doc_line: &str) -> Self { + self.docs.push(doc_line.to_owned()); + self + } + + pub fn with_title(mut self, title: &str) -> Self { + self.title = Some(title.to_owned()); + self + } + + pub fn with_only_owner(mut self) -> Self { + self.only_owner = true; + self + } + + pub fn with_only_admin(mut self) -> Self { + self.only_owner = true; + self + } + + pub fn with_allow_multiple_var_args(mut self) -> Self { + self.allow_multiple_var_args = true; + self + } + + pub fn with_label(mut self, label: &str) -> Self { + self.labels.push(label.to_owned()); + self + } + + pub fn with_payable_token(mut self, token: &str) -> Self { + self.payable_in_tokens.push(token.to_owned()); + self + } + pub fn add_input(&mut self, arg_name: &str) { self.inputs.push(InputAbi { arg_name: arg_name.to_string(), diff --git a/framework/base/src/external_view_contract.rs b/framework/base/src/external_view_contract.rs index 7a1e0722a7..4388e74618 100644 --- a/framework/base/src/external_view_contract.rs +++ b/framework/base/src/external_view_contract.rs @@ -32,22 +32,14 @@ where /// The definition for the external view pub fn external_view_contract_constructor_abi() -> EndpointAbi { let mut endpoint_abi = EndpointAbi::new( - &[ - "The external view init prepares a contract that looks in another contract's storage.", - "It takes a single argument, the other contract's address", - "You won't find this constructors' definition in the contract, it gets injected automatically by the framework. See `multiversx_sc::external_view_contract`.", - ], "init", EXTERNAL_VIEW_CONSTRUCTOR_FLAG, - None, - false, - false, EndpointMutabilityAbi::Mutable, EndpointTypeAbi::Init, - &[], - &[], - false - ); + ) + .with_docs("The external view init prepares a contract that looks in another contract's storage.") + .with_docs("It takes a single argument, the other contract's address") + .with_docs("You won't find this constructors' definition in the contract, it gets injected automatically by the framework. See `multiversx_sc::external_view_contract`."); endpoint_abi.inputs.push(InputAbi { arg_name: "target_contract_address".to_string(), type_names: crate::types::heap::Address::type_names(), diff --git a/framework/derive/src/generate/abi_gen.rs b/framework/derive/src/generate/abi_gen.rs index db727cf7c4..0aa70fbc06 100644 --- a/framework/derive/src/generate/abi_gen.rs +++ b/framework/derive/src/generate/abi_gen.rs @@ -15,11 +15,27 @@ fn generate_endpoint_snippet( ) -> proc_macro2::TokenStream { let endpoint_docs = &m.docs; let rust_method_name = m.name.to_string(); - let title_tokens = if let Some(title) = &m.title { - quote! { Some(#title) } + let title_tokens = m + .title + .as_ref() + .map(|title| quote! { .with_title(#title) }) + .unwrap_or_default(); + let only_owner_tokens = if only_owner { + quote! { .with_only_owner() } } else { - quote! { None } + quote! {} }; + let only_admin_tokens = if only_admin { + quote! { .with_only_admin() } + } else { + quote! {} + }; + let allow_multiple_var_args_tokens = if allow_multiple_var_args { + quote! { .with_allow_multiple_var_args() } + } else { + quote! {} + }; + let payable_in_tokens = m.payable_metadata().abi_strings(); let input_snippets: Vec = m @@ -60,18 +76,20 @@ fn generate_endpoint_snippet( quote! { let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( - &[ #(#endpoint_docs),* ], #endpoint_name, #rust_method_name, - #title_tokens, - #only_owner, - #only_admin, #mutability_tokens, #endpoint_type_tokens, - &[ #(#payable_in_tokens),* ], - &[ #(#label_names),* ], - #allow_multiple_var_args, - ); + ) + #(.with_docs(#endpoint_docs))* + #title_tokens + #only_owner_tokens + #only_admin_tokens + #(.with_label(#label_names))* + #(.with_payable_token(#payable_in_tokens))* + #allow_multiple_var_args_tokens + ; + #(#input_snippets)* #output_snippet } diff --git a/framework/scenario/tests/contract_without_macros.rs b/framework/scenario/tests/contract_without_macros.rs index 7515365023..6d445d3fc4 100644 --- a/framework/scenario/tests/contract_without_macros.rs +++ b/framework/scenario/tests/contract_without_macros.rs @@ -387,17 +387,10 @@ mod sample_adder { false, ); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( - &[], "getSum", "sum", - None, - false, - false, multiversx_sc::abi::EndpointMutabilityAbi::Readonly, multiversx_sc::abi::EndpointTypeAbi::Endpoint, - &[], - &[], - false, ); endpoint_abi .add_output::< @@ -409,50 +402,30 @@ mod sample_adder { >(); contract_abi.endpoints.push(endpoint_abi); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( - &[], "init", "init", - None, - false, - false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, multiversx_sc::abi::EndpointTypeAbi::Init, - &[], - &[], - false, ); endpoint_abi.add_input::>("initial_value"); contract_abi.add_type_descriptions::>(); contract_abi.constructors.push(endpoint_abi); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( - &[], "upgrade", "upgrade", - None, - false, - false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, multiversx_sc::abi::EndpointTypeAbi::Upgrade, - &[], - &[], - false, ); endpoint_abi.add_input::>("initial_value"); contract_abi.add_type_descriptions::>(); contract_abi.upgrade_constructors.push(endpoint_abi); let mut endpoint_abi = multiversx_sc::abi::EndpointAbi::new( - &["Add desired amount to the storage variable."], "add", "add", - None, - false, - false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, multiversx_sc::abi::EndpointTypeAbi::Endpoint, - &[], - &[], - false, - ); + ) + .with_docs("Add desired amount to the storage variable."); endpoint_abi.add_input::>("value"); contract_abi.add_type_descriptions::>(); contract_abi.endpoints.push(endpoint_abi); From 53a64a0b4ba96c5b4bec9cedc0ad770d24187d9a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Mon, 14 Oct 2024 10:24:38 +0300 Subject: [PATCH 25/28] abi - fix --- framework/base/src/abi/endpoint_abi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index 2705daca95..8e96554d84 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -96,7 +96,7 @@ impl EndpointAbi { } pub fn with_only_admin(mut self) -> Self { - self.only_owner = true; + self.only_admin = true; self } From fe0fd470f493a09c74089b9141663ddd64051814 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 15 Oct 2024 21:20:42 +0300 Subject: [PATCH 26/28] ReturnCode in chain core and VM --- .../scenario-tester/tests/st_blackbox_test.rs | 16 +++- .../scenario/src/api/impl_vh/debug_api.rs | 8 +- .../src/debug_executor/contract_container.rs | 7 +- .../facade/result_handlers/returns_status.rs | 2 +- framework/scenario/src/imports.rs | 2 + .../scenario/model/transaction/tx_expect.rs | 7 +- .../model/transaction/tx_response_status.rs | 10 +- .../src/scenario/model/value/value_set_u64.rs | 7 ++ .../src/scenario/run_vm/tx_output_check.rs | 2 +- vm-core/src/types/flags.rs | 2 + vm-core/src/types/flags/return_code.rs | 91 +++++++++++++++++++ .../esdt_nft/esdt_local_burn.rs | 3 +- .../esdt_nft/esdt_local_mint.rs | 3 +- .../esdt_nft/esdt_nft_add_quantity_mock.rs | 3 +- .../esdt_nft/esdt_nft_add_uri_mock.rs | 4 +- .../esdt_nft/esdt_nft_burn_mock.rs | 3 +- .../esdt_nft/esdt_nft_create_mock.rs | 3 +- .../esdt_nft_update_attriutes_mock.rs | 4 +- vm/src/tx_execution/exec_call.rs | 4 +- vm/src/tx_mock/tx_async_call_data.rs | 8 +- vm/src/tx_mock/tx_panic.rs | 10 +- vm/src/tx_mock/tx_result.rs | 16 ++-- vm/src/vm_hooks/vh_handler/vh_error.rs | 4 +- vm/src/vm_hooks/vh_impl/vh_debug_api.rs | 15 +-- vm/src/vm_hooks/vh_impl/vh_single_tx_api.rs | 4 +- vm/src/vm_hooks/vh_impl/vh_static_api.rs | 4 +- vm/src/vm_hooks/vh_source.rs | 6 +- 27 files changed, 194 insertions(+), 54 deletions(-) create mode 100644 vm-core/src/types/flags/return_code.rs diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs index 00c669e9f5..5c67ce2a3b 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -344,7 +344,13 @@ fn st_blackbox_returns_result_or_error() { .returns(ReturnsHandledOrError::new()) .run(); - assert_eq!(result, Err(TxResponseStatus::new(4, "sc_panic! example"))); + assert_eq!( + result, + Err(TxResponseStatus::new( + ReturnCode::UserError, + "sc_panic! example" + )) + ); // call - ok let result = world @@ -368,5 +374,11 @@ fn st_blackbox_returns_result_or_error() { .returns(ReturnsHandledOrError::new()) .run(); - assert_eq!(result, Err(TxResponseStatus::new(4, "sc_panic! example"))); + assert_eq!( + result, + Err(TxResponseStatus::new( + ReturnCode::UserError, + "sc_panic! example" + )) + ); } diff --git a/framework/scenario/src/api/impl_vh/debug_api.rs b/framework/scenario/src/api/impl_vh/debug_api.rs index b493047686..43bed2fe5d 100644 --- a/framework/scenario/src/api/impl_vh/debug_api.rs +++ b/framework/scenario/src/api/impl_vh/debug_api.rs @@ -5,7 +5,7 @@ use multiversx_chain_vm::{ tx_mock::{TxContext, TxContextRef, TxContextStack, TxPanic}, vm_hooks::{DebugApiVMHooksHandler, VMHooksDispatcher}, }; -use multiversx_sc::err_msg; +use multiversx_sc::{chain_core::types::ReturnCode, err_msg}; use crate::debug_executor::{StaticVarData, StaticVarStack}; @@ -61,7 +61,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn assert_live_handle(handle: &Self::HandleType) { if !handle.is_on_current_context() { debugger_panic( - err_msg::DEBUG_API_ERR_STATUS, + ReturnCode::DebugApiError, err_msg::DEBUG_API_ERR_HANDLE_STALE, ); } @@ -93,7 +93,7 @@ impl std::fmt::Debug for DebugApi { } } -fn debugger_panic(status: u64, message: &str) { +fn debugger_panic(status: ReturnCode, message: &str) { TxContextRef::new_from_static().replace_tx_result_with_error(TxPanic::new(status, message)); std::panic::panic_any(BreakpointValue::SignalError); } @@ -101,7 +101,7 @@ fn debugger_panic(status: u64, message: &str) { fn assert_handles_on_same_context(handle1: &DebugHandle, handle2: &DebugHandle) { if !handle1.is_on_same_context(handle2) { debugger_panic( - err_msg::DEBUG_API_ERR_STATUS, + ReturnCode::DebugApiError, err_msg::DEBUG_API_ERR_HANDLE_CONTEXT_MISMATCH, ); } diff --git a/framework/scenario/src/debug_executor/contract_container.rs b/framework/scenario/src/debug_executor/contract_container.rs index 8d89062d15..188bd6bdd5 100644 --- a/framework/scenario/src/debug_executor/contract_container.rs +++ b/framework/scenario/src/debug_executor/contract_container.rs @@ -1,6 +1,6 @@ use multiversx_chain_vm::tx_mock::{TxContextRef, TxFunctionName, TxPanic}; use multiversx_chain_vm_executor::{BreakpointValue, ExecutorError, Instance, MemLength, MemPtr}; -use multiversx_sc::contract_base::CallableContract; +use multiversx_sc::{chain_core::types::ReturnCode, contract_base::CallableContract}; use std::sync::Arc; use super::{catch_tx_panic, StaticVarStack}; @@ -81,7 +81,10 @@ impl Instance for ContractContainerRef { if call_successful { Ok(()) } else { - Err(TxPanic::new(1, "invalid function (not found)")) + Err(TxPanic::new( + ReturnCode::FunctionNotFound, + "invalid function (not found)", + )) } }); diff --git a/framework/scenario/src/facade/result_handlers/returns_status.rs b/framework/scenario/src/facade/result_handlers/returns_status.rs index 184163619d..30eba0730c 100644 --- a/framework/scenario/src/facade/result_handlers/returns_status.rs +++ b/framework/scenario/src/facade/result_handlers/returns_status.rs @@ -31,6 +31,6 @@ where } fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { - raw_result.tx_error.status + raw_result.tx_error.status.as_u64() } } diff --git a/framework/scenario/src/imports.rs b/framework/scenario/src/imports.rs index 171862dc9a..b82583b97c 100644 --- a/framework/scenario/src/imports.rs +++ b/framework/scenario/src/imports.rs @@ -24,3 +24,5 @@ pub use crate::{ whitebox_legacy::*, ScenarioTxRun, }; + +pub use crate::multiversx_sc::chain_core::types::ReturnCode; diff --git a/framework/scenario/src/scenario/model/transaction/tx_expect.rs b/framework/scenario/src/scenario/model/transaction/tx_expect.rs index d487a10db5..24c125f207 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_expect.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_expect.rs @@ -8,8 +8,7 @@ use crate::{ scenario_model::Checkable, }; use multiversx_chain_vm::tx_mock::result_values_to_string; - -const USER_ERROR_CODE: u64 = 4; +use multiversx_sc::chain_core::types::ReturnCode; #[derive(Debug, Clone)] pub struct TxExpect { @@ -67,7 +66,7 @@ impl TxExpect { where BytesValue: From, { - Self::err(USER_ERROR_CODE, err_msg_expr) + Self::err(ReturnCode::UserError, err_msg_expr) } pub fn no_result(mut self) -> Self { @@ -100,7 +99,7 @@ impl TxExpect { fn check_response(&self, tx_response: &TxResponse) { assert!( - self.status.check(tx_response.tx_error.status), + self.status.check(tx_response.tx_error.status.as_u64()), "{}result code mismatch. Want: {}. Have: {}. Message: {}", &self.additional_error_message, self.status, diff --git a/framework/scenario/src/scenario/model/transaction/tx_response_status.rs b/framework/scenario/src/scenario/model/transaction/tx_response_status.rs index bdfb888b56..17860ab05f 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_response_status.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_response_status.rs @@ -1,15 +1,17 @@ +use multiversx_sc::chain_core::types::ReturnCode; + #[derive(Debug, Default, Clone, PartialEq, Eq)] /// The status of a transaction. pub struct TxResponseStatus { /// The status of the transaction. - pub status: u64, + pub status: ReturnCode, /// The message of the transaction. pub message: String, } impl TxResponseStatus { /// Creates a [`TxResponseStatus`] - pub fn new(status: u64, message: &str) -> Self { + pub fn new(status: ReturnCode, message: &str) -> Self { Self { status, message: message.to_string(), @@ -18,12 +20,12 @@ impl TxResponseStatus { /// Creates a [`TxResponseStatus`] that signals an error. pub fn signal_error(message: &str) -> Self { - Self::new(4, message) + Self::new(ReturnCode::UserError, message) } /// Checks if the transaction was successful. pub fn is_success(&self) -> bool { - self.status == 0 + self.status.is_success() } } diff --git a/framework/scenario/src/scenario/model/value/value_set_u64.rs b/framework/scenario/src/scenario/model/value/value_set_u64.rs index b332543116..a0305eb9f5 100644 --- a/framework/scenario/src/scenario/model/value/value_set_u64.rs +++ b/framework/scenario/src/scenario/model/value/value_set_u64.rs @@ -4,6 +4,7 @@ use crate::scenario_format::{ value_interpreter::{interpret_string, interpret_subtree}, }; +use multiversx_sc::chain_core::types::ReturnCode; use num_bigint::BigUint; use num_traits::ToPrimitive; use std::fmt; @@ -108,6 +109,12 @@ impl From for U64Value { } } +impl From for U64Value { + fn from(from: ReturnCode) -> Self { + U64Value::from(from.as_u64()) + } +} + impl From<&str> for U64Value { fn from(from: &str) -> Self { U64Value::interpret_from(from, &InterpreterContext::default()) diff --git a/framework/scenario/src/scenario/run_vm/tx_output_check.rs b/framework/scenario/src/scenario/run_vm/tx_output_check.rs index eeec7a1c4e..7a3380de46 100644 --- a/framework/scenario/src/scenario/run_vm/tx_output_check.rs +++ b/framework/scenario/src/scenario/run_vm/tx_output_check.rs @@ -8,7 +8,7 @@ use multiversx_chain_vm::{ pub fn check_tx_output(tx_id: &str, tx_expect: &TxExpect, tx_result: &TxResult) { let have_str = tx_result.result_message.as_str(); assert!( - tx_expect.status.check(tx_result.result_status), + tx_expect.status.check(tx_result.result_status.as_u64()), "result code mismatch. Tx id: '{}'. Want: {}. Have: {}. Message: {}", tx_id, tx_expect.status, diff --git a/vm-core/src/types/flags.rs b/vm-core/src/types/flags.rs index cfe9fc28ef..6b2522c386 100644 --- a/vm-core/src/types/flags.rs +++ b/vm-core/src/types/flags.rs @@ -2,10 +2,12 @@ mod code_metadata; mod esdt_local_role; mod esdt_local_role_flags; mod esdt_token_type; +mod return_code; mod token_type; pub use code_metadata::CodeMetadata; pub use esdt_local_role::EsdtLocalRole; pub use esdt_local_role_flags::EsdtLocalRoleFlags; pub use esdt_token_type::EsdtTokenType; +pub use return_code::ReturnCode; pub use token_type::TokenType; diff --git a/vm-core/src/types/flags/return_code.rs b/vm-core/src/types/flags/return_code.rs new file mode 100644 index 0000000000..d1617f9aaf --- /dev/null +++ b/vm-core/src/types/flags/return_code.rs @@ -0,0 +1,91 @@ +const MESSAGE_OK: &str = "ok"; +const MESSAGE_FUNCTION_NOT_FOUND: &str = "function not found"; +const MESSAGE_WRONG_SIGNATURE: &str = "wrong signature for function"; +const MESSAGE_CONTRACT_NOT_FOUND: &str = "contract not found"; +const MESSAGE_USER_ERROR: &str = "user error"; +const MESSAGE_OUT_OF_GAS: &str = "out of gas"; +const MESSAGE_ACCOUNT_COLLISION: &str = "account collision"; +const MESSAGE_OUT_OF_FUNDS: &str = "out of funds"; +const MESSAGE_CALL_STACK_OVERFLOW: &str = "call stack overflow"; +const MESSAGE_CONTRACT_INVALID: &str = "contract invalid"; +const MESSAGE_EXECUTION_FAILED: &str = "execution failed"; +const MESSAGE_UNKNOWN_ERROR: &str = "unknown error"; + +#[derive(Clone, Copy, Default, PartialEq, Eq, Debug)] +pub enum ReturnCode { + /// Returned when execution was completed normally. + #[default] + Success = 0, + + /// Returned when the input specifies a function name that does not exist or is not public. + FunctionNotFound = 1, + + /// Returned when the wrong number of arguments is provided. + FunctionWrongSignature = 2, + + /// Returned when the called contract does not exist. + ContractNotFound = 3, + + /// Returned for various execution errors. + UserError = 4, + + /// Returned when VM execution runs out of gas. + OutOfGas = 5, + + /// Returned when created account already exists. + AccountCollision = 6, + + /// Returned when the caller (sender) runs out of funds. + OutOfFunds = 7, + + /// Returned when stack overflow occurs. + CallStackOverFlow = 8, + + /// Returned when the contract is invalid. + ContractInvalid = 9, + + /// Returned when the execution of the specified function has failed. + ExecutionFailed = 10, + + /// Returned when the upgrade of the contract has failed + UpgradeFailed = 11, + + /// Returned when tx simulation fails execution + SimulateFailed = 12, + + /// Only occurs in the debugger context. + DebugApiError = 100, +} + +impl ReturnCode { + pub fn as_u64(self) -> u64 { + self as u64 + } + + pub fn is_success(self) -> bool { + self == ReturnCode::Success + } + + pub fn message(self) -> &'static str { + match self { + ReturnCode::Success => MESSAGE_OK, + ReturnCode::FunctionNotFound => MESSAGE_FUNCTION_NOT_FOUND, + ReturnCode::FunctionWrongSignature => MESSAGE_WRONG_SIGNATURE, + ReturnCode::ContractNotFound => MESSAGE_CONTRACT_NOT_FOUND, + ReturnCode::UserError => MESSAGE_USER_ERROR, + ReturnCode::OutOfGas => MESSAGE_OUT_OF_GAS, + ReturnCode::AccountCollision => MESSAGE_ACCOUNT_COLLISION, + ReturnCode::OutOfFunds => MESSAGE_OUT_OF_FUNDS, + ReturnCode::CallStackOverFlow => MESSAGE_CALL_STACK_OVERFLOW, + ReturnCode::ContractInvalid => MESSAGE_CONTRACT_INVALID, + ReturnCode::ExecutionFailed => MESSAGE_EXECUTION_FAILED, + _ => MESSAGE_UNKNOWN_ERROR, + } + } +} + +impl core::fmt::Display for ReturnCode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.as_u64().fmt(f) + } +} diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_burn.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_burn.rs index b3f42b3844..f87af9f766 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_burn.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_burn.rs @@ -1,3 +1,4 @@ +use multiversx_chain_core::types::ReturnCode; use num_bigint::BigUint; use crate::{ @@ -47,7 +48,7 @@ impl BuiltinFunction for ESDTLocalBurn { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_logs: vec![esdt_nft_create_log], ..Default::default() }; diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_mint.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_mint.rs index cb59eee3d5..b82c7ca8b4 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_mint.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_local_mint.rs @@ -1,3 +1,4 @@ +use multiversx_chain_core::types::ReturnCode; use num_bigint::BigUint; use crate::{ @@ -50,7 +51,7 @@ impl BuiltinFunction for ESDTLocalMint { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_logs: vec![esdt_nft_create_log], ..Default::default() }; diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_quantity_mock.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_quantity_mock.rs index 4ef229d686..c773ee80bc 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_quantity_mock.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_quantity_mock.rs @@ -1,3 +1,4 @@ +use multiversx_chain_core::types::ReturnCode; use num_bigint::BigUint; use crate::{ @@ -56,7 +57,7 @@ impl BuiltinFunction for ESDTNftAddQuantity { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_logs: vec![esdt_nft_create_log], ..Default::default() }; diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_uri_mock.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_uri_mock.rs index 3c4d2b986b..9685063fc9 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_uri_mock.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_add_uri_mock.rs @@ -1,3 +1,5 @@ +use multiversx_chain_core::types::ReturnCode; + use crate::{ chain_core::builtin_func_names::ESDT_NFT_ADD_URI_FUNC_NAME, tx_execution::BlockchainVMRef, @@ -53,7 +55,7 @@ impl BuiltinFunction for ESDTNftAddUri { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_logs: vec![esdt_nft_create_log], ..Default::default() }; diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_burn_mock.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_burn_mock.rs index ef6362f073..f92d89efbd 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_burn_mock.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_burn_mock.rs @@ -1,3 +1,4 @@ +use multiversx_chain_core::types::ReturnCode; use num_bigint::BigUint; use crate::{ @@ -53,7 +54,7 @@ impl BuiltinFunction for ESDTNftBurn { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_logs: vec![esdt_nft_create_log], ..Default::default() }; diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_create_mock.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_create_mock.rs index 0007ec3c91..5966330213 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_create_mock.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_create_mock.rs @@ -1,3 +1,4 @@ +use multiversx_chain_core::types::ReturnCode; use num_bigint::BigUint; use crate::{ @@ -79,7 +80,7 @@ impl BuiltinFunction for ESDTNftCreate { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_values: vec![top_encode_u64(new_nonce)], result_logs: vec![esdt_nft_create_log], ..Default::default() diff --git a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_update_attriutes_mock.rs b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_update_attriutes_mock.rs index d6f088f4f6..42a6f965ae 100644 --- a/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_update_attriutes_mock.rs +++ b/vm/src/tx_execution/builtin_function_mocks/esdt_nft/esdt_nft_update_attriutes_mock.rs @@ -1,3 +1,5 @@ +use multiversx_chain_core::types::ReturnCode; + use crate::{ chain_core::builtin_func_names::ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME, tx_execution::BlockchainVMRef, @@ -52,7 +54,7 @@ impl BuiltinFunction for ESDTNftUpdateAttributes { }; let tx_result = TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_logs: vec![esdt_nft_create_log], ..Default::default() }; diff --git a/vm/src/tx_execution/exec_call.rs b/vm/src/tx_execution/exec_call.rs index ffc48e12ae..1b8e50b855 100644 --- a/vm/src/tx_execution/exec_call.rs +++ b/vm/src/tx_execution/exec_call.rs @@ -92,7 +92,7 @@ impl BlockchainVMRef { self.execute_builtin_function_or_default(tx_input, tx_cache, f) }); - if tx_result.result_status == 0 { + if tx_result.result_status.is_success() { blockchain_updates.apply(state); } @@ -155,7 +155,7 @@ impl BlockchainVMRef { // legacy async call // the async call also gets reset - if tx_result.result_status == 0 { + if tx_result.result_status.is_success() { if let Some(async_data) = pending_calls.async_call { let (async_result, callback_result) = self.execute_async_call_and_callback(async_data, state); diff --git a/vm/src/tx_mock/tx_async_call_data.rs b/vm/src/tx_mock/tx_async_call_data.rs index 45cbce639c..ab1b744a3b 100644 --- a/vm/src/tx_mock/tx_async_call_data.rs +++ b/vm/src/tx_mock/tx_async_call_data.rs @@ -56,8 +56,8 @@ pub fn async_callback_tx_input( async_result: &TxResult, builtin_functions: &BuiltinFunctionContainer, ) -> TxInput { - let mut args: Vec> = vec![result_status_bytes(async_result.result_status)]; - if async_result.result_status == 0 { + let mut args: Vec> = vec![result_status_bytes(async_result.result_status.as_u64())]; + if async_result.result_status.is_success() { args.extend_from_slice(async_result.result_values.as_slice()); } else { args.push(async_result.result_message.clone().into_bytes()); @@ -108,7 +108,7 @@ pub fn async_promise_callback_tx_input( async_result: &TxResult, builtin_functions: &BuiltinFunctionContainer, ) -> TxInput { - let callback_name = if async_result.result_status == 0 { + let callback_name = if async_result.result_status.is_success() { promise.success_callback.clone() } else { promise.error_callback.clone() @@ -122,7 +122,7 @@ pub fn async_promise_callback_tx_input( } pub fn merge_results(mut original: TxResult, mut new: TxResult) -> TxResult { - if original.result_status == 0 { + if original.result_status.is_success() { original.result_values.append(&mut new.result_values); original.result_logs.append(&mut new.result_logs); original.result_message = new.result_message; diff --git a/vm/src/tx_mock/tx_panic.rs b/vm/src/tx_mock/tx_panic.rs index 63d1154558..86875f765f 100644 --- a/vm/src/tx_mock/tx_panic.rs +++ b/vm/src/tx_mock/tx_panic.rs @@ -1,11 +1,13 @@ +use multiversx_chain_core::types::ReturnCode; + #[derive(Debug, Clone)] pub struct TxPanic { - pub status: u64, + pub status: ReturnCode, pub message: String, } impl TxPanic { - pub fn new(status: u64, message: &str) -> Self { + pub fn new(status: ReturnCode, message: &str) -> Self { Self { status, message: message.to_string(), @@ -13,10 +15,10 @@ impl TxPanic { } pub fn user_error(message: &str) -> TxPanic { - TxPanic::new(4, message) + TxPanic::new(ReturnCode::UserError, message) } pub fn vm_error(message: &str) -> TxPanic { - TxPanic::new(10, message) + TxPanic::new(ReturnCode::ExecutionFailed, message) } } diff --git a/vm/src/tx_mock/tx_result.rs b/vm/src/tx_mock/tx_result.rs index 4234f3a207..68a5319948 100644 --- a/vm/src/tx_mock/tx_result.rs +++ b/vm/src/tx_mock/tx_result.rs @@ -1,11 +1,13 @@ use std::fmt; +use multiversx_chain_core::types::ReturnCode; + use super::{AsyncCallTxData, TxLog, TxPanic, TxResultCalls}; #[derive(Clone, Debug)] #[must_use] pub struct TxResult { - pub result_status: u64, + pub result_status: ReturnCode, pub result_message: String, pub result_values: Vec>, pub result_logs: Vec, @@ -24,7 +26,7 @@ pub struct TxResult { impl Default for TxResult { fn default() -> Self { TxResult { - result_status: 0, + result_status: ReturnCode::Success, result_message: String::new(), result_values: Vec::new(), result_logs: Vec::new(), @@ -55,7 +57,7 @@ impl TxResult { pub fn from_panic_string(s: &str) -> Self { TxResult { - result_status: 4, + result_status: ReturnCode::UserError, result_message: s.to_string(), result_values: Vec::new(), result_logs: Vec::new(), @@ -72,7 +74,7 @@ impl TxResult { S: Into, { TxResult { - result_status: 10, + result_status: ReturnCode::ExecutionFailed, result_message: result_message.into(), ..Default::default() } @@ -94,7 +96,7 @@ impl TxResult { pub fn assert_ok(&self) { assert!( - self.result_status == 0, + self.result_status.is_success(), "Tx success expected, but failed. Status: {}, message: \"{}\"", self.result_status, self.result_message.as_str() @@ -111,7 +113,7 @@ impl TxResult { self.result_message.as_str() ); assert!( - self.result_status == expected_status, + self.result_status.as_u64() == expected_status, "Tx error status mismatch. Want status {}, message \"{}\". Have status {}, message \"{}\"", expected_status, expected_message, @@ -121,7 +123,7 @@ impl TxResult { } pub fn assert_user_error(&self, expected_message: &str) { - self.assert_error(4, expected_message); + self.assert_error(ReturnCode::UserError.as_u64(), expected_message); } } diff --git a/vm/src/vm_hooks/vh_handler/vh_error.rs b/vm/src/vm_hooks/vh_handler/vh_error.rs index ac1b4b4448..9b72740c94 100644 --- a/vm/src/vm_hooks/vh_handler/vh_error.rs +++ b/vm/src/vm_hooks/vh_handler/vh_error.rs @@ -1,3 +1,5 @@ +use multiversx_chain_core::types::ReturnCode; + use crate::{types::RawHandle, vm_hooks::VMHooksHandlerSource}; use super::VMHooksManagedTypes; @@ -8,7 +10,7 @@ pub trait VMHooksError: VMHooksHandlerSource { // run `clear & cargo test -- --nocapture` to see the output println!("{}", std::str::from_utf8(message).unwrap()); - self.halt_with_error(4, std::str::from_utf8(message).unwrap()) + self.halt_with_error(ReturnCode::UserError, std::str::from_utf8(message).unwrap()) } } diff --git a/vm/src/vm_hooks/vh_impl/vh_debug_api.rs b/vm/src/vm_hooks/vh_impl/vh_debug_api.rs index 618788d966..e4ef791d1b 100644 --- a/vm/src/vm_hooks/vh_impl/vh_debug_api.rs +++ b/vm/src/vm_hooks/vh_impl/vh_debug_api.rs @@ -1,5 +1,6 @@ use std::sync::{Arc, MutexGuard}; +use multiversx_chain_core::types::ReturnCode; use multiversx_chain_vm_executor::BreakpointValue; use crate::{ @@ -36,10 +37,10 @@ impl VMHooksHandlerSource for DebugApiVMHooksHandler { self.0.m_types_lock() } - fn halt_with_error(&self, status: u64, message: &str) -> ! { + fn halt_with_error(&self, status: ReturnCode, message: &str) -> ! { *self.0.result_lock() = TxResult::from_panic_obj(&TxPanic::new(status, message)); let breakpoint = match status { - 4 => BreakpointValue::SignalError, + ReturnCode::UserError => BreakpointValue::SignalError, _ => BreakpointValue::ExecutionFailed, }; std::panic::panic_any(breakpoint); @@ -127,7 +128,7 @@ impl VMHooksHandlerSource for DebugApiVMHooksHandler { execute_current_tx_context_input, ); - if tx_result.result_status == 0 { + if tx_result.result_status.is_success() { self.sync_call_post_processing(tx_result, blockchain_updates) } else { // also kill current execution @@ -168,11 +169,11 @@ impl VMHooksHandlerSource for DebugApiVMHooksHandler { ); match tx_result.result_status { - 0 => ( + ReturnCode::UserError => ( new_address, self.sync_call_post_processing(tx_result, blockchain_updates), ), - 10 => self.vm_error(&tx_result.result_message), // TODO: not sure it's the right condition, it catches insufficient funds + ReturnCode::ExecutionFailed => self.vm_error(&tx_result.result_message), // TODO: not sure it's the right condition, it catches insufficient funds _ => self.vm_error(vm_err_msg::ERROR_SIGNALLED_BY_SMARTCONTRACT), } } @@ -198,12 +199,12 @@ impl VMHooksHandlerSource for DebugApiVMHooksHandler { ); match tx_result.result_status { - 0 => { + ReturnCode::UserError => { self.0.result_lock().all_calls.push(async_call_data); let _ = self.sync_call_post_processing(tx_result, blockchain_updates); }, - 10 => self.vm_error(&tx_result.result_message), // TODO: not sure it's the right condition, it catches insufficient funds + ReturnCode::ExecutionFailed => self.vm_error(&tx_result.result_message), // TODO: not sure it's the right condition, it catches insufficient funds _ => self.vm_error(vm_err_msg::ERROR_SIGNALLED_BY_SMARTCONTRACT), } } diff --git a/vm/src/vm_hooks/vh_impl/vh_single_tx_api.rs b/vm/src/vm_hooks/vh_impl/vh_single_tx_api.rs index 27fa484a4a..d29eb20ef4 100644 --- a/vm/src/vm_hooks/vh_impl/vh_single_tx_api.rs +++ b/vm/src/vm_hooks/vh_impl/vh_single_tx_api.rs @@ -3,6 +3,8 @@ use std::{ sync::{Arc, Mutex, MutexGuard}, }; +use multiversx_chain_core::types::ReturnCode; + use crate::{ tx_mock::{BackTransfers, TxFunctionName, TxInput, TxManagedTypes, TxResult}, types::{VMAddress, VMCodeMetadata}, @@ -57,7 +59,7 @@ impl VMHooksHandlerSource for SingleTxApiVMHooksHandler { self.0.managed_types.lock().unwrap() } - fn halt_with_error(&self, status: u64, message: &str) -> ! { + fn halt_with_error(&self, status: ReturnCode, message: &str) -> ! { panic!("VM error occured, status: {status}, message: {message}") } diff --git a/vm/src/vm_hooks/vh_impl/vh_static_api.rs b/vm/src/vm_hooks/vh_impl/vh_static_api.rs index aba07908e0..9f9a445b37 100644 --- a/vm/src/vm_hooks/vh_impl/vh_static_api.rs +++ b/vm/src/vm_hooks/vh_impl/vh_static_api.rs @@ -1,5 +1,7 @@ use std::sync::{Mutex, MutexGuard}; +use multiversx_chain_core::types::ReturnCode; + use crate::{ tx_mock::{BackTransfers, TxFunctionName, TxInput, TxLog, TxManagedTypes, TxResult}, types::{VMAddress, VMCodeMetadata}, @@ -28,7 +30,7 @@ impl VMHooksHandlerSource for StaticApiVMHooksHandler { self.0.lock().unwrap() } - fn halt_with_error(&self, status: u64, message: &str) -> ! { + fn halt_with_error(&self, status: ReturnCode, message: &str) -> ! { panic!("VM error occured, status: {status}, message: {message}") } diff --git a/vm/src/vm_hooks/vh_source.rs b/vm/src/vm_hooks/vh_source.rs index 0ad2e59e2a..7370c09e87 100644 --- a/vm/src/vm_hooks/vh_source.rs +++ b/vm/src/vm_hooks/vh_source.rs @@ -1,5 +1,7 @@ use std::{fmt::Debug, sync::MutexGuard}; +use multiversx_chain_core::types::ReturnCode; + use crate::{ tx_mock::{BackTransfers, TxFunctionName, TxInput, TxLog, TxManagedTypes, TxResult}, types::{VMAddress, VMCodeMetadata, H256}, @@ -10,10 +12,10 @@ use crate::{ pub trait VMHooksHandlerSource: Debug { fn m_types_lock(&self) -> MutexGuard; - fn halt_with_error(&self, status: u64, message: &str) -> !; + fn halt_with_error(&self, status: ReturnCode, message: &str) -> !; fn vm_error(&self, message: &str) -> ! { - self.halt_with_error(10, message) + self.halt_with_error(ReturnCode::ExecutionFailed, message) } fn input_ref(&self) -> &TxInput; From 5a265f6c06055eee973852e75a65066791f1ee3d Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 15 Oct 2024 21:58:55 +0300 Subject: [PATCH 27/28] bugfix --- vm/src/vm_hooks/vh_impl/vh_debug_api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/src/vm_hooks/vh_impl/vh_debug_api.rs b/vm/src/vm_hooks/vh_impl/vh_debug_api.rs index e4ef791d1b..20ba8d20b3 100644 --- a/vm/src/vm_hooks/vh_impl/vh_debug_api.rs +++ b/vm/src/vm_hooks/vh_impl/vh_debug_api.rs @@ -169,7 +169,7 @@ impl VMHooksHandlerSource for DebugApiVMHooksHandler { ); match tx_result.result_status { - ReturnCode::UserError => ( + ReturnCode::Success => ( new_address, self.sync_call_post_processing(tx_result, blockchain_updates), ), @@ -199,7 +199,7 @@ impl VMHooksHandlerSource for DebugApiVMHooksHandler { ); match tx_result.result_status { - ReturnCode::UserError => { + ReturnCode::Success => { self.0.result_lock().all_calls.push(async_call_data); let _ = self.sync_call_post_processing(tx_result, blockchain_updates); From 2c692827b38b608b3161090a211a62e6357c7710 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 15 Oct 2024 21:59:06 +0300 Subject: [PATCH 28/28] example cleanup --- sdk/http/examples/generate_mnemonic.rs | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 sdk/http/examples/generate_mnemonic.rs diff --git a/sdk/http/examples/generate_mnemonic.rs b/sdk/http/examples/generate_mnemonic.rs deleted file mode 100644 index 2dcb1b6ed9..0000000000 --- a/sdk/http/examples/generate_mnemonic.rs +++ /dev/null @@ -1,9 +0,0 @@ -use multiversx_sdk::wallet::Wallet; - -fn main() { - let mnemonic = Wallet::generate_mnemonic(); - println!("mnemonic: {mnemonic}"); - - let private_key = Wallet::get_private_key_from_mnemonic(mnemonic, 0, 0); - println!("private key: {:?}", private_key.to_string()); -}