From 4bb710087afad78cbb081f2a71b7e39f50083210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Bilge=20Yal=C3=A7=C4=B1nkaya?= Date: Fri, 2 Aug 2024 12:25:05 +0300 Subject: [PATCH] Storage Host Functions (#18) * Implement `loadObjectFull` for converting HostVals to ScVals on the stack * add wasm tests * add rust test * define storage configuration cells * implement host functions * Set Version: 0.1.14 --------- Co-authored-by: devops --- package/version | 2 +- pyproject.toml | 2 +- .../kdist/soroban-semantics/configuration.md | 58 ++- .../kdist/soroban-semantics/host/hostfuns.md | 2 + .../kdist/soroban-semantics/host/ledger.md | 147 ++++++ src/tests/integration/data/increment.wast | 180 +++++++ .../soroban/contracts/test_storage/Cargo.toml | 15 + .../soroban/contracts/test_storage/README.md | 18 + .../soroban/contracts/test_storage/src/lib.rs | 33 ++ .../integration/data/struct_storage.wast | 451 ++++++++++++++++++ 10 files changed, 902 insertions(+), 6 deletions(-) create mode 100644 src/ksoroban/kdist/soroban-semantics/host/ledger.md create mode 100644 src/tests/integration/data/increment.wast create mode 100644 src/tests/integration/data/soroban/contracts/test_storage/Cargo.toml create mode 100644 src/tests/integration/data/soroban/contracts/test_storage/README.md create mode 100644 src/tests/integration/data/soroban/contracts/test_storage/src/lib.rs create mode 100644 src/tests/integration/data/struct_storage.wast diff --git a/package/version b/package/version index 7ac4e5e..71d6a66 100644 --- a/package/version +++ b/package/version @@ -1 +1 @@ -0.1.13 +0.1.14 diff --git a/pyproject.toml b/pyproject.toml index 4773f4a..58da002 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "ksoroban" -version = "0.1.13" +version = "0.1.14" description = "K tooling for the Soroban platform" authors = [ "Runtime Verification, Inc. ", diff --git a/src/ksoroban/kdist/soroban-semantics/configuration.md b/src/ksoroban/kdist/soroban-semantics/configuration.md index be4d9e6..9bb0611 100644 --- a/src/ksoroban/kdist/soroban-semantics/configuration.md +++ b/src/ksoroban/kdist/soroban-semantics/configuration.md @@ -32,7 +32,19 @@ module CONFIG Contract(.Bytes) .Bytes - .Map +``` + +- `instanceStorage`: Instance storage is a map from user-provided keys (ScVal) to values (ScVal), and it is tied to the + contract's lifecycle. + If the value is a container (e.g., map or vector), the contained values must also be `ScVal`, not `HostVal`. + Therefore, before storing data, all `HostVal`s in the data should be resolved to `ScVal`s. + Other storage types (persistent and temporary) are stored separately in ``. + + - [Stellar Docs](https://developers.stellar.org/docs/learn/encyclopedia/storage/persisting-data#ledger-entries) + - [CAP 46-05: Instance Storage](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-05.md#instance-storage) + +```k + .Map // Map of ScVal to ScVal @@ -41,6 +53,13 @@ module CONFIG 0 +``` +- `contractData`: Stores persistent and temporary storage items separately from the contract instances. + The storage entries are identified by `(ContractId, Durability, ScVal)` and contain values of type `ScVal`. + Keys and values must be fully resolved `ScVal`s as in ``. + +```k + .Map // Map of StorageKey to ScVal .Map ``` @@ -59,6 +78,14 @@ module CONFIG syntax InternalCmd ::= #callResult(ValStack, List) [symbol(#callResult)] + syntax Durability ::= "#temporary" [symbol(#temporary)] + | "#persistent" [symbol(#persistent)] + + syntax StorageType ::= Durability + | "#instance" [symbol(#instance)] + + syntax StorageKey ::= #skey( ContractId , Durability , ScVal ) [symbol(StorageKey)] + endmodule ``` @@ -131,25 +158,27 @@ These internal commands manages the call stack when calling and returning from a syntax AccountsCellFragment syntax ContractsCellFragment - syntax Accounts ::= "{" AccountsCellFragment "," ContractsCellFragment "}" + syntax Accounts ::= "{" AccountsCellFragment "," ContractsCellFragment "," Map "}" // -------------------------------------------------------- syntax InternalCmd ::= "pushWorldState" [symbol(pushWorldState)] // --------------------------------------- rule [pushWorldState]: pushWorldState => .K ... - (.List => ListItem({ ACCTDATA , CONTRACTS })) ... + (.List => ListItem({ ACCTDATA , CONTRACTS , CTRDATA })) ... CONTRACTS ACCTDATA + CTRDATA [priority(60)] syntax InternalCmd ::= "popWorldState" [symbol(popWorldState)] // -------------------------------------- rule [popWorldState]: popWorldState => .K ... - (ListItem({ ACCTDATA , CONTRACTS }) => .List) ... + (ListItem({ ACCTDATA , CONTRACTS , CTRDATA }) => .List) ... _ => CONTRACTS _ => ACCTDATA + _ => CTRDATA [priority(60)] syntax InternalCmd ::= "dropWorldState" [symbol(dropWorldState)] @@ -276,6 +305,7 @@ If `SCV` is a small value, `allocObject(SCV)` returns a small `HostVal` directly ### Accessing host objects +- loadObject: Load a host object from `` to `` ```k syntax InternalInstr ::= loadObject(HostVal) [symbol(loadObject)] @@ -306,6 +336,26 @@ If `SCV` is a small value, `allocObject(SCV)` returns a small `HostVal` directly requires notBool isObject(VAL) andBool fromSmallValid(VAL) +``` + +- loadObjectFull: Like `loadObject` but resolves all `HostVal`s in containers recursively using `HostVal2ScValRec` + +```k + syntax InternalInstr ::= loadObjectFull(HostVal) [symbol(loadObjectFull)] + | "loadObjectFullAux" + // -------------------------------------------------------------------- + rule [loadObjectFull]: + loadObjectFull(VAL) + => loadObject(VAL) + ~> loadObjectFullAux + ... + + + rule [loadObjectFullAux]: + loadObjectFullAux => .K ... + (SCV => HostVal2ScValRec(SCV, OBJS, RELS)) : _ + RELS + OBJS ``` diff --git a/src/ksoroban/kdist/soroban-semantics/host/hostfuns.md b/src/ksoroban/kdist/soroban-semantics/host/hostfuns.md index 1f2defe..5702f25 100644 --- a/src/ksoroban/kdist/soroban-semantics/host/hostfuns.md +++ b/src/ksoroban/kdist/soroban-semantics/host/hostfuns.md @@ -2,6 +2,7 @@ ```k requires "context.md" requires "integer.md" +requires "ledger.md" requires "map.md" requires "symbol.md" requires "vector.md" @@ -9,6 +10,7 @@ requires "vector.md" module HOSTFUNS imports HOST-CONTEXT imports HOST-INTEGER + imports HOST-LEDGER imports HOST-MAP imports HOST-SYMBOL imports HOST-VECTOR diff --git a/src/ksoroban/kdist/soroban-semantics/host/ledger.md b/src/ksoroban/kdist/soroban-semantics/host/ledger.md new file mode 100644 index 0000000..8987300 --- /dev/null +++ b/src/ksoroban/kdist/soroban-semantics/host/ledger.md @@ -0,0 +1,147 @@ +# Ledger Host Functions + +```k +requires "integer.md" + +module HOST-LEDGER + imports HOST-INTEGER + +``` + +## put_contract_data + +```k + rule [hostfun-put-contract-data]: + hostCall ( "l" , "_" , [ i64 i64 i64 .ValTypes ] -> [ i64 .ValTypes ] ) + => loadObjectFull(HostVal(VAL)) + ~> loadObjectFull(HostVal(KEY)) + ~> putContractData(Int2StorageType(STORAGE_TYPE)) + ... + + + 0 |-> < i64 > KEY // HostVal + 1 |-> < i64 > VAL // HostVal + 2 |-> < i64 > STORAGE_TYPE // 0: temp, 1: persistent, 2: instance + + requires Int2StorageTypeValid(STORAGE_TYPE) + + syntax InternalInstr ::= putContractData(StorageType) [symbol(putContractData)] + // --------------------------------------------------------------------------------- + rule [putContractData-instance]: + putContractData(#instance) => toSmall(Void) ... + KEY : VAL : S => S + CONTRACT + + CONTRACT + STORAGE => STORAGE [ KEY <- VAL ] + ... + + + rule [putContractData-other]: + putContractData(DUR:Durability) => toSmall(Void) ... + KEY : VAL : S => S + CONTRACT + + STORAGE => STORAGE [ #skey(CONTRACT, DUR, KEY) <- VAL ] + + +``` + +## has_contract_data + +```k + rule [hostfun-has-contract-data]: + hostCall ( "l" , "0" , [ i64 i64 .ValTypes ] -> [ i64 .ValTypes ] ) + => loadObjectFull(HostVal(KEY)) + ~> hasContractData(Int2StorageType(STORAGE_TYPE)) + ... + + + 0 |-> < i64 > KEY // HostVal + 1 |-> < i64 > STORAGE_TYPE // 0: temp, 1: persistent, 2: instance + + requires Int2StorageTypeValid(STORAGE_TYPE) + + syntax InternalInstr ::= hasContractData(StorageType) [symbol(hasContractData)] + // --------------------------------------------------------------------------------- + rule [hasContractData-instance]: + hasContractData(#instance) + => toSmall(SCBool( KEY in_keys(STORAGE) )) + ... + + KEY : S => S + CONTRACT + + CONTRACT + STORAGE + ... + + + rule [hasContractData-other]: + hasContractData(DUR:Durability) + => toSmall(SCBool( #skey(CONTRACT, DUR, KEY) in_keys(STORAGE) )) + ... + + KEY : S => S + CONTRACT + STORAGE +``` + +## get_contract_data + +```k + rule [hostfun-get-contract-data]: + hostCall ( "l" , "1" , [ i64 i64 .ValTypes ] -> [ i64 .ValTypes ] ) + => loadObjectFull(HostVal(KEY)) + ~> getContractData(Int2StorageType(STORAGE_TYPE)) + ... + + + 0 |-> < i64 > KEY // HostVal + 1 |-> < i64 > STORAGE_TYPE // 0: temp, 1: persistent, 2: instance + + requires Int2StorageTypeValid(STORAGE_TYPE) + + syntax InternalInstr ::= getContractData(StorageType) [symbol(getContractData)] + // --------------------------------------------------------------------------------- + rule [getContractData-instance]: + getContractData(#instance) + => allocObject(VAL) + ~> returnHostVal + ... + + KEY : S => S + CONTRACT + + CONTRACT + ... KEY |-> VAL ... + ... + + + rule [getContractData-other]: + getContractData(DUR:Durability) + => allocObject(VAL) + ~> returnHostVal + ... + + KEY : S => S + CONTRACT + ... #skey(CONTRACT, DUR, KEY) |-> VAL ... + +``` + +## Helpers + +```k + syntax StorageType ::= Int2StorageType(Int) [function, total] + // ------------------------------------------------------------------------------- + rule Int2StorageType(0) => #temporary + rule Int2StorageType(1) => #persistent + rule Int2StorageType(_) => #instance [owise] + + syntax Bool ::= Int2StorageTypeValid(Int) [function, total] + // ------------------------------------------------------------ + rule Int2StorageTypeValid(I) => 0 <=Int I andBool I <=Int 2 + +endmodule +``` \ No newline at end of file diff --git a/src/tests/integration/data/increment.wast b/src/tests/integration/data/increment.wast new file mode 100644 index 0000000..c3b76ff --- /dev/null +++ b/src/tests/integration/data/increment.wast @@ -0,0 +1,180 @@ + +setExitCode(1) + +uploadWasm( b"test-wasm", + +;; Increment contract with two integer counters and one endpoint, `increment`. +;; `increment` takes a boolean to select a counter, increments the chosen counter by one, and returns the updated value. + +;; #![no_std] +;; use soroban_sdk::{contract, contractimpl, log, symbol_short, Env, Symbol}; + +;; const COUNTER1: Symbol = symbol_short!("COUNTER1"); +;; const COUNTER2: Symbol = symbol_short!("COUNTER2"); + +;; #[contract] +;; pub struct IncrementContract; + +;; #[contractimpl] +;; impl IncrementContract { +;; pub fn increment(env: Env, p: bool) -> u32 { +;; let counter = if p { COUNTER1 } else { COUNTER2 }; +;; let mut count: u32 = env.storage().instance().get(&counter).unwrap_or(0); + +;; count += 1; + +;; log!(&env, "count: {}", count); + +;; env.storage().instance().set(&counter, &count); + +;; count +;; } +;; } +(module $soroban_increment_contract.wasm + (type (;0;) (func (param i64 i64) (result i64))) + (type (;1;) (func (param i64 i64 i64) (result i64))) + (type (;2;) (func (param i64) (result i64))) + (type (;3;) (func)) + (import "l" "0" (func $_ZN17soroban_env_guest5guest6ledger17has_contract_data17h79546e647e9b20a7E (type 0))) + (import "l" "1" (func $_ZN17soroban_env_guest5guest6ledger17get_contract_data17h472f93112d86127fE (type 0))) + (import "l" "_" (func $_ZN17soroban_env_guest5guest6ledger17put_contract_data17h6938c7a297250993E (type 1))) + (func $increment (type 2) (param i64) (result i64) + (local i32 i32 i64) + block ;; label = @1 + block ;; label = @2 + local.get 0 + i32.wrap_i64 + i32.const 255 + i32.and + local.tee 1 + i32.const 2 + i32.ge_u + br_if 0 (;@2;) + i32.const 0 + local.set 2 + block ;; label = @3 + i64.const 16228901097784078 + i64.const 16228901097784334 + local.get 1 + select + local.tee 0 + i64.const 2 + call $_ZN17soroban_env_guest5guest6ledger17has_contract_data17h79546e647e9b20a7E + i64.const 1 + i64.ne + br_if 0 (;@3;) + local.get 0 + i64.const 2 + call $_ZN17soroban_env_guest5guest6ledger17get_contract_data17h472f93112d86127fE + local.tee 3 + i64.const 255 + i64.and + i64.const 4 + i64.ne + br_if 1 (;@2;) + local.get 3 + i64.const 32 + i64.shr_u + i32.wrap_i64 + local.set 2 + end + local.get 2 + i32.const 1 + i32.add + local.tee 2 + i32.eqz + br_if 1 (;@1;) + local.get 0 + local.get 2 + i64.extend_i32_u + i64.const 32 + i64.shl + i64.const 4 + i64.or + local.tee 3 + i64.const 2 + call $_ZN17soroban_env_guest5guest6ledger17put_contract_data17h6938c7a297250993E + drop + local.get 3 + return + end + unreachable + unreachable + end + call $_ZN4core9panicking5panic17hb157b525de3fe68dE + unreachable) + (func $_ZN4core9panicking5panic17hb157b525de3fe68dE (type 3) + call $_ZN4core9panicking9panic_fmt17hc7427f902a13f1a9E + unreachable) + (func $_ZN4core9panicking9panic_fmt17hc7427f902a13f1a9E (type 3) + unreachable + unreachable) + (func $_ (type 3)) + (memory (;0;) 16) + (global $__stack_pointer (mut i32) (i32.const 1048576)) + (global (;1;) i32 (i32.const 1048576)) + (global (;2;) i32 (i32.const 1048576)) + (export "memory" (memory 0)) + (export "increment" (func $increment)) + (export "_" (func $_)) + (export "__data_end" (global 1)) + (export "__heap_base" (global 2))) + +) + +setAccount(Account(b"test-account"), 9876543210) + +deployContract( + Account(b"test-account"), + Contract(b"test-sc"), + b"test-wasm", + .List +) + +;; assert_eq!(client.increment(&true), 1); +;; assert_eq!(client.increment(&true), 2); +;; assert_eq!(client.increment(&false), 1); +;; assert_eq!(client.increment(&true), 3); +;; assert_eq!(client.increment(&false), 2); + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "increment", + ListItem(SCBool(true)), + U32(1) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "increment", + ListItem(SCBool(true)), + U32(2) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "increment", + ListItem(SCBool(false)), + U32(1) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "increment", + ListItem(SCBool(true)), + U32(3) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "increment", + ListItem(SCBool(false)), + U32(2) +) + +setExitCode(0) \ No newline at end of file diff --git a/src/tests/integration/data/soroban/contracts/test_storage/Cargo.toml b/src/tests/integration/data/soroban/contracts/test_storage/Cargo.toml new file mode 100644 index 0000000..bfce849 --- /dev/null +++ b/src/tests/integration/data/soroban/contracts/test_storage/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "test_storage" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/src/tests/integration/data/soroban/contracts/test_storage/README.md b/src/tests/integration/data/soroban/contracts/test_storage/README.md new file mode 100644 index 0000000..e6fe26b --- /dev/null +++ b/src/tests/integration/data/soroban/contracts/test_storage/README.md @@ -0,0 +1,18 @@ +A quick example of a contract that can be ran with `ksoroban test` + +You will need to have the stellar cli utils installed: +https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup + +And the soroban semantics kompiled: +``` +kdist build soroban-semantics.llvm +``` + +And then (from this directory): + +```sh +soroban contract build --out-dir output +ksoroban test output/test_storage.wasm +``` + +`ksoroban test` should exit successfully diff --git a/src/tests/integration/data/soroban/contracts/test_storage/src/lib.rs b/src/tests/integration/data/soroban/contracts/test_storage/src/lib.rs new file mode 100644 index 0000000..ec1ce00 --- /dev/null +++ b/src/tests/integration/data/soroban/contracts/test_storage/src/lib.rs @@ -0,0 +1,33 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env, Symbol, symbol_short}; + +#[contract] +pub struct StorageContract; + +const INST_KEY: Symbol = symbol_short!("INST"); +const TEMP_KEY: Symbol = symbol_short!("TEMP"); +const PRST_KEY: Symbol = symbol_short!("PRST"); + +#[contractimpl] +impl StorageContract { + pub fn test_u32(env: Env, num1: u32, num2: u32, num3: u32) -> bool { + env.storage().instance().set(&INST_KEY, &num1); + env.storage().temporary().set(&TEMP_KEY, &num2); + env.storage().persistent().set(&PRST_KEY, &num3); + + let snum1: u32 = env.storage().instance().get(&INST_KEY).unwrap(); + let snum2: u32 = env.storage().temporary().get(&TEMP_KEY).unwrap(); + let snum3: u32 = env.storage().persistent().get(&PRST_KEY).unwrap(); + + num1 == snum1 && num2 == snum2 && num3 == snum3 + } + + pub fn test_u32_overwrite(env: Env, num1: u32, num2: u32) -> bool { + env.storage().instance().set(&INST_KEY, &num1); + env.storage().instance().set(&INST_KEY, &num2); + + let num: u32 = env.storage().instance().get(&INST_KEY).unwrap(); + + num == num2 + } +} diff --git a/src/tests/integration/data/struct_storage.wast b/src/tests/integration/data/struct_storage.wast new file mode 100644 index 0000000..9836281 --- /dev/null +++ b/src/tests/integration/data/struct_storage.wast @@ -0,0 +1,451 @@ + +setExitCode(1) + +uploadWasm( b"test-wasm", +;; A contract that stores a struct containing a u64 and a vector of Points. +;; It has three endpoints: one for setting the storage, one for retrieving the vector of Points, +;; and one for retrieving the u64. + +;; #![no_std] +;; use soroban_sdk::{contract, contractimpl, contracttype, log, symbol_short, Env, Symbol, Vec}; + +;; #[contracttype] +;; #[derive(Debug, Clone)] +;; pub struct Point(u64, u64); + +;; #[contracttype] +;; #[derive(Debug)] +;; pub struct State { +;; x: u128, +;; points: Vec +;; } + +;; const STATE: Symbol = symbol_short!("STATE"); + +;; #[contract] +;; pub struct IncrementContract; + +;; #[contractimpl] +;; impl IncrementContract { +;; pub fn set(env: Env, s: State) { +;; env.storage().instance().set(&STATE, &s); +;; } +;; pub fn get_x(env: Env) -> u128 { +;; let s: State = env.storage().instance().get(&STATE).unwrap(); +;; s.x +;; } +;; pub fn get_points(env: Env) -> Vec { +;; let s: State = env.storage().instance().get(&STATE).unwrap(); +;; s.points +;; } +;; } + +(module $soroban_increment_contract.wasm + (type (;0;) (func (param i64 i64) (result i64))) + (type (;1;) (func (param i64 i64 i64 i64) (result i64))) + (type (;2;) (func (param i64) (result i64))) + (type (;3;) (func (param i64 i64 i64) (result i64))) + (type (;4;) (func (param i32))) + (type (;5;) (func (param i32 i64))) + (type (;6;) (func (result i64))) + (type (;7;) (func)) + (import "i" "3" (func $_ZN17soroban_env_guest5guest3int20obj_from_u128_pieces17h5d7cf2ad07a3899bE (type 0))) + (import "l" "0" (func $_ZN17soroban_env_guest5guest6ledger17has_contract_data17h79546e647e9b20a7E (type 0))) + (import "l" "1" (func $_ZN17soroban_env_guest5guest6ledger17get_contract_data17h472f93112d86127fE (type 0))) + (import "m" "a" (func $_ZN17soroban_env_guest5guest3map27map_unpack_to_linear_memory17hb44f5a6c36f14cf3E (type 1))) + (import "i" "5" (func $_ZN17soroban_env_guest5guest3int16obj_to_u128_hi6417h645b49e080dcfdf6E (type 2))) + (import "i" "4" (func $_ZN17soroban_env_guest5guest3int16obj_to_u128_lo6417h0c596faaeffbf363E (type 2))) + (import "m" "9" (func $_ZN17soroban_env_guest5guest3map26map_new_from_linear_memory17h905b0cda6fdc76f0E (type 3))) + (import "l" "_" (func $_ZN17soroban_env_guest5guest6ledger17put_contract_data17h6938c7a297250993E (type 3))) + (func $_ZN104_$LT$soroban_env_common..val..Val$u20$as$u20$soroban_env_common..convert..TryFromVal$LT$E$C$u128$GT$$GT$12try_from_val17h5c3a8408ff9f5a37E (type 0) (param i64 i64) (result i64) + block ;; label = @1 + local.get 0 + i64.const 72057594037927935 + i64.gt_u + local.get 1 + i64.const 0 + i64.ne + local.get 1 + i64.eqz + select + br_if 0 (;@1;) + local.get 0 + i64.const 8 + i64.shl + i64.const 10 + i64.or + return + end + local.get 1 + local.get 0 + call $_ZN17soroban_env_guest5guest3int20obj_from_u128_pieces17h5d7cf2ad07a3899bE) + (func $_ZN11soroban_sdk7storage8Instance3get17hd62867e0a50c0338E (type 4) (param i32) + (local i32 i64 i64) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 1 + global.set $__stack_pointer + i64.const 0 + local.set 2 + block ;; label = @1 + block ;; label = @2 + i64.const 130942488590 + i64.const 2 + call $_ZN17soroban_env_guest5guest6ledger17has_contract_data17h79546e647e9b20a7E + i64.const 1 + i64.ne + br_if 0 (;@2;) + local.get 1 + i64.const 130942488590 + i64.const 2 + call $_ZN17soroban_env_guest5guest6ledger17get_contract_data17h472f93112d86127fE + call $_ZN153_$LT$soroban_increment_contract..State$u20$as$u20$soroban_env_common..convert..TryFromVal$LT$soroban_sdk..env..Env$C$soroban_env_common..val..Val$GT$$GT$12try_from_val17h8d7857b7998f70f4E + local.get 1 + i64.load + i64.eqz + i32.eqz + br_if 1 (;@1;) + local.get 1 + i64.load offset=24 + local.set 2 + local.get 1 + i64.load offset=8 + local.set 3 + local.get 0 + i32.const 16 + i32.add + local.get 1 + i32.const 16 + i32.add + i64.load + i64.store + local.get 0 + local.get 3 + i64.store offset=8 + local.get 0 + local.get 2 + i64.store offset=24 + i64.const 1 + local.set 2 + end + local.get 0 + local.get 2 + i64.store + local.get 1 + i32.const 32 + i32.add + global.set $__stack_pointer + return + end + unreachable + unreachable) + (func $_ZN153_$LT$soroban_increment_contract..State$u20$as$u20$soroban_env_common..convert..TryFromVal$LT$soroban_sdk..env..Env$C$soroban_env_common..val..Val$GT$$GT$12try_from_val17h8d7857b7998f70f4E (type 5) (param i32 i64) + (local i32 i32 i64 i64) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 2 + global.set $__stack_pointer + i32.const 0 + local.set 3 + block ;; label = @1 + loop ;; label = @2 + local.get 3 + i32.const 16 + i32.eq + br_if 1 (;@1;) + local.get 2 + local.get 3 + i32.add + i64.const 2 + i64.store + local.get 3 + i32.const 8 + i32.add + local.set 3 + br 0 (;@2;) + end + end + block ;; label = @1 + block ;; label = @2 + local.get 1 + i64.const 255 + i64.and + i64.const 76 + i64.ne + br_if 0 (;@2;) + local.get 1 + i32.const 1048584 + i64.extend_i32_u + i64.const 32 + i64.shl + i64.const 4 + i64.or + local.get 2 + i64.extend_i32_u + i64.const 32 + i64.shl + i64.const 4 + i64.or + i64.const 8589934596 + call $_ZN17soroban_env_guest5guest3map27map_unpack_to_linear_memory17hb44f5a6c36f14cf3E + drop + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + local.get 2 + i64.load + local.tee 1 + i64.const 255 + i64.and + i64.const 75 + i64.ne + br_if 0 (;@6;) + local.get 2 + i64.load offset=8 + local.tee 4 + i32.wrap_i64 + i32.const 255 + i32.and + local.tee 3 + i32.const 68 + i32.eq + br_if 1 (;@5;) + local.get 3 + i32.const 10 + i32.ne + br_if 3 (;@3;) + local.get 4 + i64.const 8 + i64.shr_u + local.set 4 + i64.const 0 + local.set 5 + br 2 (;@4;) + end + local.get 0 + i64.const 1 + i64.store + br 4 (;@1;) + end + local.get 4 + call $_ZN17soroban_env_guest5guest3int16obj_to_u128_hi6417h645b49e080dcfdf6E + local.set 5 + local.get 4 + call $_ZN17soroban_env_guest5guest3int16obj_to_u128_lo6417h0c596faaeffbf363E + local.set 4 + end + local.get 0 + local.get 4 + i64.store offset=8 + local.get 0 + local.get 1 + i64.store offset=24 + local.get 0 + i64.const 0 + i64.store + local.get 0 + i32.const 16 + i32.add + local.get 5 + i64.store + br 2 (;@1;) + end + local.get 0 + i64.const 1 + i64.store + br 1 (;@1;) + end + local.get 0 + i64.const 1 + i64.store + end + local.get 2 + i32.const 16 + i32.add + global.set $__stack_pointer) + (func $set (type 2) (param i64) (result i64) + (local i32) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 1 + local.get 0 + call $_ZN153_$LT$soroban_increment_contract..State$u20$as$u20$soroban_env_common..convert..TryFromVal$LT$soroban_sdk..env..Env$C$soroban_env_common..val..Val$GT$$GT$12try_from_val17h8d7857b7998f70f4E + block ;; label = @1 + local.get 1 + i64.load + i64.eqz + br_if 0 (;@1;) + unreachable + unreachable + end + local.get 1 + i64.load offset=24 + local.set 0 + local.get 1 + local.get 1 + i64.load offset=8 + local.get 1 + i32.const 16 + i32.add + i64.load + call $_ZN104_$LT$soroban_env_common..val..Val$u20$as$u20$soroban_env_common..convert..TryFromVal$LT$E$C$u128$GT$$GT$12try_from_val17h5c3a8408ff9f5a37E + i64.store offset=8 + local.get 1 + local.get 0 + i64.store + i64.const 130942488590 + i32.const 1048584 + i64.extend_i32_u + i64.const 32 + i64.shl + i64.const 4 + i64.or + local.get 1 + i64.extend_i32_u + i64.const 32 + i64.shl + i64.const 4 + i64.or + i64.const 8589934596 + call $_ZN17soroban_env_guest5guest3map26map_new_from_linear_memory17h905b0cda6fdc76f0E + i64.const 2 + call $_ZN17soroban_env_guest5guest6ledger17put_contract_data17h6938c7a297250993E + drop + local.get 1 + i32.const 32 + i32.add + global.set $__stack_pointer + i64.const 2) + (func $get_x (type 6) (result i64) + (local i32 i64) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 0 + global.set $__stack_pointer + local.get 0 + call $_ZN11soroban_sdk7storage8Instance3get17hd62867e0a50c0338E + block ;; label = @1 + local.get 0 + i64.load + i64.const 0 + i64.ne + br_if 0 (;@1;) + call $_ZN4core6option13unwrap_failed17hb5bacfb0dd292085E + unreachable + end + local.get 0 + i64.load offset=8 + local.get 0 + i32.const 16 + i32.add + i64.load + call $_ZN104_$LT$soroban_env_common..val..Val$u20$as$u20$soroban_env_common..convert..TryFromVal$LT$E$C$u128$GT$$GT$12try_from_val17h5c3a8408ff9f5a37E + local.set 1 + local.get 0 + i32.const 32 + i32.add + global.set $__stack_pointer + local.get 1) + (func $_ZN4core6option13unwrap_failed17hb5bacfb0dd292085E (type 7) + call $_ZN4core9panicking5panic17hb157b525de3fe68dE + unreachable) + (func $get_points (type 6) (result i64) + (local i32 i64) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 0 + global.set $__stack_pointer + local.get 0 + call $_ZN11soroban_sdk7storage8Instance3get17hd62867e0a50c0338E + block ;; label = @1 + local.get 0 + i64.load + i64.const 0 + i64.ne + br_if 0 (;@1;) + call $_ZN4core6option13unwrap_failed17hb5bacfb0dd292085E + unreachable + end + local.get 0 + i64.load offset=24 + local.set 1 + local.get 0 + i32.const 32 + i32.add + global.set $__stack_pointer + local.get 1) + (func $_ZN4core9panicking9panic_fmt17hc7427f902a13f1a9E (type 7) + unreachable + unreachable) + (func $_ZN4core9panicking5panic17hb157b525de3fe68dE (type 7) + call $_ZN4core9panicking9panic_fmt17hc7427f902a13f1a9E + unreachable) + (func $_ (type 7)) + (memory (;0;) 17) + (global $__stack_pointer (mut i32) (i32.const 1048576)) + (global (;1;) i32 (i32.const 1048600)) + (global (;2;) i32 (i32.const 1048608)) + (export "memory" (memory 0)) + (export "set" (func $set)) + (export "get_x" (func $get_x)) + (export "get_points" (func $get_points)) + (export "_" (func $_)) + (export "__data_end" (global 1)) + (export "__heap_base" (global 2)) + (data $.rodata (i32.const 1048576) "pointsx\00\00\00\10\00\06\00\00\00\06\00\10\00\01\00\00\00")) + +) + +setAccount(Account(b"test-account"), 9876543210) + +deployContract( + Account(b"test-account"), + Contract(b"test-ctr"), + b"test-wasm", + .List +) + +callTx( + Account(b"test-caller"), + Contract(b"test-ctr"), + "set", + ListItem( + ScMap( + Symbol(str("x")) |-> U128(1329227995784915872903807060280344576) + Symbol(str("points")) |-> ScVec( + ListItem(ScVec(ListItem(U64(1)) ListItem(U64(2)))) + ListItem(ScVec(ListItem(U64(10)) ListItem(U64(20)))) + ) + ) + ), + Void +) + +callTx( + Account(b"test-caller"), + Contract(b"test-ctr"), + "get_x", + .List, + U128(1329227995784915872903807060280344576) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-ctr"), + "get_points", + .List, + ScVec( + ListItem(ScVec(ListItem(U64(1)) ListItem(U64(2)))) + ListItem(ScVec(ListItem(U64(10)) ListItem(U64(20)))) + ) +) + +setExitCode(0) \ No newline at end of file