From 78737e4fa9ca22f90faec917951e712b62187361 Mon Sep 17 00:00:00 2001 From: Song Zhou Date: Sat, 15 Jan 2022 05:34:53 +0000 Subject: [PATCH] impl all externals funcs --- enclave/app/Cargo.lock | 1074 ++++++++++++++++- enclave/app/Cargo.toml | 1 + enclave/app/src/main.rs | 5 + enclave/crates/skw-ipfs/src/lib.rs | 2 +- .../src/near-test-contracts/Cargo.toml | 13 + .../src/near-test-contracts/README.md | 21 + mock-enclave/src/near-test-contracts/build.rs | 79 ++ .../contract-for-fuzzing-rs/Cargo.lock | 7 + .../contract-for-fuzzing-rs/Cargo.toml | 25 + .../contract-for-fuzzing-rs/src/lib.rs | 304 +++++ .../src/near-test-contracts/res/.gitignore | 3 + .../res/ZombieOwnership.bin | 1 + .../src/near-test-contracts/res/near_evm.wasm | Bin 0 -> 214744 bytes .../res/test_contract_ts.wasm | Bin 0 -> 13229 bytes .../src/near-test-contracts/src/lib.rs | 85 ++ .../test-contract-rs/Cargo.lock | 97 ++ .../test-contract-rs/Cargo.toml | 35 + .../test-contract-rs/src/lib.rs | 804 ++++++++++++ .../test-contract-ts/.gitignore | 1 + .../test-contract-ts/README.md | 31 + .../test-contract-ts/assembly/index.ts | 57 + .../test-contract-ts/assembly/tsconfig.json | 6 + .../test-contract-ts/package-lock.json | 3 + .../test-contract-ts/package.json | 7 + mock-enclave/src/skw-vm-engine-cli/Cargo.lock | 2 +- mock-enclave/src/skw-vm-engine/Cargo.lock | 3 +- mock-enclave/src/skw-vm-engine/Cargo.toml | 2 +- mock-enclave/src/skw-vm-engine/src/cache.rs | 25 +- .../src/skw-vm-engine/src/externals.rs | 365 +++++- mock-enclave/src/skw-vm-host/Cargo.toml | 1 - mock-enclave/src/skw-vm-primitives/Cargo.toml | 1 + .../src/skw-vm-primitives/src/errors.rs | 2 + 32 files changed, 3013 insertions(+), 49 deletions(-) create mode 100644 mock-enclave/src/near-test-contracts/Cargo.toml create mode 100644 mock-enclave/src/near-test-contracts/README.md create mode 100644 mock-enclave/src/near-test-contracts/build.rs create mode 100644 mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.lock create mode 100644 mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.toml create mode 100644 mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/src/lib.rs create mode 100644 mock-enclave/src/near-test-contracts/res/.gitignore create mode 100644 mock-enclave/src/near-test-contracts/res/ZombieOwnership.bin create mode 100644 mock-enclave/src/near-test-contracts/res/near_evm.wasm create mode 100644 mock-enclave/src/near-test-contracts/res/test_contract_ts.wasm create mode 100644 mock-enclave/src/near-test-contracts/src/lib.rs create mode 100644 mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.lock create mode 100644 mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.toml create mode 100644 mock-enclave/src/near-test-contracts/test-contract-rs/src/lib.rs create mode 100644 mock-enclave/src/near-test-contracts/test-contract-ts/.gitignore create mode 100644 mock-enclave/src/near-test-contracts/test-contract-ts/README.md create mode 100644 mock-enclave/src/near-test-contracts/test-contract-ts/assembly/index.ts create mode 100644 mock-enclave/src/near-test-contracts/test-contract-ts/assembly/tsconfig.json create mode 100644 mock-enclave/src/near-test-contracts/test-contract-ts/package-lock.json create mode 100644 mock-enclave/src/near-test-contracts/test-contract-ts/package.json diff --git a/enclave/app/Cargo.lock b/enclave/app/Cargo.lock index 6f6aaca..0dc6c79 100644 --- a/enclave/app/Cargo.lock +++ b/enclave/app/Cargo.lock @@ -2,28 +2,1098 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "app" version = "1.0.0" dependencies = [ - "sgx_types", + "sgx_types 1.1.4", "sgx_urts", + "skw_ipfs", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fastrand" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" + +[[package]] +name = "futures-io" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" + +[[package]] +name = "futures-sink" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" + +[[package]] +name = "futures-task" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" + +[[package]] +name = "futures-util" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown_tstd" +version = "0.11.2" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.1", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 0.4.8", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", ] +[[package]] +name = "ipnet" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "openssl" +version = "0.10.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "security-framework" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" +dependencies = [ + "itoa 1.0.1", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa 0.4.8", + "ryu", + "serde", +] + +[[package]] +name = "sgx_alloc" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" + +[[package]] +name = "sgx_backtrace_sys" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" +dependencies = [ + "cc", + "sgx_build_helper", + "sgx_libc", +] + +[[package]] +name = "sgx_build_helper" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" + +[[package]] +name = "sgx_demangle" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" + +[[package]] +name = "sgx_libc" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" +dependencies = [ + "sgx_types 1.1.4 (git+https://github.com/apache/teaclave-sgx-sdk.git)", +] + +[[package]] +name = "sgx_tprotected_fs" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" +dependencies = [ + "sgx_trts", + "sgx_types 1.1.4 (git+https://github.com/apache/teaclave-sgx-sdk.git)", +] + +[[package]] +name = "sgx_trts" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" +dependencies = [ + "sgx_libc", + "sgx_types 1.1.4 (git+https://github.com/apache/teaclave-sgx-sdk.git)", +] + +[[package]] +name = "sgx_tstd" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" +dependencies = [ + "hashbrown_tstd", + "sgx_alloc", + "sgx_backtrace_sys", + "sgx_demangle", + "sgx_libc", + "sgx_tprotected_fs", + "sgx_trts", + "sgx_types 1.1.4 (git+https://github.com/apache/teaclave-sgx-sdk.git)", + "sgx_unwind", +] + +[[package]] +name = "sgx_types" +version = "1.1.4" + [[package]] name = "sgx_types" version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" + +[[package]] +name = "sgx_unwind" +version = "1.1.4" +source = "git+https://github.com/apache/teaclave-sgx-sdk.git#565960cd7b4b36d1188459d75652619971c43f7e" +dependencies = [ + "sgx_build_helper", +] [[package]] name = "sgx_urts" version = "1.1.4" dependencies = [ "libc", - "sgx_types", + "sgx_types 1.1.4", +] + +[[package]] +name = "skw_ipfs" +version = "0.1.0" +dependencies = [ + "hashbrown", + "reqwest", + "serde", + "serde_json", + "skw_types", +] + +[[package]] +name = "skw_types" +version = "0.1.0" +dependencies = [ + "sgx_tstd", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "socket2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "winapi", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi", ] diff --git a/enclave/app/Cargo.toml b/enclave/app/Cargo.toml index fc1423d..de9308d 100644 --- a/enclave/app/Cargo.toml +++ b/enclave/app/Cargo.toml @@ -5,5 +5,6 @@ authors = ["SkyeKiwi "] build = "build.rs" [dependencies] +skw_ipfs = { path = "../crates/skw-ipfs" } sgx_types = { path = "../../teaclave-sgx-sdk/sgx_types" } sgx_urts = { path = "../../teaclave-sgx-sdk/sgx_urts" } diff --git a/enclave/app/src/main.rs b/enclave/app/src/main.rs index 429a92b..8057a73 100644 --- a/enclave/app/src/main.rs +++ b/enclave/app/src/main.rs @@ -39,6 +39,11 @@ fn main() { }, }; + const CONTENT: &str = "some random string ..."; + let result = skw_ipfs::IpfsClient::add(CONTENT.as_bytes().to_vec()).unwrap(); + let recovered = skw_ipfs::IpfsClient::cat(result.cid).unwrap(); + println!("{:?}", String::from_utf8(recovered)); + let input_string = String::from("This is a normal world string passed into Enclave!\n"); let mut retval = sgx_status_t::SGX_SUCCESS; diff --git a/enclave/crates/skw-ipfs/src/lib.rs b/enclave/crates/skw-ipfs/src/lib.rs index 5556046..12b0533 100644 --- a/enclave/crates/skw-ipfs/src/lib.rs +++ b/enclave/crates/skw-ipfs/src/lib.rs @@ -108,7 +108,7 @@ impl IpfsClient { #[test] fn ipfs_works() { - const CONTENT: &'static str = "some random string ..."; + const CONTENT: &str = "some random string ..."; let result = IpfsClient::add(CONTENT.as_bytes().to_vec()).unwrap(); let recovered = IpfsClient::cat(result.cid).unwrap(); diff --git a/mock-enclave/src/near-test-contracts/Cargo.toml b/mock-enclave/src/near-test-contracts/Cargo.toml new file mode 100644 index 0000000..f5b09d1 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "near-test-contracts" +version = "0.0.0" +publish = false +authors = ["Near Inc "] +# Please update rust-toolchain.toml as well when changing version here: +rust-version = "1.56.0" +edition = "2021" +license = "Apache-2.0" + +[dependencies] +once_cell = "1" +wat = "1.0.40" diff --git a/mock-enclave/src/near-test-contracts/README.md b/mock-enclave/src/near-test-contracts/README.md new file mode 100644 index 0000000..502cfa4 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/README.md @@ -0,0 +1,21 @@ +A collection of smart-contract used in nearcore tests. + +Rust contracts are built via `build.rs`, the Assembly Script contract +is build manually and committed to the git repository. +`res/near_evm.wasm` and `res/ZombieOwnership.bin` are taken from + +and it's for reproduce a performance issue encountered in EVM +contracts. + +If you want to use a contract from rust core, add + +```toml +[dev-dependencies] +near-test-contracts = { path = "../near-test-contracts" } +``` + +to the Cargo.toml and use `near_test_contract::rs_contract()`. + +If you want to use a contract from an integration test, you can read +the wasm file directly from the `./res` directory. To populate +`./res`, you need to make sure that this crate was compiled. diff --git a/mock-enclave/src/near-test-contracts/build.rs b/mock-enclave/src/near-test-contracts/build.rs new file mode 100644 index 0000000..43c43bc --- /dev/null +++ b/mock-enclave/src/near-test-contracts/build.rs @@ -0,0 +1,79 @@ +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; +use std::{env, fs, io, process}; + +fn main() { + if let Err(err) = try_main() { + eprintln!("{}", err); + process::exit(1); + } +} + +fn try_main() -> io::Result<()> { + build_contract("./test-contract-rs", &[], "test_contract_rs")?; + build_contract( + "./test-contract-rs", + &["--features", "nightly_protocol_features"], + "nightly_test_contract_rs", + )?; + build_contract("./contract-for-fuzzing-rs", &[], "contract_for_fuzzing_rs")?; + build_contract( + "./test-contract-rs", + &["--features", "base_protocol"], + "test_contract_rs_base_protocol", + )?; + Ok(()) +} + +fn build_contract(dir: &str, args: &[&str], output: &str) -> io::Result<()> { + let mut cmd = cargo_build_cmd(); + cmd.args(args); + cmd.current_dir(dir); + check_status(cmd)?; + + let target_dir = shared_target_dir().unwrap_or_else(|| format!("./{}/target", dir).into()); + fs::copy( + target_dir.join(format!("wasm32-unknown-unknown/release/{}.wasm", dir.replace('-', "_"))), + format!("./res/{}.wasm", output), + )?; + println!("cargo:rerun-if-changed=./{}/src/lib.rs", dir); + println!("cargo:rerun-if-changed=./{}/Cargo.toml", dir); + Ok(()) +} + +fn cargo_build_cmd() -> Command { + let mut res = Command::new("cargo"); + res.env("RUSTFLAGS", "-C link-arg=-s"); + res.env_remove("CARGO_ENCODED_RUSTFLAGS"); + if let Some(target_dir) = shared_target_dir() { + res.env("CARGO_TARGET_DIR", target_dir); + } + + res.args(&["build", "--target=wasm32-unknown-unknown", "--release"]); + res +} + +fn check_status(mut cmd: Command) -> io::Result<()> { + let status = cmd.status().map_err(|err| { + io::Error::new(io::ErrorKind::Other, format!("command `{:?}` failed to run: {}", cmd, err)) + })?; + if !status.success() { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("command `{:?}` exited with non-zero status: {:?}", cmd, status), + )); + } + Ok(()) +} + +fn shared_target_dir() -> Option { + let target_dir = env::var("CARGO_TARGET_DIR").ok()?; + // Avoid sharing the same target directory with the patent Cargo + // invocation, to avoid deadlock on the target dir. + // + // That is, this logic is needed for the case like the following: + // + // CARGO_TARGET_DIR=/tmp cargo build -p near-test-contracts --release + Some(Path::new(&target_dir).join("near-test-contracts")) +} diff --git a/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.lock b/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.lock new file mode 100644 index 0000000..e2d40b9 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "contract-for-fuzzing-rs" +version = "0.1.0" diff --git a/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.toml b/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.toml new file mode 100644 index 0000000..015e490 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "contract-for-fuzzing-rs" +version = "0.1.0" +authors = ["Near Inc "] +publish = false +# Please update rust-toolchain.toml as well when changing version here: +rust-version = "1.56.0" +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +# Tell `rustc` to optimize for small code size. +opt-level = "z" +lto = true +debug = false +panic = "abort" +rpath = false +debug-assertions = false +incremental = false + +[workspace] +members = [] diff --git a/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/src/lib.rs b/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/src/lib.rs new file mode 100644 index 0000000..c091c51 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/contract-for-fuzzing-rs/src/lib.rs @@ -0,0 +1,304 @@ +use std::mem::size_of; + +#[allow(unused)] +extern "C" { + // ############# + // # Registers # + // ############# + fn read_register(register_id: u64, ptr: u64); + fn register_len(register_id: u64) -> u64; + // ############### + // # Context API # + // ############### + fn current_account_id(register_id: u64); + fn signer_account_id(register_id: u64); + fn signer_account_pk(register_id: u64); + fn predecessor_account_id(register_id: u64); + fn input(register_id: u64); + // TODO #1903 fn block_height() -> u64; + fn block_index() -> u64; + fn block_timestamp() -> u64; + fn epoch_height() -> u64; + fn storage_usage() -> u64; + // ################# + // # Economics API # + // ################# + fn account_balance(balance_ptr: u64); + fn attached_deposit(balance_ptr: u64); + fn prepaid_gas() -> u64; + fn used_gas() -> u64; + // ############ + // # Math API # + // ############ + fn random_seed(register_id: u64); + fn sha256(value_len: u64, value_ptr: u64, register_id: u64); + // ##################### + // # Miscellaneous API # + // ##################### + fn value_return(value_len: u64, value_ptr: u64); + fn panic(); + fn panic_utf8(len: u64, ptr: u64); + fn log_utf8(len: u64, ptr: u64); + fn log_utf16(len: u64, ptr: u64); + fn abort(msg_ptr: u32, filename_ptr: u32, line: u32, col: u32); + // ################ + // # Promises API # + // ################ + fn promise_create( + account_id_len: u64, + account_id_ptr: u64, + method_name_len: u64, + method_name_ptr: u64, + arguments_len: u64, + arguments_ptr: u64, + amount_ptr: u64, + gas: u64, + ) -> u64; + fn promise_then( + promise_index: u64, + account_id_len: u64, + account_id_ptr: u64, + method_name_len: u64, + method_name_ptr: u64, + arguments_len: u64, + arguments_ptr: u64, + amount_ptr: u64, + gas: u64, + ) -> u64; + fn promise_and(promise_idx_ptr: u64, promise_idx_count: u64) -> u64; + fn promise_batch_create(account_id_len: u64, account_id_ptr: u64) -> u64; + fn promise_batch_then(promise_index: u64, account_id_len: u64, account_id_ptr: u64) -> u64; + // ####################### + // # Promise API actions # + // ####################### + fn promise_batch_action_create_account(promise_index: u64); + fn promise_batch_action_deploy_contract(promise_index: u64, code_len: u64, code_ptr: u64); + fn promise_batch_action_function_call( + promise_index: u64, + method_name_len: u64, + method_name_ptr: u64, + arguments_len: u64, + arguments_ptr: u64, + amount_ptr: u64, + gas: u64, + ); + fn promise_batch_action_transfer(promise_index: u64, amount_ptr: u64); + fn promise_batch_action_stake( + promise_index: u64, + amount_ptr: u64, + public_key_len: u64, + public_key_ptr: u64, + ); + fn promise_batch_action_add_key_with_full_access( + promise_index: u64, + public_key_len: u64, + public_key_ptr: u64, + nonce: u64, + ); + fn promise_batch_action_add_key_with_function_call( + promise_index: u64, + public_key_len: u64, + public_key_ptr: u64, + nonce: u64, + allowance_ptr: u64, + receiver_id_len: u64, + receiver_id_ptr: u64, + method_names_len: u64, + method_names_ptr: u64, + ); + fn promise_batch_action_delete_key( + promise_index: u64, + public_key_len: u64, + public_key_ptr: u64, + ); + fn promise_batch_action_delete_account( + promise_index: u64, + beneficiary_id_len: u64, + beneficiary_id_ptr: u64, + ); + // ####################### + // # Promise API results # + // ####################### + fn promise_results_count() -> u64; + fn promise_result(result_idx: u64, register_id: u64) -> u64; + fn promise_return(promise_id: u64); + // ############### + // # Storage API # + // ############### + fn storage_write( + key_len: u64, + key_ptr: u64, + value_len: u64, + value_ptr: u64, + register_id: u64, + ) -> u64; + fn storage_read(key_len: u64, key_ptr: u64, register_id: u64) -> u64; + fn storage_remove(key_len: u64, key_ptr: u64, register_id: u64) -> u64; + fn storage_has_key(key_len: u64, key_ptr: u64) -> u64; + fn storage_iter_prefix(prefix_len: u64, prefix_ptr: u64) -> u64; + fn storage_iter_range(start_len: u64, start_ptr: u64, end_len: u64, end_ptr: u64) -> u64; + fn storage_iter_next(iterator_id: u64, key_register_id: u64, value_register_id: u64) -> u64; + // ############### + // # Validator API # + // ############### + fn validator_stake(account_id_len: u64, account_id_ptr: u64, stake_ptr: u64); + fn validator_total_stake(stake_ptr: u64); + // ################# + // # alt_bn128 API # + // ################# + #[cfg(feature = "protocol_feature_alt_bn128")] + fn alt_bn128_g1_multiexp(value_len: u64, value_ptr: u64, register_id: u64); + #[cfg(feature = "protocol_feature_alt_bn128")] + fn alt_bn128_g1_sum(value_len: u64, value_ptr: u64, register_id: u64); + #[cfg(feature = "protocol_feature_alt_bn128")] + fn alt_bn128_pairing_check(value_len: u64, value_ptr: u64) -> u64; +} + +#[no_mangle] +pub unsafe fn number_from_input() { + input(0); + let value = [0u8; size_of::()]; + read_register(0, value.as_ptr() as u64); + value_return(value.len() as u64, &value as *const u8 as u64); +} + +#[no_mangle] +pub unsafe fn count_sum() { + input(0); + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + + let number_of_numbers = u64::from_le_bytes(data); + + let mut sum: u64 = 0; + + for i in 0..number_of_numbers { + promise_result(i, 0); + + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + + let number = u64::from_le_bytes(data); + sum += number; + } + + let value = sum.to_le_bytes(); + + value_return(value.len() as u64, &value as *const u8 as u64); +} + +#[no_mangle] +pub unsafe fn sum_of_numbers() { + input(0); + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + + let number_of_numbers = u64::from_le_bytes(data); + let mut promise_ids = vec![]; + + for i in 1..=number_of_numbers { + let i: u64 = 1; + let method_name = "number_from_input".as_bytes(); + let account_id = { + signer_account_id(0); + let result = vec![0; register_len(0) as usize]; + read_register(0, result.as_ptr() as *const u64 as u64); + result + }; + let arguments = i.to_le_bytes(); + + promise_ids.push(promise_create( + account_id.len() as u64, + account_id.as_ptr() as u64, + method_name.len() as u64, + method_name.as_ptr() as u64, + arguments.len() as u64, + arguments.as_ptr() as u64, + 0, + 3_000_000_000, + )); + } + + let promise_idx = promise_and(promise_ids.as_ptr() as u64, promise_ids.len() as u64); + + { + let method_name = "count_sum".as_bytes(); + let account_id = { + signer_account_id(0); + let result = vec![0; register_len(0) as usize]; + read_register(0, result.as_ptr() as *const u64 as u64); + result + }; + let arguments = number_of_numbers.to_le_bytes(); + + promise_then( + promise_idx, + account_id.len() as u64, + account_id.as_ptr() as u64, + method_name.len() as u64, + method_name.as_ptr() as u64, + arguments.len() as u64, + arguments.as_ptr() as u64, + 0, + 3_000_000_000_000, + ); + } +} + +// Function that does not do anything at all. +#[no_mangle] +pub fn noop() {} + +#[no_mangle] +pub unsafe fn data_producer() { + input(0); + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + let size = u64::from_le_bytes(data); + + let data = vec![0u8; size as usize]; + value_return(data.len() as _, data.as_ptr() as _); +} + +#[no_mangle] +pub unsafe fn data_receipt_with_size() { + input(0); + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + let size = u64::from_le_bytes(data); + + let buf = [0u8; 1000]; + current_account_id(0); + let buf_len = register_len(0); + read_register(0, buf.as_ptr() as _); + + let method_name = b"data_producer"; + let args = size.to_le_bytes(); + let mut ids = [0u64; 10]; + let amount = 0u128; + let gas = prepaid_gas(); + let id = promise_create( + buf_len, + buf.as_ptr() as _, + method_name.len() as _, + method_name.as_ptr() as _, + args.len() as _, + args.as_ptr() as _, + &amount as *const u128 as *const u64 as u64, + gas / 20, + ); + + let method_name = b"noop"; + let args = b""; + promise_then( + id, + buf_len, + buf.as_ptr() as _, + method_name.len() as _, + method_name.as_ptr() as _, + args.len() as _, + args.as_ptr() as _, + &amount as *const u128 as *const u64 as u64, + gas / 3, + ); +} diff --git a/mock-enclave/src/near-test-contracts/res/.gitignore b/mock-enclave/src/near-test-contracts/res/.gitignore new file mode 100644 index 0000000..51bb69e --- /dev/null +++ b/mock-enclave/src/near-test-contracts/res/.gitignore @@ -0,0 +1,3 @@ +*.wasm +!test_contract_ts.wasm +!near_evm.wasm diff --git a/mock-enclave/src/near-test-contracts/res/ZombieOwnership.bin b/mock-enclave/src/near-test-contracts/res/ZombieOwnership.bin new file mode 100644 index 0000000..bc8e363 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/res/ZombieOwnership.bin @@ -0,0 +1 @@ +60806040526010600155600154600a0a6002556201518060035566038d7ea4c6800060085560006009556046600a55336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a361232b806100f96000396000f3fe60806040526004361061011f5760003560e01c80636352211e116100a05780638f32d59b116100645780638f32d59b14610736578063c39cbef114610765578063ccf670f8146107f5578063e1fa763814610830578063f2fde38b146108755761011f565b80636352211e1461052057806370a082311461059b578063715018a6146106005780637bff0a01146106175780638da5cb5b146106df5761011f565b80633ccfd60b116100e75780633ccfd60b146103525780634412e10414610369578063528b7b8f1461040f5780635f4623f11461048a5780635faf2880146104db5761011f565b8063095ea7b3146101245780630ce90ec21461017257806317a7f4cc146101a05780632052465e146101e557806323b872dd146102e4575b600080fd5b6101706004803603604081101561013a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506108c6565b005b61019e6004803603602081101561018857600080fd5b81019080803590602001909291905050506109e4565b005b3480156101ac57600080fd5b506101e3600480360360408110156101c357600080fd5b810190808035906020019092919080359060200190929190505050610a79565b005b3480156101f157600080fd5b5061021e6004803603602081101561020857600080fd5b8101908080359060200190929190505050610c04565b60405180806020018781526020018663ffffffff1663ffffffff1681526020018563ffffffff1663ffffffff1681526020018461ffff1661ffff1681526020018361ffff1661ffff168152602001828103825288818151815260200191508051906020019080838360005b838110156102a4578082015181840152602081019050610289565b50505050905090810190601f1680156102d15780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390f35b610350600480360360608110156102fa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610d21565b005b34801561035e57600080fd5b50610367610e05565b005b34801561037557600080fd5b506103b86004803603602081101561038c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610e6c565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156103fb5780820151818401526020810190506103e0565b505050509050019250505060405180910390f35b34801561041b57600080fd5b506104486004803603602081101561043257600080fd5b8101908080359060200190929190505050610f99565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561049657600080fd5b506104d9600480360360208110156104ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fcc565b005b3480156104e757600080fd5b5061051e600480360360408110156104fe57600080fd5b810190808035906020019092919080359060200190929190505050611021565b005b34801561052c57600080fd5b506105596004803603602081101561054357600080fd5b81019080803590602001909291905050506110fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156105a757600080fd5b506105ea600480360360208110156105be57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611138565b6040518082815260200191505060405180910390f35b34801561060c57600080fd5b50610615611181565b005b34801561062357600080fd5b506106dd6004803603602081101561063a57600080fd5b810190808035906020019064010000000081111561065757600080fd5b82018360208201111561066957600080fd5b8035906020019184600183028401116401000000008311171561068b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611251565b005b3480156106eb57600080fd5b506106f46112c7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074257600080fd5b5061074b6112f0565b604051808215151515815260200191505060405180910390f35b34801561077157600080fd5b506107f36004803603604081101561078857600080fd5b8101908080359060200190929190803590602001906401000000008111156107af57600080fd5b8201836020820111156107c157600080fd5b803590602001918460018302840111640100000000831117156107e357600080fd5b9091929391929390505050611347565b005b34801561080157600080fd5b5061082e6004803603602081101561081857600080fd5b810190808035906020019092919050505061142d565b005b34801561083c57600080fd5b506108736004803603604081101561085357600080fd5b810190808035906020019092919080359060200190929190505050611448565b005b34801561088157600080fd5b506108c46004803603602081101561089857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506116d4565b005b806005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461093257600080fd5b82600b600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b60085434146109f257600080fd5b610a3a600160048381548110610a0457fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff166116f190919063ffffffff16565b60048281548110610a4757fe5b906000526020600020906003020160020160006101000a81548163ffffffff021916908363ffffffff16021790555050565b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e98b7f4d836040518263ffffffff1660e01b8152600401808281526020019150506101406040518083038186803b158015610aef57600080fd5b505afa158015610b03573d6000803e3d6000fd5b505050506040513d610140811015610b1a57600080fd5b810190808051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919050505090919293949596979850909192939495969750909192939495965090919293949550909192939450909192935090919250909150905080915050610bff83826040518060400160405280600581526020017f6b69747479000000000000000000000000000000000000000000000000000000815250611719565b505050565b60048181548110610c1157fe5b9060005260206000209060030201600091509050806000018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610cbd5780601f10610c9257610100808354040283529160200191610cbd565b820191906000526020600020905b815481529060010190602001808311610ca057829003601f168201915b5050505050908060010154908060020160009054906101000a900463ffffffff16908060020160049054906101000a900463ffffffff16908060020160089054906101000a900461ffff169080600201600a9054906101000a900461ffff16905086565b3373ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161480610dec57503373ffffffffffffffffffffffffffffffffffffffff16600b600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610df557600080fd5b610e008383836118fb565b505050565b610e0d6112f0565b610e1657600080fd5b6000610e206112c7565b90508073ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610e68573d6000803e3d6000fd5b5050565b606080600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054604051908082528060200260200182016040528015610edd5781602001602082028038833980820191505090505b509050600080905060008090505b600480549050811015610f8e578473ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610f815780838381518110610f6c57fe5b60200260200101818152505081806001019250505b8080600101915050610eeb565b508192505050919050565b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610fd46112f0565b610fdd57600080fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b601482816004828154811061103257fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff16101561106557600080fd5b836005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146110d157600080fd5b83600486815481106110df57fe5b9060005260206000209060030201600101819055505050505050565b60006005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6111896112f0565b61119257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541461129d57600080fd5b60006112a882611ad9565b9050606481816112b457fe5b06810390506112c38282611b67565b5050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b600283816004828154811061135857fe5b906000526020600020906003020160020160009054906101000a900463ffffffff1663ffffffff16101561138b57600080fd5b846005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146113f757600080fd5b84846004888154811061140657fe5b906000526020600020906003020160000191906114249291906121d1565b50505050505050565b6114356112f0565b61143e57600080fd5b8060088190555050565b816005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114b457600080fd5b6000600484815481106114c357fe5b906000526020600020906003020190506000600484815481106114e257fe5b9060005260206000209060030201905060006114fe6064611e39565b9050600a5481116116325761153360018460020160089054906101000a900461ffff1661ffff16611ed290919063ffffffff16565b8360020160086101000a81548161ffff021916908361ffff16021790555061157f60018460020160009054906101000a900463ffffffff1663ffffffff166116f190919063ffffffff16565b8360020160006101000a81548163ffffffff021916908363ffffffff1602179055506115cb600183600201600a9054906101000a900461ffff1661ffff16611ed290919063ffffffff16565b82600201600a6101000a81548161ffff021916908361ffff16021790555061162d8683600101546040518060400160405280600681526020017f7a6f6d6269650000000000000000000000000000000000000000000000000000815250611719565b6116cc565b61165c600184600201600a9054906101000a900461ffff1661ffff16611ed290919063ffffffff16565b83600201600a6101000a81548161ffff021916908361ffff1602179055506116a460018360020160089054906101000a900461ffff1661ffff16611ed290919063ffffffff16565b8260020160086101000a81548161ffff021916908361ffff1602179055506116cb83611ef6565b5b505050505050565b6116dc6112f0565b6116e557600080fd5b6116ee81611f20565b50565b60008082840190508363ffffffff168163ffffffff16101561170f57fe5b8091505092915050565b826005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461178557600080fd5b60006004858154811061179457fe5b906000526020600020906003020190506117ad81612018565b6117b657600080fd5b60025484816117c157fe5b0693506000600285836001015401816117d657fe5b04905060405160200180807f6b69747479000000000000000000000000000000000000000000000000000000815250600501905060405160208183030381529060405280519060200120846040516020018082805190602001908083835b602083106118575780518252602082019150602081019050602083039250611834565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012014156118ab576063606482816118a457fe5b0682030190505b6118ea6040518060400160405280600681526020017f4e6f4e616d65000000000000000000000000000000000000000000000000000081525082611b67565b6118f382611ef6565b505050505050565b61194e6001600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461203f90919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506119e46001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546120c790919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600080826040516020018082805190602001908083835b60208310611b135780518252602082019150602081019050602083039250611af0565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012060001c90506002548181611b5e57fe5b06915050919050565b6000600160046040518060c00160405280868152602001858152602001600163ffffffff168152602001600354420163ffffffff168152602001600061ffff168152602001600061ffff16815250908060018154018082558091505090600182039060005260206000209060030201600090919290919091506000820151816000019080519060200190611bfc929190612251565b506020820151816001015560408201518160020160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160020160046101000a81548163ffffffff021916908363ffffffff16021790555060808201518160020160086101000a81548161ffff021916908361ffff16021790555060a082015181600201600a6101000a81548161ffff021916908361ffff1602179055505050039050336005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611d456001600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461203f90919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f88f026aacbbecc90c18411df4b1185fd8d9be2470f1962f192bf84a27d0704b78184846040518084815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611df8578082015181840152602081019050611ddd565b50505050905090810190601f168015611e255780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1505050565b6000611e51600160095461203f90919063ffffffff16565b600981905550814233600954604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140182815260200193505050506040516020818303038152906040528051906020012060001c81611eca57fe5b069050919050565b60008082840190508361ffff168161ffff161015611eec57fe5b8091505092915050565b60035442018160020160046101000a81548163ffffffff021916908363ffffffff16021790555050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f5a57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000428260020160049054906101000a900463ffffffff1663ffffffff1611159050919050565b6000808284019050838110156120bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600061210983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612111565b905092915050565b60008383111582906121be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612183578082015181840152602081019050612168565b50505050905090810190601f1680156121b05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061221257803560ff1916838001178555612240565b82800160010185558215612240579182015b8281111561223f578235825591602001919060010190612224565b5b50905061224d91906122d1565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061229257805160ff19168380011785556122c0565b828001600101855582156122c0579182015b828111156122bf5782518255916020019190600101906122a4565b5b5090506122cd91906122d1565b5090565b6122f391905b808211156122ef5760008160009055506001016122d7565b5090565b9056fea265627a7a72315820a51ff617e191b9a50c14f4f6ec96f1ccaee214484ad9ef9d78e6b6ecca9e24d264736f6c63430005110032 \ No newline at end of file diff --git a/mock-enclave/src/near-test-contracts/res/near_evm.wasm b/mock-enclave/src/near-test-contracts/res/near_evm.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1907938d03f0ed3d4464750704a0782b71b6ffa7 GIT binary patch literal 214744 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%0Ap$aLTtTWtJ0T=Xk#+16YGSTy_G$xsl435pzZ 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%0APpRCxhgcz*dT$*$zEVJ-6t|;TWI+g4)qjNA%dO zYE!JsImCZX8jVU$@57$a?p%Ea9Pcjd-o&B8@)&XAsHxbUbLX zHq9r6eSMryO%WO@+DWED5_@E~uU{t9dv||7Jhe$K{2()9lEp+Qy|i2srC?R zt_SWB!~EG^K=7n&rIf)I#K5c>{M)kn9%o&(1M8)e((>*sR5y(jWWfW< zCPSa^N0@bdR2L;;49r0X-X(fiVj~B%dC(*zAV|HaSLO%$#7%UA3)K+m zA@a;SHyAv^n0lkwv;*tD8g4mmj+pR24V;O{pR_wC(MN*o?@wsWJ`w_uXnh@aYDnF+ zyZAQ8x3|!rTpsTuz{o)Z#?*TpoEUn{n&l_zW0{UYQIpuuPLU`Zf3zUkbT+zdQhd?> zC#1Rq2aTU!3{xEfrG$3{`8w_o4+ zI`n-=SM!u$|KfMP%0yj$86fla1ev!xGOq(q6!(#Ndqn1ShRo}P%-g4tsRlsibsaK8 zy(wf~=g188P7|4bS;CoBE(+l9x3t%qiP;s=_SR6WAS89Nw$f4tUF4UU~ zjqRY`OubEwQ55T4P|t>Xv!T73dZT))+M_7elk|AMGoigD>J95HYLB8=?}9{v9KK!D z8`KMGkK?mqJ)&iyy>V#o>S7O9CP5U1dOf1QO_CIkN`nN;?fQhae}tS0=CJurQ&Qk8 zt1OX>mZh5~9Q7e|%W}Ybw%!yz?Z|CAkNwxZ#-d(Ryn^;@9!z`Y)zg%$G5wH59^*1R z;k*UFiw&yBefAA!-qZY;P;+<>AF+K;^JTzb@5uP15d4^!?rb3Vzk1^u1|<0bjFq(t zJ+UM@lAnVbnYOU!ET)9}ssF+rSGK`S`%%4(O+GgZT5K1sMqFs%M0fW$SG=(L4Ve&z zy0EW$d$??ydQKM@=~Hrprq;3-R`2iHdfRkcYspz$Nve%JD&KMC$>&TU+>f|_SpAkS zT`@EWxMN@SO6@wUj_R*W4`S@Ap_~D_D4&QkQx`diReQQ<6hFr{>n=N-x3onTYY#_(hNJxri!Z#X@}$M1u|<{lo4iJA zIbcOwuWjA!RgOj&!AHPmWCb>DHm4PPY5^dBX%rnbTfH^l-G+_ppaZCC&{hli#3#VL zZNV(7(6mo}abT_$wLl(UAAmYanc(tzfbjvqeU~)vF?I46;u=2lSY!q!)pqf&RD@FM z?b~jPxlxyxTT0z)66*Tkt-nBC4Wv(B4XUFruwj3(>h1SH(Y{sUcJs* zS2P;eJrnC!?UlLnDzis>(GB-jusW{f4;O3BGG&)jBAeDlCO>U zEtAjY3w}9n#)`}4)o(iXZzApy5q?g*Nc{|O~(ef-u&J_!1w0&@DS&k-_-%$HNVS4 z+-tR0t_&vI^t(2=ZGv51p%53C3Ef;>)!VL}jF`u5!;p;dl8@=(7P+-sG1HXdOV61v zty*(6rPNwgEj~?p8~0nTz4tb%Y}Lm@nDgCByz_q6{Lo(-qyH5CV<9Uig>jF_Sy%U% zq!}s9Lh~kZE){EKvrU<%!{!69v{eiC zcSEKv*UH`5yA{2H5Gycn%d~KcUhGj;W!nNBr#t)Pi)cyeqonNOZz(BqTU!DJzM0;kf@Lxaf{noJwRg;7z`iYhJ- zC)@fJO@ukq#zcBM0>)MC;%eTcd5uhqb;yph@ZyEsc(IPf0qSt~1igEW^nxy`$rJUn zXYwQ};U3x>w@r53HhFRoc%EjHi&bgYTUVV!@)Dho#UFqOr_Gr6~?CiiwXxz}NGZ(nC}Z;vLIm>?#XSf6V3 zOzyZ|xLqdqx_fVz$-OR^+}r=YN)g0Or05@=Pbsp_r=%z*ak|rq<0?PpEF9N0_gu_d z`uL&q;kYt7w&?{Ym6&w6+SGBy7n}C9ac1S-QH;~nMohS+T(;B7+lYym!x`yGn=1D%VRsM-Q}_NQV&;bp^*`^LoqzHAgkPmVtDG6`%oyK z8prUI>_AIM;<0X`FSP?_+xvjby{7E0z98%zdPhW*Ka#_!|Ycrw7KH<}Dg z&F=(DI}1Qk5|wo2`BX{Pc_7QVo=YF!K*GTTfs=C_EttY}7b#$LXJptn)}e@nX=TQ< zUP30UUxqJ2Ov%VZUue=heJRnG8*DP_QUXG%zqHw{O;Al5LqlqL&BQPis6iF<8sfz_qYQQ88Vne zGyi|@9f*%T?m(cFI|l+uNmSC)&ZkPU&L1I_bmY7{5RC3jRMN@@0Lx(8oQBb)?t{wB z!B%-Xr!fPMeN}ni(jUQfSPOA%Z<7vtZCX>Z%~Ne!Q=z=y=8D>s=O+d`^Eu60>k1@u z8oovqJ^B;fI9dD6p{*}-aByvp6TPlmrnZ<}%pL0iZ<-ExzwUZ`wM8>rNhYfC_)kI!nsjfE$vDg8yU_DZKT>#y}RD=_tH zd&^Q_)?W3;9eusuUhS^lLtz0Lko6{W*}LDgx|~)2Rpk#yL3@LM)x^oM0S3;#EEP1e zm?-GW&!>X6&cD(WG=uu`Q_w~UvAFrck1OcbkNkV7pg+}DxsRBFzUOfTt)rUUoV05X z$YP?Pm--5N_FPBiPwKZ>=dKpaT~;2Sedr<0<5Lh^eze8-+XrFxr#!xLLmw_RtBDUs zBJ??4doZuxR)(hX_!ylwYkAHd8@R(2d*C((c)jnhMNH-Akz6qHJig@_&)YjZqdY!~ z;p3EQ5o;}V@cao*X`J%5o}NDedvWgDclp+E`Fzn7smv?i&Q1U150Y$Td4raGL|&m~ z3$Bn?X#3}#$+GxH;tKwvyMk=ov^_vtnG-U6dzz5pS3bc^7bV;7f4Hs^$b`Q%P1jfTyme>X8_3?MeJW8?`{rQ>C0I0HKmQ+qc!*mH$K$ZN(y-@#N<6@_5d^Ah3TTSB|De z5o%79nyD--1`&#Gn{4+)Dp5=Cv6*R`N~pyU;)`SLgsR$_E1_mrax6sNoD^k^&fhpEH;`W!R;IR7wDUX1)tx8v^=h_6jDMl9a7c zMjib>)LQ_jRB>GMN*MLt{7#{-y%$bzAbEzL<($MCrfD69=E+tS(tyHWpKKwmZGmK0 z^3t~YHb~WA)7Dn)$RZzBPiX5F3MdT)z^ZG#=DD{=^2M#T(_&a}CntxwS53n0s(!bT zYNy{ZGda!4f^N)XFirQ8>hxZ+9PahAE{S<+x%`wwL!0!;mIi&a04eE8a%a!ca=9tW zPL0w@7wtxqCMN4^`X=krbFI)%YO<{JKo%)inXFcy8@-^9NGFq}ucW(x=nV)ZMJe6PL4uJ zbSi>!i^QlrF-I$uTQElDePeW-gT+>4rxcp7nFAfBZK~YbRC&^-%02C6U7KsPdE5dj zFj(#8%3>G5K~LiCcWFlNxj9E-$7(SdjLLm5cF_(}7rxqPHt8^5giBX6Dw(Z1u}QMFy^WN{f)mSH%t@<2^Mzg9q#0Gk9+?JmYc_pGCl2 zX@HRs;aaoHSW8%8xb8C8W$y_Mny%tWpMG5+eiQq><~Zl+Z1t;w;g=y<)+`s{d?7aN zEfv!Hr5cNkDkxoF#Nl%>Bk^Pi9qV}nEMC4+<5!x(Rhp*H!hw&B#EjtP~3R(4Wvx2AN z!Me?G<3RB=54hp@NIM}39L(Ce6*R2qRHA0RlICi6d91yZ@3k_DED-TF<$OhtuBSiUf|+O6D@U)IWSHv^pSTo8 z-2sK71xY=!!Bhfcs{+iwn%;tkt9ix=j8G==$o@ebHk))GbZ|jp*-!y z@E^+iu9BO<%FOlSKw!EJDA-iOnD4QcSOU8xa(&tPlxyo;qW2Xk z*NpCQxjwaAKQ7iAnCmm&X#=+DKe%s9NV=X^tv`I(Lq$WspAZsGb`~70M)> zuWkP4jq|PZV9-L)JjRn_V&CPs+~?mED3=|&&R`_ z>0K{Zt=-ni$Q-%pwodtON%(+U%z4|ExrXUozvbb>am?sS!={UKnNW7#LJcra!pDRU z&mSLK=R$1an00YBJ-~5ZA8ONsQ%<;6HlDvcimAVh?o3qqdhv^)?{=mYL*MP>M*_+~ zrvlQN^(5kFQ&vfB+m2COxU~(DsXY4=kZU_5*R{MBL)|M;CW4@P2EoZffvOl^Y6a;` zwk>J~y+Ls9(K~7gdM1MN)V|=%JgTdv*15zWtS@aCsR$-u^HtML&cCunBsJcTRGjk> zZn|p9=(NS$*LphpnumirwKtajB)^^;*H(@Vh=7CaJH3xU6v=`+>=b zkMsx+$R3xbL5PKL$sS0Zz3AVg;j=V4SXV&=3oabeGJE*YPxzLBPRXRHfqwMu5q>uR zI)|$p!NEAiq%qze+=uW)agp8=qk-N*1+|$KiqWsc(Wz3T&7VqhHKZ&7?NQFvKo}CO^Ht|l>saRj|KhQ)EUm-n9@jch z^~ki=ITEzaU5~iddClWmr@tPF(mp?02VqFG&QtnY=bW!uoHRqsI`35mdG+=8pSh zKG1W+RCtk7Yk4tsub)?VWD^hhoR4q{*IiyAqtj<0+(XtmFMg%zRLGF*d&nCAyk?FW z<771H%uwa#A*(!Lbd{TTrt&_UA5oIKNq{vqxr|mvd zsAZ%?N%|pcG5UGOt(o+$=RjLd;@#_V-|jAy1F}@SS+=a;O9z)Ms`)nW&3s}$d@#wM z$!CQuLyTI@jPk==*h7vZcVNWJJQc<>94QRn0W>e1yA879I8M4euwNelo)jTNZl=C0 zIG(fhQ^M7#&6=~tb){#e(|RQ*GWSV|w_?Pb)Zs~jW<3GTi{Z%>nomBhH`S&WQAS-U zvc&N)k$aRUBj}w(!C%r>@Q>w+<>K?HTCDRxmajb3!ss4XEnm^9#kPJtu3Fk1+HicLTAqA9Rf}~#rCQ=j zhnoUazot@}mUf#9^aeISQ;N+~OjBPoIsq~^=iD#b)N5gMXOfDxwvn4<6B@>;`Ca0* ztk~2dl&5x=aIeF{^bFA6lPA?$DLlk@kZ?>N-v^*@tjE%)$ducG%g% z4l(@UHdD1(?k*qdoglYXElU3;Bz{bZ6P+TJr^Ja)k;?nTX^%cz zGuM@I$SE?-weUm(0@UVwPmcDMimdwG;D&q8XW=bH7jpeX?3CWpCcctfPRn}>*bX~J zL?XU`)9xAhYv*#~Q@Mp1=}3GbE+i%S%$^M+e>tj|X7J6X^z%1jSMWwmC({?pEaIlJ zR<+^f(hwiz;zM$}uI>A{PDP2n?H?&Nj=X)qP;$zTNxggMfazFnF8yOt$EH6f_2Kqo zQr3Bzme=Vw?VQ?Fxhc3R<#w5d%j#o4=H_f7>i1WrHyN8F{gh)nZKQu`6hAn`@HWzM zv&3&Ug4<>IQGxp*KYgv^lpfICL<2k%4UN#A(-^u86qJ&-jVr2hpjCuji=Wq)PF4{X zt-snj72vu|^~@ejVo1z&5N#=5sApV0HBPonKhbC%o^iPtpIL-F4Rht3OUBM!Rc)2{ zA4?M#CcoV-d}pPVR)ZOS*YEj4I!>FLdLrz?O7l!NBhpOkGdA{#w?{%408`7;vT&!9 znqXG2)j&bGFpf5rysQm4epMZDS=XCjjveZzm1p<)*Jg!36pio*ic)M!3$DNrOT~MN z>V#v~al1BZ2EDI?xt25CNDIGg3UhfzdjBfJcByaZxu!%rp7w{rJ{$!?3Rl}WHc*vr zYg$!#*~Y5!;i!|7h^2Kd-C&W1^+E|U*5`0ict(p_CO|QmfI5P$(z{;N+}x$37B#QC z4dX{c(EM#$2Wg_PoToTZfdtiecS>x!p&GX4pZGS2xn1g1=fo8|c*dN~%{~~&(zO2FEk^fsJBRWJr^;D@qyz&V< z9qeNgbn=6W=BdxwBHa(i)hLa@m09-mEF;H4yY34MyC;(}B%x^P=0R&CeyrM2pzgf0 z7IYVx$DP2XObT)n&2~|Lp1X;o^aweD*7;Yi6Ugws{G33eNfaFiST-hbB2i& zQpfHD294CYfT5ss07HS>_9^$z+S$l}_Gpv^;AH@}q}`4^x!iYA=I6W!Q3zMuyWxe6OE ze{KwmIop}J?Pmp&buPwYGARwRfx40&*+5;1_M5rLNQ+pFW@8+|oD}OO(N0wBcrox& z>Q%`TBR9BZ>?AA1qC%QmDj%GV_&cRyP8J)|93}Z;xGTo94i7~FMz_y&ilaa#ir8gw{`Zq#C7etq7&IhSIri*F^EMzrg$oPZhOG9?rnG6zjz@oP;5IxB&XrbgRE zzpXulKg!O!b$;&SJ&zTQ$MDW5-m^~Qt!Eq5-RZK8A(#3|V)^~;If>0`cX_P6RD|Ec z<{fv2bK_@W+S6sZ`SFG%{^_ZYY7yv4XNQ`O>hsUEbUT;wLSwJt&W z)a&x?a+$5}#hHMHyy?39$=3DK!3Mp1w(i%)^XUZ>(J8zEZVzv|#}`QRJ@HkYfxtIM z_BIb>(QtY(XlFY}b9}0pR%R)_zbn=e^Lvs771vwuO{Z?|;8lJC*{DrQXH_BC>e+re zgr>pm0?npqUu(YszJ8%*9oo-+m1bkKbC7H@Gn*gV3T9lvFq?Wm(^xHIcnArAr(3@lNkjgSOt5|B?=_nZ?oKw70nlI;o=Q(ek=K3Dpu|3eMNP=L-6T{ zOiKE79@Lp04cDg@s14LIuZhz|owMSUSr+Z&$t%$SJz) zRb`+ek)GMUmyz?mkPYeb2(2qw_p&r`#eC{BHjyq<;f_d`?ko(aOJb4&qfN?<$MbM9 z08SpqaEv;uDP}yyX3CzLVli!VIaloE#xgKt^+Sq)igm?aEjjfANF|b5(X8Mxz2*k@yG9|Lk9knr-K9yel zFyay$Y(A0#e*{K&a!F#4XB3xMH@mQaprx;+aS2Oa3k9Z;Ep;t&sJWi~mCIlw+UQ2Y z#cn&|yJ3wh)bGbS+Qb**VkN7&5U4WTd|p;8BMS#fjhJdRmYXwVHKMFlTyEO@iH)<< zUu^I-^C;9ZR<#|?qlvusVw!&94vA09qr770X}xM1w8gB-%@|B!T;--WRK6bL=5DR| z)GSWos{6xY#{)iB>Al#TXbThV^!c{1V*+CoBFD$|(G6#b)%IJg8F}CTEFZ{n%L!`F zy+3IJ@58Z4C(#wwx#RUKS648|$907ZoJ&Er@dCtITlL7okL!wVu70j`g>(d}g6$-O z1&+2frP1F3P~vQ8JH3A)ZF%HhIb0hq&a3>P;bL$`Vif)I@|b-Yv9{+cquVEZI!$2* zw#sk4o$s%0tLLwq6!%ij=KJCjzN@B(9LvC0@u)q|6qzU2y@aRZ>xc?blW)3N%~jRp z>xz8!aCAFmTduqJcB;)^N6MeRXLCCrZ8KHgs@=E~#MNX6uGNu$HE}tN zYh|Rb67pG{fq&(ZG1=D@9~#&J5(H&YzHIKV=lH6h)AM~5kR|BsFYJJ0R&c~;k z^Yu1;jjrH3gZ??5Eqsngwe(>9c;lZ_GT(>bU88xh77>Mo15$1z- zElv?TTNeoMru6oiN6Q|Adw#WAu$P$0a%o!iFaKwU5+%!w3^9mGGNWAwrVwO|k$*SOPk)dn5?%j8? z`#IgWHmPXpebsMj;2ISCQX|EziZr_-KJLsreAN3VrQ@S17YD^24S1FylYSR;hKrJ> zy?Y<3@}|A}cn_AW`*087eg!V8H_8!gwk`6V2a=?vgiF8+bot0AA4IyWm?#-)TKg2US0GrQ3zfJYzuUacYnDK&dL@|UJuf%(?Rp&`_DrNA&ZFB^zl?&c_ z!B)srlT9mu=J@tjXv^P`@G1jFtAa(Tdb1 ztXaQshZU}Ng;cr6?~X`FmS|sZSMLwa6H1T$s#ibWHdV(&D+5LKvjmn)#ow*1G*{Cg zJ6)0$S7x=Z3W@=Y337_I7FiC<65Iir&oH2+KGz!r>8?b->O+kzYIsYS+i;dJx8bW}ZVjzK;HN~wilPQ}sj#BHU~r6-2}X^y>2W*> zj>}dY(QE$9W}ND5HH%nzu!(Vlvt&J;wY-V^ zc|AGf`ew3rMJ$L_6e+~fL@yCL6VFx&N~T*|Rs+M)miPBz%W8XW$pJwLWKsfUhS+OC z7R{(7ku3#AD6ifo84^Yznj*fjf4nn8X{lxFPaC)N zFs7L|x$2J}nkfbc2X_Q_LuPH@Qp(C0>xvL*V%yubXGr((O3;gb50}iiGBD-ohK;3k zRc`wNVcQh-0Lp>s@Mxo5n7j;>CMLtn;O4|)U}#Lj(CFm$0a`Fbo9~W_UrT=$%X`*h z04(me(iu5>^M5JSG{Y7`Gw1TAn>uzez(}~9uyv|eXks$pSpbHPE-z=X7~U0Pv{-Ts zb2si-FBmgTXUvAQBaVyS*3uGRV9i5QF%xlM_A(uh3t*&JphuvW--T8CNF-X6&2=(` zFTZy%N@KPsIy+oJ*G$$yEA83t1!nJu~}h#JP+$5m^ssdMRCo-EGqirNkk@pfBq$*@nD9Vujy0$cNFLUBe2`1i7E#@xK-mkz`V(J}MsfUFQMlNZqrEaofhqM_ras6b|m5HEvi6Up>4 z#&$^35m0J31i}P0gE2QEGn3IfcVdU} zrelT)V;&XKgjR8E1htU}t)OW!kp_7LjZ6Vi;_$E$kSHkawACSdTd{(Ftb<;*r~}604t)&q2(;Z8TyJsfe5oX-A8ZE zTmPeK%>WLhqD$1Ig@2GBtA1Q@2dHIyg7B4l?bc$`dO#qC_s>iVyNI=xrQW?TQ!JqZ z;Y*#l3F9g}AYfbkc5bzA_I3l>c9ya%Zea>g%jQlie7|)yrI4^B&RZx0A6F6VzsU3H z$i{#@?V|y$bV^@*w3pEMnc#{JxYC75P;oI^eZ%tP&Rovnv)Xd_!I!q}$5*rqi$ z(5tZla6QA={1e)w)3B_~U|~j{r}|sqBhCxM=Dh-cVMH%e^+4@w!1aul0D>DW|D)19 zUP8lE(N{jg%|Eca*{j&6 zdY_Qz6X;ov%8HRW0WbK>ni!eK`xu$qJ)>}6pYUG^0mb?Z5f>J~Mt_*M+Jm4xI1Tvx zQ!QL9F4Ax%mf{G>1}&RHM#Qy^8R>{6$Tue+OTI%%I_j2YG$w{QErwyp;svERv}6zC z$yn65TT;70@aJdg{|Idipaie&)ZqAsp{nzLJx9ekL|FnKz@ZW#%h8u5+Fx{++W&XQG z@j=`v9 zey*`x%3D6s|XN{k`G(6t4ecxc(Zh z|HFuMU@`yit!Vz=*-ukb@?5`M;PSiua?Is(>~hqc%JmiDdK1@|dzG`e{7%2z&gEr( z`8Y1W!!N&<%V*o=s5y=6OTGB(xcqj%Tr_lN^WWCq77N+@x3;$>x6f*C2i#uL-cE7* zZ`#{wZlBrS&TxBidpqRz8SU*Xw@+_x=eWJ7y&ZA;wDxwM+o!g->$u(3-md4iX>T`h zyVTxR+&-nf-N@~?w6~{l`_1j`soXxfz1_s^liJ(UxP4-Kdpft@)ZU)K?S<{_W^Q-3 zw_CWqpuOG7?fLEPHg3;rZ_niR3GMA;xc%4d?bmSojqUAYx!uv;*4%!B-<}=l`>)zt z(f8c;R`fl`Z=r3&3-gcnTWD*yU+=fj)^5-CTWD*yi+(!{w_oSC(AJ)Qt=~dhyM3JB zLR-7t?zhm^ZqM>tXlu7)zlFATyWqFb)^2ORg|>G4SijA={d$J*HGa!j?e;N#%UJF9 zOuyB5Re77=YP`DL>bDxNZnyZY#;e=Seme}eXZWqgtEZ<+cVzRMq*b!{Q>9R}d9@M0 zZX7k@(`tly*S3^Ke7RolXQmvv6!_>#e)IWt(t!SCUTVWHM^cD>$)b3vz}ZnFoi`jc z(swhX=J7Ou@@4HtBegd*YNQ?qqefb{95v^J=f$Xz?#)MnTyNkPT3|Z74&zx}cWs?t zJGvvsg$r4iqeNf1yLRR;SHG<35H48;u4GzDYugHNm89&qE&f(XN|NWg3#sp=8g~gd zhd(PRXQqNqLegu5B{2ASWNWE@G=&9(iOIhfpi=?RDO@!w5*WT}ub^dB@o-_9;mSYe zW_~=xo&Gs@-xWhFs@$>zHSR7z>G@0bTn<%9oFzY;?M~*JPuDZ@k*iOc3p>}44zqgo zTr+&WVe`9oD{YQPN@t7A*Wy}h2Nmb&^zo(s%IB{v=B|vskSCfwZz9U23O6|u4DY;(|H*gS80P{ zJIuPw$Sev^`=*MeI`^_RaZq?DSvUZN$N%uqg)xS%EfHM6=|U!BR$HFeoESb3 z)rwE7xPt-8SD;JofqeWWyzve9u!CB+3k;2gmh$- ziM)9z3+JaPY`tESyh02)lg|hns4K1Nnc_cvX%8|!l~w47Df95i<|8Mp>ucuV-}uA$exYV%NkEE-@ zcCNDVlt3nd(b2_IrhPdG4uGetcL!6IJt@C|_EB?aJ7o;ACuJ~2qcg#j8R4xjd|`&| zHK<_@mm@d!e9O>~_&~EeR+J24^HKE?;YQFnJi|Eu2SoEsj-*bd{M0F`O`R$)fjJi7 z6V-r!bxmW-MZ>J zb4sO8>?PD<(R?I}$C^Te7IE73)W-AJ86#0F+-KrE#qEvQ3l zE!m>2szqx&MqkL=bsJ>nf>1bJjkZjKW$OoI3YgrD#gKC##W60|4>av7Dp3ZHu9(D> zWB_rnnEaB!gh!vaRl-y(P}vST5mc;MG27_cD4^LU?j$UJFV*BM%D{n!LFb;v6BLy- zO9kPAA6xjstETh4hmHYo{u2gLnr>EaDRVY@V5U_Nhl{Qg_1^O$l21-;;-EEa^$z9MGG~ zoOs!H6TGbNCU_Zb%^Js<8D$t@PHUOuZgY@^B+RrwAMBgdKm1?0)}lAte{ZmQl@$p9CTdO`>AzUW7Q)i zLq!p#Twzz-y}3}3d?KAup&HK6)Udv;XT@Vcm^W4Zxq+J}PtmF^7dBkw?q6PX!Qjia zd}t{*@h)XMKxG%ogFFV2J}F^j*9ac~c6Cd0P|7=Q^6Hp%Z8B>!XK;y0b5cEe_duAJ z;PNn+o2gRou1DUfbOa+?vlg^pyVcJ7fC3S#_lu9YhWgd7>RKd#(W?)K2ZxK8ntvW) zU9+PZRIfwo#Nde2IkuFjsQDQPLQS9-mH%i*0BaGbY-=QemQ9kI1oQ<|L2NE4=6%$z z%@jfKjvWI&dd*Zm8~qNcmFev?v#hCtea2d*jEHDlRJ;@h^0k8F*&t)&*X?RwjsRPw z>J3t;EG70kKYxBsc=3V{?Dbw?GfVD|0+VTq!X$4zpGvTSnkX8tOC^i$ufq2(tkZJ6 z<{QSxv~Ki=TR4@OhB|PsQ?&KXW^}Ds4IoT z5L)O}z{@T0D&XZ7b`=1BLY=h%_z65K0D9}spw}xJK>{g^-~o^wF<->d@ZCCGAP4Qf zw0VRhVRx30XS%uH0aEZC#0o_sV^-d;$MnVD&Wkopt|y>@zx(XD8WCQpUAY))*3yD%*FOpS63!^^Lj}mO*gGX{Mu|Wy19reOqK`96EN$2rpBQKtk=8F zXmTx7$#E)hP;12hHubuV7_9Yn)%`4MMtIxW6oW zv~S%)K-F$hW}eh$7FH<6yC1|@z3P>r1=pMYi1z}X3)7aM$zBO)f(^ag`k*N~34Csy zT(Psfo*Hi|G`Z){Y?cG=mpjNpgvyE-SYZLW)#i#-3Ve~#*cSL z3K0z-)^YU{0=l5=+-$jQ?09B>@aNJ$UR5kS*B$XsDtsmtVBYx ztu~QtX-665=KN|C+VxD~&Fe66wjap<&DmAP5A8mY*7=3E`3oaeFOgZXK-7TuQaWx~ zYoCqK!gn8a;sHHDna%T(p7e){DJu6V<`+^&c*3E@VhN~(sv z#1dlQfTXav+OgBDDG^IS)+r!wP`%R}jY0Ju`z;zipt7BDVdwvzC^uTzgHvgqTgqsN zNb@s5oY7RYHD;QgRbMjT+vVY~hF(7q;#l@P)<|8z`h!7pKODsJ19^}K2$PWtLS7xS zs8SYZ=%b+x`eH8Btxz51Qo%o(nzmE*iJmt`|94=iKl2J_nsd^SsDj2fc&tY%kWnRC zG?R&2!OiKr&(1L%9OS4w;$QCaxBK084}1>+Cc#|>WAnAl8R9kexEWl#Fdc@@V>`DT z0Xc_Z(S$G#1soWKYt3SmjwuHOoK{DivdzJ%Kv7bfMuX5rdIxv-g5m&h`Qx@RL$KGb z-f3*E(1L7!X*As0ZpYpo2qw(Y9I*F_OT?6v?Xl^2p4wn#2&M(C$s~?)WUrA zJE?_mq^5W0$7@pKUe;Nt=8DdZ$~gWcF4EKLl*rb$z)+r-`?;vgxa5r;Pr*Tk0>m2k zqo=iGPuF+LL-%W#VP}3@C_e-bXuaBwIHH#JgJz$HMWf^?c@a8%oh?6-4j-6n1Uxgi zLLRtShx?^9#R_z;VDiDx`E5j={}4LAMnMHFfO7+(Wjqs%d6Gy9HXPMZXI<>T_y{aV zAJ2N(#}Fa4)vi7uR4YyxGz#u|FMG7N`el@ni7bDCs0D`m2O}otq=a${Z3lRRlC%f) zTCyN3;EIoMJo8e$x?5cyynqPghQ zh%9Cu(8Ol3&zaS4hK^LjxU0z*jGequXf@w$7K;@yhlO+e{fzXafJCo(XLb?avT~D` z1C%GX!RxzpP@e3lA>#nO++E@;SP$NIbwK@~1PAA42S{I;Hc;c$2PNV>uyE55SRK)* zMm01Qt}eQkmDENVAEGimt^W6gUqWl`{gONQ1zw%3CRkmGV|KHz{wWBv#5>DT$TxR!U-pyw$V9C3&l-(KB8RMC#_P zNMk8)wZxA{fsVj7Z*>h%mQg7(KB^J(R%F>>D*PHxT`|jNdguOR?WRnOrkW2S{hO*! zm=%a;B~uq0*eO2ZDuGVyv*gnH(OGNs3@s_ElVpQW<56myn7B|mCb8cU<(Q6ngP1G< zMsxj1%lptJ$1GU|)IPunub<{j^WI7)7j=+^5(L7B3TV0a{icJo3;#b99GGZP~P?>|40QbQY2|I1os6ns6dk;5oIG0U@X@RI>vezXsBf)f*#Lt zDHu0Jmq@jWJE?VdVQSRW#ju~&Qg-T~W+CRfP0Jz*7H`p^IYD;HR={KL@W9UoTOKTP zd5p`DokGB57*cj>jane8mz_$jf^`X~85SGu+Sw`CIc2Ao%jnL2WLQoUi?=He{>A2^ zS*sv44sgV$nm>_vgHt|{gD_eyCxd*=ADP&j6ri@P2rYBJc)`ATm;IjJUNJEvO5*x{ z81*k@khmr?QFE+JSe(dJGtCurerQOM5N9>G*mowgy)2rJ5aC%p0p-Rc#(lo?;;>{u z0?t}xay*Q%dUb#Y*m&k}0-JZ}wX4s!b(G(-K?!(^YvwFbtFejs{2BdABWa@qV->5f zC%5mR%8{P>=qU>F&n5Vu zPVT3T5#csKx}fychsEyF7<3z_(p-IXlG`i!&Mc}AjT>&vL@H4zej`X^SmPD=XYDRb zm#onkpn`;?SislXY44*c?ftsWs*sg-^P)7ZXV(t!<|~7$%;A^VL(l~(qyT<#4E-tG;?lrth~$`d0fBDT6s(=@q#-akRZ*hfe zU6+>QK~RcaYO=d5;JHIjniHF}^;G~clXcM}1~S^jVR-Yc(!)OVqS~vBk>Bx`+55u* zL`GS?Ue{awz3|5Nm`$)j_@ioHXe11MA6+dLFUe0Z_}A$T4IL}7onE+kXVI>pI*P1J zc{xHSgd20AI;R7Eywtc0rIe1E7lQBymw4+>usl{9{=sH(XSM7Ob9Dvk*(zt>#bfC{ zRBC5gk(U`qBnQyTjN%=o>I;ipM>-AU%SK-WlStyRJR<98W)VQp`u3Mzxjq7895$ku z;A`!jluy)rN?68wX|j;TBt2prL<2_?4u7??eDVk@Zo>W(TvMhJ2*d1%a-3>Bc}A9# zwFv06A_k_dKY`f>N+Q=gOXcC>N>}t@OEskalNwiF3)t9VYRKl0KiPto!ZpLXLwpp1MJh;w9QFTJ&;<51&U@-2Efc0yLx5iDY%pe~N{miA%XpTAo$7_%uOh%?BSyuOXau`&U$|mc ztx(EG?(@a41_xyrcb>Bm{4PsHLRM7>-cBF^l4>g?gTdF!3p4iWLXZ05r?tqh@>TRV zG1QYj3n0)og?$j(hasz{dLtGT2#X~_^2m6gJU;Qm=#%dTF+>x`iIs{b*mc*Nqx(9G z{Z={#IV!jXoC0A>X3+#Bp~t3EG@&RJZf3|hA|V4?o}OS?`p!$VKUzN0twj@^HPP`H zh`Ki0Y*tIzxE+Do6kw{uNIqG#T3fC~YZ=g(;e;SttrE_~P(SfZjM9ao)ZCbBOE_jM z-VMOn6BMi_`4hxeNaLFAPiP6&jcFo1=1)8jE@9N>z=Tm|4MX!}N5d6!g|W-DAe=U& zPOLq6r{yGg2|u=Wby7A@vhE^3LUk@w66 zEUnF@Bt$jAYq>2Q5UrqTW@DAET^=jjW~UeMR17#NEpSsN}}wnD7J{s#POTtZH$@I6pa~M*?gmw@GSzBm@tANn|&TnTcP-9VLam% zq|M>~VU!--!vnM3d&Frj-0SCJ+NDX}!khJ0xaB3zp-i{D!{n#;M^`oPJb=#En<+vC zdAQsvul_!Ga1@nhVUoy6bD6k3Yay>kzMY(*&8KA->zLwm^<}bhaod?1cLKE>Bx$=U zO55Yr8{M}I)S*gw)z0iJI09_JQ8@&|zgyR*2;+`?Bn#`BS|KMkCFry}x*=yrr@=Ox znoE7Dm94~Tc06w(FP6%sVyVvYEgTQVu6z#M)0kcsm9)EA(pI_>S$HBP0}-n?g=o*X z1g9x!HxmI>g=7J7mi@A#B#aujTr0~2A^ciJl?z_Qm__xF454jNkkCZUXJ>v*O>`Aw zO^9aw#8|V$(p!cgAnKu_jm@-^qgDO}eXIWs@^~~-fVyV|NQ=k`1a%!n7LpwVR2@Zz zsO5{crSqF(5L(JeDDFfiC8ju|AfEUnrM2Z(653F$LGAhVjvhIvz z*87C2gH;zJt7?xzI#)ro3EL6i&ZWeiJuT<`M)t%gtWtAb?7yMIrhU`v_7qL+_H;4E z?q+k4dO7JS#y4g(%b-wgwPi?#)801TOpH0j8;K?H8-i3yk7>YW8A=mqYgz!ca*fb@ zX?Ao1XAff;x_0!gldz+#J`JL4rqH+`Z=M`+XomE>e;I}pMVJmf>bo6SlHk3`HHd;P z&mc;9;pRt<{wh(Nj^3?dSS%H!%?-jMFc+44SXA zoK9e>T;9goaPC)FzzmxFP&E-^D}l{h{)~%Y9Ie>w6t7UFTWk)mij&i8gg!#Pkp;|k z1c+1aCPri+&~*aAG({3u0J$&%a$&E>9kF;vuXr&Q-BGwM+WQ#03r&5< zj{!NZgLrH|i!Ck{GT1yL@0~3+Q?8bd8SmTtR{OTC`hym|^>=n0xv>g)!4{(dkZXi~ zL*CdY3=^;_HNn*)>0YUEcX7Ja@8W!` zMLtL1Mn{Xk+0NnwmtFf-8E*9FbtgLRmr?>zZGEF%+pnQ90%52NH?ajqJJG_)Dqtz~ zbI>HmAK_S*&1|1=II04r+mWb18X*nM8$p9c z9Ug#Rmet>(;i*QPRR78j=;4Utqk-3*KFLck5T!49AQHtjt`0lWA%hHWiAr$;b)u3D z^a!f^(HrSR(yhmWt@AUTmJJNBO>2<{t1tnzP_siM50*n1;XavC_e@~hXjx?2cCds% z)E0(JEy&uWCcNBaMdhg}FE;^DdA~^vtyz;1>F3tPf)g}>wz659#T~|Ji%h(2yT{SRc8y>70nXwHI`a?rM+R)k|#U+PF z7=`f2lWJd3wT2%a1O?xZjHKh4#h1QkFD5ZxBmgAqfT?1`KgAs&9bLReaUVnodQ?`& z<%NqQeS)go8dQ0wMU^|is|b3j@rc+<#7@A8zf_PK5re6q4^U)>y90&*oqBY~U+ASp zR??D-8?l1RSyn6wCwH^AQmafNd+>5-7WOEc*H{}W#2VU4WK_B>-!R{cO(ARX%!KH@ zIxSZ+wFjkR@X_w$2 z*ofI=!N;ZA#76KE{#@uWez{2VwQ-*3Bs-(Ni8p<{P3-BN%ORo7v&+ppSz{9B!Zr(H zVKwd*;rX!h+;Tbo+*)-^2_l@CkUM#AC*yq#6s3uF1_O)mb_n2#rWQ-JS#WOA<{{T> zPvzmb>sIKeM$W7}W!mD*R3{yN1UA%ogR1j$@?iTI)_DOfNB=iXpyRX`HX)YtOEW~K zt8(H?aTflgJh$2{bJ{#S^HSddVu|%HZT*j~s`CD$stVMen1}~Y0h_N|*QUjf^_KKe z=Y&oZOZu*fOZq-40o2)WeV<7H7uW5~KA1biMC2Kln(}4wRg#ggeBk5#C4CQIakZ@B zhdM43V>7`tzw{O!ME}B?V;0hu^T-}YTP+Z>J+_Kh>`Vo<5dDtMk}34Ws>OVdV0`98 zWWgOQn%>w>VliKYc*mm$@xxO@nA7x!6D7C~i6o*GB|#tz#UM zDNwWAcPxS3CqrODf$=;dp@L^6o3v;b>EkZ`#L3T-P7Lf%fKv;Y^cI&fVz;KTP}lJ2 zFdS}TYn)C$$>U%m>u_4Q_;)rQDz{P_7C%^HMDE!SxGY?gM8R0KWfhGfO0Uu<*0+xe zi=6P{#Wp006MDSZ%mT%IEbXxUKx|z~URulq$P@I0RUC6fXBfKC$Uh;%v2-)V5=1Po z*_A&VE#CofKlBgngp>G(g~h?<8-+EEVkQyCcm%HMfTd!?CdDmaR@<;iaUYxTT!h!#1K*wY zj>PsT?zE@k<5DLg-P;p4b{Z5KI~<(wtnwgddZQ0y;9h#nZAFmh1N@j6NgAVeyz-ZZ zH2aSr;6KV6h<=ldhbX>S90`O1YjaW4 zTFB&&g}Bsew$dUTBd|&CgaYo9Y}oh^V0u8StBqB@82r!YRXk9z^`rhWW4D*#_*IKX zE&I_Thw(+^tmTCnaRQRw+VN>0!QupV+We0YATpv7H|J0vZKei&ffdlfwb5xcG=l47 z8a(=&TwR5aETYu1g@!fG{Aih~Sd!NG5?0;zRDpqVvWTl-*~<2r`1fH)Up`Fk{}+f! zxMevDnEdL3nc9@!j->p)^aV3t#pRa|mv8BOzu}+Kx(Q3`b<90MhRlvF9Crsm_Sv-O zgz;bS#}B%L*IQkyGIQP*V_+2**K$5!$ZxbO$gG5Z+m&QiV%}kN^@H`YH4vIvRA!N0 zthMUprt{3{NUOv3Su-lO#x*XyNY+)>RyF$O^((v1V!~w9t*t%YI*S)h=ksv^p!g>3 zumx_M14}6=Fx0dS8LP0b)}mby81o4OMX#8_p~WBC{KEpHlwxCQ&K3=+6px#&keK8b z>oC9Sb5gBX$o$;w3O~z8jw3DWh`f!Fy0)!W(9BV~rC&fCOiMx=T4%n)Y3B#k$^Efi;|{jFh+z!k`F7}XfkpCw8;zPv=>F?%y3@WPV260Y zI)uhP6(|p@6aQuz4mJQr(uBatlA~VcBIIjvtRb9my<`oEVLTvg8&a7IqLsmR&O)&v zp>}_Ypguj-X8R8J)|{bdeNkQjs%L7dM@yL_Sv z*e@quc;xN0D#Z$TyNv`?1HS4l4yk>cg+#J7AoS}ERzE4h2x$XCg0wYA`z}I zb7eJ%0OLI`M0>lBiYt6&J>v4 zBck#BkuOW1jKpiSCvJq1j2op}Rl#eH0 z-9hq?PO#o0uU@VZ3A$QG7x1g2?>U+r7vY?ECRlFI8y!qv<9-DXVn=i!{0`$Va&HmVhzTp z&EJ}rkv!>*v}<3Xw>;^i_JGILD?PYWO1(Q%6;GgAv~lCciP zJK5M^ynVQEzh@^>4{A{UZyWLBXE7L;b<5(s#0rwTAFVw=1@JHr?wxb~l}__YfZi!!-Qqy6^pPwzR6H4Ky7gQvE*zK528kWcONcFIR;3<@uW3hUu$W>j_2pJsN-JIs z+TR1L$vcsrz?D2uM34CskZjPrmL=7ww=4s) zJ+d;pt@B>iooF8u@`kq!l40H`c`G|%%*Olan;kBE!H~>0;I>#~p9e+6i zjkr8|KpP@Y0JuY92@@ktgg6pL6oW9mV$(E{GVzJ{Aq`Q=v_D3X(qi|Zi`A|L?%`f~ zhWl2}NGwQBa^SA_1c-V^>9(Y-{7DG6^dzY*e*&QDS5Nv4vnu0&oJ~HRVEOxXHDilG^i=NN=HH8WS+ z3W07+KyH4nz^C`Xh7Q+~Q&Qrp^p#Xc4rbStWx))ED5l8Fws^VE_(X5i`PsHkWcX!q zDCX4$AC`lgC#&!Vy_WX-$Z1|Nb!Se_xWGv18$RMNl?O-1GOarJnsN(h^kJ$Mb#e?E znXc5E{+^29a!v$~pobXfnAjU=Ir$oHwW08Z99`CPPlQYP<*Qb&P_4Vf-JbtY%{Lpf zAM_Z;eV0M=>#5MQY}V#)q(Tn?tnhu-TFF^+cKczgv+S*fh^YC4ROkY0H9wUKUB0bQ z-!=)#sp<*79>@g(U>Z52=!Lf__0U zf5on@FYNW|XUsQ|*>VdO)R>$U74-YXPL?9bx!Ey3Gh0VHt<)y<_jis2N9pk`8Dj|n z$q40;-Qs(hC>F?n>xS0&W6*pq+#M=SX_WpUldz*M=$Ni@*=L`*b%B?+9EWZi0C>{T zcv8TJ^mP{X30CC^M!IzZ+@YDIUX3D!VM^m&}rM$iME(xWJ zAYtft0+;r|7(D_%iolFA^w_R~k;omI(A`3&(*(BaxHB4IwubJu{IgXBM?Qk2yV*PI z>#XLdR*&^?u{&sTLuhmQ!u2G{{`m}ph&oV%0l8=+H4@yt zWs>VC@pBYEM~r}#wb@b3xMIvGNpMGks%taj$`{RyKH}D)YIXT+x2d$B;-lzk`WFSyf^Ea)2TH7JbSA9Ws{ayqsetQ`6c%3D>q_%hvSpg)Zszn6=<3$$``#D668!Jv_Z)` z+L9g#@$dUI^l1nbWi= z%%K#$CsPiIr4`{kdOY1*?mcLFLfa;{X6rbJ>3+^3L5T4vvJmq1q|>gR1cua;e#>mMd=yYN!F}(>;Y}tzM1cK+RxG`Aw?&E` zy)mr)#(E-Vf7w7(r*?|kNrFIZ9rpW7EQ!@2+~gU9U)nccEQ zl`Xb1qIY+wY)2bGsO-rqPL3mFK)H%r0sRr&H%Be=S4e|LxP@NWPpd}Fbs5L=icAaa2<+EN zsvldm9QqSlJ2m3Rs9=~} z+&$j31}=B(9-kH~%TK@5jwrBU;nF5-)|1$THKx}WSz$*Zi42J|1C%VI&~tM1|C36eeeiR{KT4i)@sJG{Ho@a>nin zPkWnzd*5B^YiWnNmLXDQ36;L4*TK;}+{JIzOZEz55vrN6Nz@WoNVNU4j5fx=8nZsi z=uCO~mE^0^Ou{=1HA>%JjHEztCtuhvLjLX*a;a`3zgKPm^$llTlcI5Fcy=5@mM z80Yh_Yy8p?$q(*&pLJe?M`Bc$_+zvyUzqP`DmfnLoK;RmRAH-)qH;iCj+w=c(xKLl$(D;y;E})Lw)pZ^?j^ONO6p8C z)iM7(S}UKfB0g;V>M-qmBofL=A3<+aZiH$@F(i{pq^vx`5sqOZHYRvs9a|kDfdWL! zt46+)skg?`?2U?G z>Ug-FkgOuKWY3z2Nz4I!fT7bwMLp=nU;0jeMZwofp@pUR;pj0}rYt2gbdEP#x+fu1 zrF3@+r5(UM3H`vJwfo949U1gf%wdNNyBvVwa2H*&iYiE0(z$~w==1?{ zCq@>(J+y$eI)Qq8m^9K+XpnKXwlru-yxQdTn3=a!=#+v4Ig1`7IJc>lte=;M<<<%k zCi3$1(9Wq2r5Hf9#vjLL_l&=XN5&uVC|XCnRj*UFG{EgGr6tzFg->XL3&$cBKh2ex z0Y|CFwMQ+U6SB+-_fRC6oInvSjPk{XBth~OK~hMU<2n14p>1k+^?Q~qwzQEnZ4ZmC zCj!<+T?t{ajoBD6KIVz_>`8GE(Dt|}5rUP4VQ{T0ue3|BKCASTl=D|a_)db0m^N%>P^RjWO?LLz)F=GvVh-$T>k%_V+F}mYb zlJ%b~L|k{f27eDW`5a?exuCwr)G~F=u?uW0`0Ku$AI@dqkUen%>^zL5LyZh1J z-H-L|UfR3+@!s9bdUrq3yZfom9o$(R=-dygpKkBijWMWh@7&|l^zQZiRTIy<_h`@F zbM@AF&fWhTG44x8(RaI>5wp#s*LN23i^0pl;94_`T0ClB75;tWc_ygm7g!stV>DR~ zD+$P9m*pXO$Uj#5#Zt{S*&$23`59<-l%*ZjPwA08uyc&$apzcP*4wKIuHp=`SF$zt z*f3c!US|Qm`f7RnwViKe2;e*btSln^9qRy$37lU5D&XRB$O90WjSb~ku2Q>TjtXbb2v^sCqzO+>?Pt^r0k zG=Coy0$K-4=?|YQ)zxE zTEh7C8kec+_g0Tcn^Xf+?Cp$bk}2|Lzd`#jyxAMkn!I_O8zUBCD$otw?^Y0ralXLPe@{j1IjJVb6t7MU$ZiB|rAB#}-evAsuu zh;~u}8;i}lr+iR2p2yn@!_+=E*1|AXP;8Fa^b%`4)EZRxni0#xrZe6MP%!-58t9(u zqe3C=ik$@_Dr^}8MO0btNjIvqqHg(|5K$*vh{_`eMUw1c)WM5K;Y_H+rV& zkszA2ONO1WgC_r0IgNCMn>o0kI1@agx)GZIf3qVxz%aB_&jW_1&pI#C zt>aQJgx$2@@`sRKEHMl>Q zx9d*pR&(LZpxy2?l@Puc;v!+fgq|*gBm{XXAUJZxkOCdvy``98x#w9TB{2Y7@xqE$ zslg64u$sMn$urxUJ8j3Hb0wqS?#nu7oFhf1`NiUCB4Nhrivrc&z!97Iu@y9#_CVU4 zu!U4Jgj5o6>Hg%zrHM^14Q3~;fQxHtIXri|IciIKtfFrW1$ZwVRKKFZU38L=%qK|H zWPhP95QM&}zcit;9;AEAG@a^2Xx(;MTLknd#B!j*K`_H`=L!2EWC;Zy*bBt4URK@Z z>Yj46TACK;8}_L|K%p>%t&ZcI|$v8=rqwoz<5TstGe5SU`D%Hy+I%dZ2+lFZy7b| zyn2=5x^;=-O;P=_VaNth-ES>*cx!_7lq80}kqK=)VFMLr*`fJz_MmKWrxV@4Rga7W zLU_dDo7=IY!q!Tj+N6fq!ZGUrv^(ky9vJPBpiy%B#ZX-e;EFHm4fuo;imJB-KEYd) z$r9JryU{l-pXnYO5joJFhaiGg-+>ub$=pi#KYrTGY9iip>{&_MsmWp$MUTF5H}H=%cm?A!5$rGT>C^l9o&$tPvHcl@?T$0BZ}T3V^c(Q3b%*f~Nw8 zAGhavH;jJ*s^WI|C4hBR1gqQ^g~(rP7a2@9hk`PNS1a4RF7{zFQdk)onI>OD_NJRZ zp3c&?Yd5$0bD z_{>|bOr103#)!~s{^ijDNsQP5%QDy4wt>0u_FgQ-iko8Y#sidUIpf4rsdQJxb$7vt z2Dw01v)0lui%RgVym|G58r_ z^-GQg<0oZGFLp-=dAW}>>%%@6`9Vg^;~*sUy~k#x{+uk z4$>TS(<7cSarXr#hilhX_Il=eyDJ>xNmpGa99(~bc}(Ngz>q(AfyW48Rhlq-EN#qt`Jl~;uJFyq!ULRQi6;DLB|^krU|kZz+`dAB z*@8jBsK1kDL{1Bx*&*prt{o5ACn~)Z^D8Z$KD~%XZ#L>^?ytc>GW2;wDmmZ}?s1d$v%;$B?|6#2jUEu*3qZZQT7t0m% zS8NPNqr$SV|IG0kD7dFZ0d}Hj?rVph2ClL&@Cg9#i^Eo@02B42!OJ>DYfoTeEq>C1 zVDPXK=7W4tZxM=QkCiA`3&Qud5JIF^s+BQhYVLi}%5v5`zWJCvkFx}Yw4T$x&PE?w z*XN3v@MI>0nHXNVabcuh3U!%;W;|i6*iE~__pk)Aeq{ap3woT$6=F0+PCH^#v)nAU zEx^yUc`xy0a~QUYGyET1L=B{&c3%5fgC`ey$P0C0}!~bOjSY%p!S7sfPLy_p)kFq?wQC9i5DVe4|1MRLRLJgLV)BTP7koUA|_ zmS_)_)X-5G2N{f&yM(xn7O|vSz8JzdRV?bYNKUyc+Pe7W76KOYBc%O0ZsCk=BQ`#n zX+EncN4^8zzy-z2p@baIeWD09@*0Zq7O&ziGDRJH!g_{Nm~wf7<+KHd(CKlUz`&aZ zi;_}u@S*O7^1 zI?OI}Oh>QCalK-)?Zq87=T^B)65Ws3Uh6(v*Stxfn1OXKsvEV94dM;p%5#lR38M_n7m7Dd@XL8Y2IbZ=uR5(_~WEV zVN5G=m^u54B}E8B935+uBD9{EH#laS83}^*F0+$dC;K*fMqb=3v$=`0BH`@d=wLt= zvT_L(BP*#DLOj}ycFR@QaIAvHEGiG7)!7=8coa?92KQfyPh@6~(#O2^v8xh))! z%(5+@U;5nc7xmoryYAgPMnRX1!Hw_e)t!mVPVQey*ha#36*q<&N$zuUb&lgyD!QPv zu6p(|IZ5i(-6#AGySmswsmZ(R#o#{K5%@L>lwg)C#=z1&t!X|X-fIlZmihS;b-vps z3_vBOAH+B+rwo!BNB1q*-bsMD)3v#1369{=rtOu>2>)W5Bcx(~JuGpEgM0#LG^r?o)|8BwN@8o1(q6 zy38Eb&^vT)Kl7`X`G15#M0BPbJ*n-xGs&vCGW)Qwb%6X9!D@)F0=wp;w@$Y+v|1+@ zAUD8Jw&V=$vnz!JR=kZq)z2WH-OCe)r!z=mOm}6IFU&}M^uC9QOlOdyOJuX%(CCo# zh6RAC{dQq!VaB7p(EW^e-^P+Er+bNgUSTYj{;~EEY>PEl1L99XchV)J8OcP8-eSSa{uy^Fkwz$cC)DIatcF^&1v~4 zg-#$8f57v7Hc>eQ68o${r-K2v1{PIQ@UPb*zB7le?BKb5PaOw31%lImVl&6JjL>RS zoFr03u$8!Qvz{3}rxm*H6t#LSg4{``p(JqEJX}I!C`#hbeDxulKD38#mwQ6Ju~F-jiGPXf3&k?SSz@aPDC%ce^uZyM2_2$t`_5!9@TJKSu7b} z)bZ2;5g4BA>bHv}1gLZ4#sG|cn0PzLT?XLM`2i<+4R3m6wNYV{A!Js4+7OLK5bs^+mOwNBgJ)Vy1Vcb{-_RDhy5!Twc{(JPAfTdlBF zz**y+0=U-O4VtOzn*3UIy?c>$7}f2@OW2R*K}(*z-|h)o{ROI%+UHefRm!Dei6FT2 z%pAO$Rj)QOx@jUYAZxJ+nlt1BuUc8os$Vn&Dr^>l0RXQW{fa?sc|zrsvYgw;4r%_U zzm~XKo;l1|i__6!WwWrm*=HU6wt>sb9I#GStj0eBk)ffI1{O*kEdP@osld!dkE>@k zX%>-_i2Q^|Wuiu`AemUmZR|jaKR2>2QV1}XqU-HihiT+J^Px~ zqow2Mo{^l5EI1ow!|iDX#=C>QNd2BcTX)sjU3Ga^UEH-Rt6nT>Z5`dvHr%4P5YH5M z@dg!dQ$^32l?_U!qUq)A4(GvLjP(2>s~G08;5YRbT^8WC$pc^8W@J-5mIyI=cH8+% zS6^rxMH*HC_F%7f1iNKpR2dxO!!#Wb@cWJq&-B|wYr+aA<(IjN3YyfSooE_0LVM~y z3X8HBanDba;xa|L!&KOgR%Tj>d7p7b0rjIA?GE8YSjoQvSjqocVC7qm&nuFXU?B^! z&iU2*1Fx*4m~&&`fB1KwbN;S=gHgLkh&m0LOr38!KFUGT>smCT409JlYV<_dZchtj zv707uZe9Ue zExXHg+9-8p8SeJ>hpgwPx1;X`V!&6u%bDV*c;6!e{^LTJ>T4GmM~1~3^MY3 z_UHPx!4{nujF;HxWGfh8-q*o!!1+ZLbg;|^=URZ@R*dHu@DJM!aguI6q8qaoCv4d44Gn)dHXNL7Ygk~Wkok^cP_Pm-Z$HeS z?>c6IU!~Wp4;p$hF?aR*;adKS75s)5a7WGH-Rl7bsv~cRKZEM8+>NmP9rCtR2WpIU z+SHik2~@LZK<>{JBk392hj~_KXP3+Qn2q#WJ5G$ryIdUdM6NoqLVNolX?0I^*lSED zl~)OQPJqxJEiLEXRd{z(_0cdmM&f+HmainxZ+aL+f$fMW&RS21S`?Tn2#9jHsT^^| zGis=s$j_fm)n5l(xrXxhCvl}`Hd@~2ViH&T3|Ck3E<0bn;-MB-!Y1Ez;uB+Qpk<%X zVomdEA52LM5Y8t|sYXNsqDGywi@gkTvDtsy$}&^NJYL-0++#OKP0hSpzA@6| z_&1guT-$so&1V}Y^7OpcXU%jzIz>R3NNUik?e3d*Gkesn{5OH9`h0&a)r)PxDe<@BTR9k*Xa6v;M=$IC@n_KPtG*5_vc6u09k5isg7VWESM7bg(U_vEfq6Xgy&m zs%4vYmKQRNMIrD))_*3kw898+Vn$Pt{wRVqCO!w=>Vu= zgOK7rgtoJUU{w%OD@~JdO-a2wc;)u6sa=Kh;OL_aR+z^Th$jcupB1g0RT8wtR%-`n zsiW$_wB!=HNz1=EO6s}UrBP6gjGs&g3#95;gs+&RkR8p?$}wtR$oIE^%kEbo_sot!Qpyacr{=Z+qP{x2<0v zPa2q=z39rCJHgn5PV+N$jr`T&!au!z$yrs9P@+hLD%P@P>2O^8tz*<6MqC4kS$7lzWW1sdeoIoX+U44cgZf(86+|Ugq`ak#}teKTVc< zcoP^TDRz^Mt__rjs>OA-iLbn_S?0uNa!Yl2$+qUjx?%F~`AbaMHaBDS8Wu7rz$R62 zT{r@&5q8KwXu^a9B@=VY%Qx&Hqz688@3eDvOuFVg}SUoV`Z304@_ z`PG`A02Vd_Yd8zD#ZtLc&t9~S<1`j>-4shg2z!c~e2>th!GO9s8o~n^U0n~Kxvmf| z*T7gaONa&EXn7K~Ya%pP53jCg_KatBw)m{z*3b2(P!2uqhmh;!EzNi0f)^^U>{fCnx-}AIeYC`Ty2eMfO$P?Zlsm~&?n3sf5Np+ z8{`v6JS&?Uzi=m%IZwR817z})2uQ9do- zvrX;f)t`x3HDHw%do;Q(Bn-QjV2TpW88N^ z_}n9z#p3y6rVimA%-iy-S9sa}R(~N_#y<0IC0Z<0{kcjR0Fzdr1o-$t2=s$q5chGE z!Mv&-r$v_quMTUr`K~%2{dUfRJq_Q;sy~txC2O5Uai3-Aiexp5{)>!>m1%_+E)CuHouHS52Rao zrX9Knzk_yud^9?b5r7HJBUXPc%-MkS2Ro9}@TY_6vZA_R58-e`GREq`tJRP13u=Y@xRH9476ufNs`=R?hr7rxR8XG7tf z7ygJ9#@>-0y?%=o&V`yBrKiHr_eM11g`cs)Sd*1ns`-aj7<*?`xC%dLg`?0Wa;?Jm zSYbp6A-W3RX@wC^F%E@q?Y$n5{6;IB@;0egy-(O)fFtl*oSKNkMb0h@Fgc|Eu&S6$ zaPx89V8is_ce@Y%AAbM`<<;ADJ=)@}j3r9WW_k5{_T-22wb;m@-fI9(S07PDxl0Nt z=3&oyK>T5QsPzV@jQzT)?p3|5s^wJ<`T)Jk0cn*~rFxI*E=cR9v1X$R*kqn$rF0ky z+E6Z$07kt;RRBKo>UNU}+3)oKJw45rjpbdU=u(h#tp)>ZXF!Aq-gl}e`-8#PqN zcX^SG>MWXV(0Gg-ooXSjTC4sQ*qWZ|H~Ruf#r6) ztZmg02|%@BFk)!VbpGLLGmg~F&syhC%y+Q)G3-lqzy;MKtzezwQ*e$(g zI0G$N^>TZ|%&~lU+S6DZq9|sgCo*y~uKZZeT7CYhSjb1K+XwvC!U-2ga~etXI*2b( zN2CAUK|e&C+HU9<#`RB#!K+!A7D2ylT`nWa+cc*_tfW-}K#u3eP*2r49Xp1x!2>){ ze#oy|P4_T3TnV%7Rx=HkTJv5RUXk%-O|ps0XKWD2@4}39q+a&^9TLemjLKpt8#k8* zpnb*Al3qs9sTTb^O&QUWlxU1-Z6Z&+m7A7oY1~r2uO(KIjgM-d4A~YldX_4yi>vGM z+kG&mG=5sITL@;d#UU}t10+j5XsM#w7E?TvxBdJY+G}zPIrQ)nopY?!Yr{*nx%kL$ zXBnY>z^+lu)ajJ9K!3HlJMcSX@dK<_T600MUGf5&sGvgu(LtigfO@P({7C@}6R03A zaYxMQ1G!?9iWU6Zf2cpPA6^;kEDAa4OvsEzJdTUfj86rHu%On(Zbm~LH{)1Xt?o`Y zv<8a`1OADaW+Y{Ly0Hu6wuZxKj$6E^6=^h4K)QRtl}QU@J(Ix$pwN=hcwEFT1+8TX zgsjR{XPbbVZ9p4+xi;Kx2OyCXQ=Oz)M)L+=^>aezXgTlopNwAtx5{D7(a{iqYr5KC zIux-yX7+F39*7s};Ev|=W)a^jWfhzfM>6vjF!`~FERCOjp4Fw7ILsDjb+(g*F159sjjA0d(|&$V89^B0t~-0 zT`i#q?0T*b$;90RsQUGQH3KSO7AX;CnYb&K)V7qv32Qgyb@sv+*LE)o5@3FsW3SPG{;d3ogv*{ypi*c=LuKIK;KhJJVK zvA6Ek!{I*FesF^xZPxWeGxpLV*Z)we^um36_wF6tnhVCfnL%|nhXq1YH%APVFzL>~ z3PDgzLQwP|DEbg^n;@WKf`C>61T-oLuxO(*of9k?ffLOCkE^3bM~i&!CR-sj#yY-$ zv-xmz7_BV{jiDmBmuY(CSPl^barPE23S^ zO$&3eg;71H7Up-+Ks~z;346*V+bm40r*7NJM~T+e!)1CO-gKir=Uvh=$7NafmqS-} z*4?BQZmZ|_UZEAtgIzb@K(dPD<_&ZrnpKyv$7WQo^GduiebbGxU8>RUd}ucSrFQ4k z?z~DpvKSv$}3Q}W-ISycipfsB{}?PUQG2;A9=7NvTqH^lv7jPqHs~)L=)d^|X^*e%YY*ra@l#LVG5X!Sm_CWY;R5;Ku3jjc zWqAhE*J(iDl;K{D+pn3ZIA(TP)zg=3yV^%rO8?3q7bgPa3l?-_*TO)7VX6J>WJ?lgY_m;efzEh!PTO4^_TieuR@UIpDygP=vZdhLX~mhSXi zKi2lNt|3D+oUCNRNZIUT`O9YCNti_1OSK)V+mM$sHK}w|>JCpFT(Y4ZmIFE`{*vFgWpBo zFqH2PC_D!UVw1FE|*a>iTb)Wam*#>j+80T-ZGYf1F zFtxQ9Bd=cXb=Y{OW>0d5wqb%51f0#-`_!B`lGeh%j#0Cb_iE5xTKJRJf^PbMjI|S9jv~&s&#jZzS*SBjxhz+A$ic-TPVPP@OJ(kUb zEt!tBmoR;Qpe7bQwMVmjwxA(@+e}@uP3d0sG|v=mj&HL~M#tnxVd{8FyVRXtTuwPZ znNCMqrPG<)Uq=P-b2k-tan#H5itt-tap!IX6$?WRk18CoQ2j!rA#-BjS$QB#=q2kU z`jHyi*(}*L{A=PE8c-zB7D#5HhqvtwelmDs1QtGPVna$UO%B>KjmW@1*txKNEFsUR8%7JPqMqC&6PJ<*u6-&JgKDEeChJ892tndi`_27N0W_ z&rx%#-gGH*s$Ma&+IUM1<7|zLv#s7L#@Pxgx74Tat6>~`i6M3Nj?bvis5dS1!Y1O8 zVX2Tk2D9s)ve4wt76WMe)cM-rjTrEZT{4&hScfaSCxxXm@L`-2jo|oUN(d zZQkxywYxR8YjKvxIo9sBy}UuY^+tj|F1IM~SvVsh$W}+mWnxnog&31F8107Ssu`|u z1&jyqY@b6%(#7K~y4vz@w;{Y|2!b=XU4H}k7(NH;Z=o|5L10&n@1&2Sj^$;sgqNeZ zqMq%Qqhh13jpb5fSBbHC;${YhuFt668PtzUokZ?rH;%UnUy$yy8s@wFT3%MjL!UCt5;Yequnp%AbPTo9 z^ERos3gXQU@tFp3!v3IMHwp2kwIHre3gR335MOp8i0jR@+Z!7`3k~z|Ly*F;M~{Crdb|XQCZY>7R?tYP&R-!~GS5tz{l_Tf8i} z4CcLfSz=0a;+$7HWyqeFb>6)&mPH0NM<*^ICP(oza(@rk5uSm3dmmtB! z#&1Bzw`>-z^O~wNuxVTi4$h4+r3p9R0uk>ab@+*HrGUR@--H_K^`|v^rjWrW{V`F)#Tqdz&cfB? z@rb6cHh(5`IMdwx1FUfv&s!q|xF{HcTQp5QlvC@dMIxv@s?S=*(z-Gx+Jt4f=ky+L3VN%7K2F*uaR(ALcEW9D;=xiWwg>U zE?!0}9UBvK6<1myM9y~J~B)6vtYB})Ti5M zCb?;2cy4+jd<_y!?ed^jLba}b**n!C44AGnYiv|HfdQ;{TGn0LwC;Lsi`?kxHdjb< z)tKe#*Db)r^#IeWAN3+fm0X$CwWd~llDqw ziT8}Vw>w3*LupaUW-Pqnh*Aly5pnd?i~;4lZvIZDEFZ8bgY(1q)0E}Iwvm>xy-z3_ zy)Pe3g~TUqlU&`b+=Xc^1Wj72R4MdQDO#&A7ZEy16kP3~rl^8%r82Y@X=W4>dj-&1 zQ}r-tEj)v$weW!`oTCy{zpS1!twq|Q`7OitVY+K)Vw&vHwuBkV zhsPhzjoMCf`Q&hJ><{NgY0=C3!@1FhbEAfHxee!XDd8I#Y;ieEBqhvnD4e5^;avXZ z9M0c%+WnLmOrYa$s!HD7>gmZ? zmd+8-2g`!zN2=!c#fNE%((YDIQR0WebPv3Us;0189^8uLA-Yo(`vl{mQVv#R(XGnH zK&PGMeYwvP9?{5E$^KevOuE>7;eAZK{JOwFLgG`OZW;6P+4}AQ{BEDi0H6yU9syu( z1xX&8?4ttMxv-t5(L{jkOe|?<>1L!|+kd?I1=B#DG!3a!Dbz4aH@ss!TYbzRWM<4J zdODcVSaB8)X{v<*0)+$Ag~bP|rz?0MS66@FjS+3xq}3eiPKdHEf_N8sb(h!aOuNwv zyUOCU+kWm^`fMem#6-@Nm`sO`qbmb`q~wJQGZD~)>9$hSMh9h6;$nPLy$#&6xqSA^{e!zl7pQ!`B!MKirJnB2 znK1&NGaGj1%$Ofg#W_oq_0n->;7)61`#KOMFrfy7pNTp*uc`y)o;E(M9%;^uacIu$ zbdX~VM+0K`Gk^ofc3yL4r`0oJC~8jCr}&&1)JuFc-dw{KVdm>rW}=v4+PAO;RBo;} z?W^Gma;4MM**iYHKD|C=nHQLlQlMot+1$>VZLT-or1gon)mwaSYqMsSHuLr=L=D|J zv(x{-^3DXluj;zu)SClB~r* zOF#yvAx#LTNgJBgq%=SR3F$NmO_|`%gp{Xb+j zSzDEEwaD3AwQnxTrkkNkPLZ=#s!StiPFyf(Ys8o1bI09tOHU=z$mMi`B^7iGNUj+Lm zgkc$pd)ktQujaqCeSvH^sJNLJR?fm#&d&=aG3b0*2#ivNbu>aJg|8-ITnS$ZW9Awr z(&7SNpijbhHnX%T81wnrE5MkTTP?;GzB&=c1c5bF(&nn1>(e5^Vnnby9sx~)Q5DVQ zy@jthcf5X-%DA2MWV(?&X>3z!@{>7J;7FN*LWPC6Nqf4Y6cszDoC{PFRjMGmZPbNwFVojT0_4pNH&;N_5Amh}00E2?Tt; zCD`Im5>pfk+(mo`QYR*?FE-}raho);GTP}B9o?q*PEPS1PW#di6PD|4HZ#c7$9I_g zbN;IVm^QwnIZ=Im%+oA8pKhqWjGVbqp85i9BEewLkNOxGyKQp`d|6tfoy2$G#3}Ke zyo>MH_xnxGyiDRdIy^B-;ybp-f<740a7*JmvKFW|r;ENZRD5SLClafv=S{{bDin?8 z>T0sJMoD}J))v4dzLS#y0yza<`#*5eCJsf->FQyM%9EambLqt@lOUfe0m83$WVAV! ze`{;H_HLq3VG|tcVu9m%#I@uR;XfysINH;#LFIwH2V0RSdu4lmA#+S}_tME+I+@UN z>2T&##JrqTt6QT~!X`q_^|CUFOD7ADxOBA5)Fo=0rAuquNxGEU*asK~7ZwY`_;_B5 z7U}`2&_3@{EF)m9_RoDqUcBG$$x5bSNAF3~H<%g(Cu!k=xCo@MHpJq3UmP^*=&E zeGpKG`y(p2ki`H=!AFyV3snDntG}4kzsS{p7%;r72Xi>zz9?FNP>vQE2_8tmEK>cA zuKq(5Y@A&1km_G_Go>Bk_ap`9tNz7Se?wBgI3F@j0H$Fwn29`EZN65vT{ zpEvR!&tVQxZcfTw*4erC#jfiXTe%lz&1$M=B6o5{O5ED88tJcvKLrh=cglG!U)ZY9Tf!5RU*+ zEK&#Yh#*=K2l2^iAX*RBLTpMPJ_1DXP94NY1ks8(h>uPK(Ym%4Vljbu7>Ht{I*5k_ z(TX^T4@?8mdbt*2V*>FI5XE105Dy8W6>$*nnFeA`-tGh#tc*9tNqCPVoy2>y>v%5OEPPF7^Dwwkw07Gmqb3hx0?yjKVD zupn9y2l0VvAX?`x(HKtXSm8Y&iudXu9uh<=;vn8L4a7t~7({q)j`7}-D(}rscn|pE zy(;`A;ynk@cu&lf0E72t*T_9SZx-*JRL6T6ve$^07ud5^QJ)H{Jlr-%Am&tg4>01r zIxxosrbebbmw-7rnj=^zi}$LWl0dBR9uUQQbr6pVVvS6BY8r@DPDvnEcn^r;y*h|T z1hGb@JUI=-DyJk6E4&9p@m?LoM+C7(raU?g#44vG5G%X~MDbo7#KVG^6p;n-z%&r6 zoRUDS@E#Dwdvy>G31Z3*K)h!fh^%p)jc$VX=1AK*xi_cEdnYBl2Ym5f6+U)Se1`*Q zyqAH`4H$fWbK6NZyoV1_yf>?k_d-ysVVV~>1J&_f+VAP;s_0z6i1+Hi91E$nMy5QM zfT@*xRZf{K_kbwgtAlt{5Nl)#=k^+6wGgYEl0dBR9uUQQbr6pTVvS6BavF$LPDvnE zcn^r;y*h}G2x5&)d2||xRZdADR(KDH;=MYEhXv7!Byw*Wh*eHWAXaz}h~m9Eh=&9* z*Pg!h0i-mAhlx#s{H?}?cbVDR3o8s1|@FW#G3$9nr+jjZ9$|-zhj&IVFKu z;XNRV_v#=X7R028$-QYHRyiesSm8Y&iudXu9umZqAH;jpK*Ucu>!sx0%!K!VFW#%d zH@W8k8t(=0xdAh|H?xNKOSS`dVrz8+7yaz<_ULC|Ef>Cc|J> z!!zt^p7clB?Nh`aP{ew5P`2{nixrsXW*P~Ud9wDf6gOioCY^3Jh1ri4&I6!0uMXgq z?JcfEivfHp0odXIwg_O-=T(3e#si=juMXgOY(ZcpnhhYQV_G|#9l&M*OuD=ZFy%W! z1Y)~7c%AJ{u0WH)>viCo9JnTdOZvMCE@isN@mw9ah$Wv^plIN1rHqz=8vTj_XI(nS z*QuyIJxUfnq;=4z!DtDSc)rI@*NN46uR&>|u*>1V)aA@t zfQk=N{^v@9?MaWBD_f6JAbYAnCiob*y84P`O7;Hm_y|v`ptTRAEoM>;gu=gLpq-bz z)(J|U^!tzEy>$zoe(8R4`MT{x96Y5j?JVak_uXwQ8kV!Xx~R$d$qD==p+9{Gkt}MO z>TH{Nlao1>XQB&e4FUW0;m+=)XYD&IPnCd5=>cO58 z!wGN@y1Hyp6H$J+K5~niaCgfyo~&)MK)t;G<|nUN)HF3xgd6|W_{qQJ*Y3kJiAB1D zMc~Lmb&5qRO1OxfH2AzXKKS5~36=m{&aFk+kaqEXL}0wqZ)p{XhHuGS?6%6`E0f<6 zOynFF+f7}I3pA+1^Vy7YDe#_GXpwF1R3C0|Tf@ZTUTW^-O36D^dFhW;5gQM1A`GJ> zIZBTV)eyix{6F6`R^ECZEmW+^ZEQ?W&&2SMAGx{eQb%X-C?s>!eH5XSH1#m7bl_rODP_ZofkN+QL@VrfJ5X zeI$^k)77+=F7i=dW%J6~kNVg-SQW9tEMVmUs33T>em1>}(mOqnTGfXJr6&wIeN4g9 zu-~+iZh=HrO!kt4s+BEf?8XG5!u`ABhpd0yQhKf2)rK2HFj<>Zy3LiZ(Tx{Wbz|+W zAoX>DkA*;`EoWDNq>K29y^M{NvM)((ZL?e>If^T43QjZLEU$_r=Wf32j=LXl%~NnM z1XVd3$_}EdTK1#^4x;4I0tyhsO;&y=l$Cz=!J<$Dp#zdlYrBG^Bzbc5CdYB}s)6#_ zHnY94@=CjA=#@V9(H4vCO_f(H3O9hwm;w5r&oT-iU*hZ16cu%8j2d*|^Fdv*Y&ydt z4>5r=)?zKZ@%Gu8teD-N;PVXMcQ8#Uy-&n-|3V?Qs)0eZ&mUs3n=STUa=S=q$99q5 zH&&){_>m%%_6NR<9w^kcaVoRThlWWyh7^t8ypAQYC0m_61WZ3|zS*I}vjU4|F<=k8&$)XflAc=_ZcOn9) zs5xFr5U!6b>m!@lM zXevZ{L3x7nz*m;I+rU{O}?lt^vTkUt%C_NNO1#c-Rzx2Oq(Qc}2W3D5QwT-!r7h&+v%4bc} zj$f`dbeOAy3({!6DxI!b8X#%AJ7}4fi!&s5*Kaiauc|>3SlYoW9t`Srb;c3P=z_>f zcbblUM4@D{0o88PEOv|du_!2vg%4kYyH-l3EkgZpX@xhnZ!>uPn>9=dMWxcG_ll?_ zI@Euz%+hrC=qTMiTH8j`JyfBlTNf|@Z9i&2m43%y00r~EC&vLgL(n5u}%k3f57B5!au{aV*QTrfukgY&30>6 z5q4$vOP?@&g9=|3hwJtw^OItnJz6OJPotV4@vtEQFby?iiBQdy9>3%^gPTgPosw$7b+7%2LX4b7h6N(yt zKrtHXjuum^4b5an?ph?Ia$T0)rJt&q;d#KJ1d>IBms}1Zx$oYRH7xzukwfdZOs3lT zDt^Sk*;RU%;l8hSCQ@t9sq0E`#J?B_TmA%e!&c`!Sci*#PH5rGFfS8@gj@f3-(H zFo|bZO_fO*i{NKFxbt$a>PRwJ;|8hJY&RmckV7s1XMQDk^*5WF8Sr7 z|J|_n$;=}(hm;R8M~m%kGY9TXAMsL<)Ug87&R{SeSJFVLG+*8tXvbc5vTGY0WE4?XO8#MIX_H)NgddkvHC+2}MLvSwsT4?6Z0T?Bz8Qi1_B z+Sv=A35rOA1&yJ&8-0hW%FR#(*!&&BuIlVtz*2Ll@H zIt{XEa{@Oy={(3uh1GG&2-Jg0(-8fxUm2N(sP(Jeva;0h-^2%9+%Zz53qN=3E*Y=_ zVq9^+ag(cNA{oarH^n|tz;Hs*N}0w!V!@;_6Fif==vQ`v{|7akj)_~x$so9Ggmn@vB zUQcj*Ma_{ycN?}Ri3pI1aRbHOtaHlIKiG8qZ}!M9$X)Qe(^|HUQzjq6BNjn49u~eP zzu^r@6*HS*0269{=_BcT=^WnMW zzvt>Lebikm(2E5d8ik8q{&*hOG;7?6&ouZsj_3I$oX6v+EvX*R?IyKv~chs1c&%z*hvcTjSZ z3_NyNm2&$I~tHcA5x`Z7s!moNDAh(%78e3zX=L6 zg$%b$>4WwpQ+mLzWUfxJkX_dM~~WL2cCqVIVNF-q7f+K#>ixe%Ua zDwlrW;UCXtr?=$1q$hofOx@d#8cH8?xkXq2Vo^w2|D7J{6JtG+rNkJ>P=~dlfYTWE zU$!g$m|}G52Zi#I_}lqG54|47ANL-|sXYIsJnnecsgQ^(IO3-@i3*S-9 zEMwRCjIJuRE8EdLD54bScyUCF8uwq1V=m5fo8P$5Y312QLPtmX_pdGg6g3X<;H}d0 zI;P1hCaG_^)I5%%7Xjj#@$*KA#KPRdG##rA*M!@;E4D$wZdi$~{`FlgLEyu9etZ)~ zevF8UbMAlwFG*(I)>-OE>etaq)-TT15Ec+*L3pbin#k4z(=!ZXR^{o^Nxfdr4Ji-Y z_i5T9%^G%#9CnVeTIp>X zTLt=yY1a#%d6{+@N5k-u!LwOGmZ<90@;5+;Uvi6 z?*_dIVr^C-ADH3>rrkI`2$P9t9=Fg$0|bFc_ML3r-ZzL_d~j;e3aC60uSSzfHmdTn zgR>I-B`E5}gt`{8q=$PG#PNGShg7s@t&XVRgq?GlhNU=CtDs;_b_&sJY@sZ`4Jh$3z6JEy|`U z?{eB;<-0*rw^B;KYIpLJU1@h6++D&uA}X0w0g`;Su8tERQL(~Olre~D`uQ1$(F?B( zqpcN;9Bw*D+TkYSZ5rG}S=sThpCl7Z3kx|}2Nw{HmGli#Z&4tLs)I+fgoKd7pSV`P6Z*T zC}H_AnG!h1Ejl7$)>MTP@Ve2#XiN&jg`s40zD7m|BQ(vap_ECNiUdjXs9{2SE)ICa zeM$G&xw@ao5K4x189v5m;y5V0%z9ruW>K+h{Cs`iPtOVu)brzmmE`$Z*ZW_2H04K` zZtB_w>(`g$&Ycxra9klveKH5czw-!?<1^sb#7I5AYOqy90g?cT=Us+i5Fb-98Ige# z8{*ZV^pvxI5BOCWoi#?^t1~+v`m9wUZS@ipjt&Svjd}KqLE)*N$3m3vYpp`yOcS2A zNyI;7{f1N()Y1j1OCV{yBz43aE?C3n-H;r0|7mWC%_-ADQ`;c=rNQ? z@P%FAY0eB<3N@=j*$PrR3^@JAb2DCBLf;FJ@7frsP0E^m9JF^(k*ed5i@mjIgA^JS zAm)u>e2NOQxu6nDfGSxPRnXR?6m%faK42w&>cGmyBe2ZtQKNhq$V-1I$z2g3CX4p_RxyeEdRdIRVw&Js_G8){FAB{o;3PVxC%JRl!Vr41S_gJN|9+ni&~M8Y@{4lh-C&nvAP0>6^FGY`jpDz(})JrIToA!YAoNXJLig33|J zQy(>X=f7~*lRtd-L-%~PqX;$BwecOMZd%eFua24GKZXIpwsc>XBUMW|#x{lwOb#HW zE;eN_#%^c6N0*B{`mh_|``A7^HvxFSWy=cAH%Uz?sIzcPzs}n0}D`Zttc9-nPBo6jv z<5WDYJcz$y)CfxHLkVJ*@G!=j(veNhj-WGsPr@!Fx~fF8xvw?B+WXs<>3#aw5rh3{ zV&o(ryG%m^&kBkT?J6BHTwXp`it=XZ6knmF;zL4^_hnQbVv{D{2pH8-r1I=nTv0goe1{=u zW=emgo+!S@ui7d#Oh+f0!2{khcxHh57O+qyOnkU(WoO>gnh7+q00y(oFFpsOj(kO!vwG0xi z8m}n^PY1+vM0)ohuftvO&HHecI4e)f3DA02bTay^<7}OS+rdy(s#~I*=KmUObc-BT zB6!Gt^zHfA;+3Sw5qp|=>zV6Q*=m}W9k}gaVUIe6PR5pC&9<{NqU>lp2fB| znPCLiC^N=?Rhf~fRc4jdEY=dI%s!&_L@Z+uVn!AF>rH7F6g8sMR;1D9NjPZ5pu_|G zViAuz<#T_^2nELo*jYE2Un1j74x0nC#)lJLP$-R_ zs!H3$De7si(i-2JWUF%5WFEm~QsI%$a`!2X2^s z?Y`|yXObMzMNxK77p7k7YH8q^ThD|k6SVn^cji)Jtcs(UwCdvQbDI#^IA)~sDL5ZZ zijRDQ3?@i-jb-_BknyE&NSq=9c*CxqNYrV99#roolT;k=m%ZxJsyb;{A+^!9e!`18 zZTv6yB4(c8$P;)ynuMIBkYB*e`u=CdxIf(Kam#owk2 zQ-@2fGfPv;rV0bGl3QLrxW=c5uv`9}AwsRFb8CmbKha;(`{X~^WF&QP5 z+h2Lz9EV7M6f4i|wSf|fa?#fUYEFwDNdUQ=3`7N%YICw*B$dqCA0MB#$_hp)ip?>K zO?^NU+{{89Rf&W{mVH%|w>l-K7O0}BH^v)gvwc74RyW%tTN&n-TZhuxZt1gpfviFO z;2%m%E1#Q+TaDGZcTv7DnF}D|P%3_K`mRx~HbMITyNAY3)I*Txm)1#dqEZbCy59N3 z5uDDh*5t4v!qYe!8jZXdO6dT{Lj%uM@}<(m%>AO|yOc|5A5M`gal#e1e6K@F{emLql=U@ngyYVxV@@GjfoeS zQji&Cad@qFA`Xvkk*p^~BJ0vh1L~NCHe{tML{foP31c?_ty$v2>_Lms3nQR$NO2SK zdMjoCU6e$i6eX#EYEHx1e0Av%YnIH-Ma}9fAT|~a4CShk?Z%OI7SI#C$A>FfC*%o{ zG{isTd;mv`>c14fVOPt^IX?`&aGJl2o@JOA`~!uXvc>p&x?;Z-e*fd}HN!uNCZdI?L3ev|XgxS0O$sv6xQnq&!XUhP12=leGTC z_oz|v?yMIW+J<@yo8sRuPHM?zu|~Wc)0-CC`Tnl0w_BS#lP1UiBnK?M?)ukJ`uazD zO)qugr;M7T77nG*vbaV2_REEtk>66&rwn9jpy~BcN5 zl>)8@;-9F#jBKBVsF_=vamwO^agvA{@qn6$nixtEwFcNJ!d0!(Rj5|k5%q6T9gKc- zhNYu^W$0!t{HxPbiN!Hn$zcu>pS##iKxNt2c0c;Aru*SQL_Hq#KaSDie?OPaf~d*v399O`(63}L_{HR&o<*v?d5Uy`)5WJrt5y!daw zK=utFir3xS$G1P$v=PIMw%XD+C}EBtoodGCCTfB|Du0bD4dPmeLlr{8w%4hprPc6r z(30H=I0bxDGc%O<(~tiGXlX#E&@y>iN6TYJUKK5G7r$))(VvNyRyv_2jE83+{>-;V zcg3Ii&Ka83c=0pu9NQH?Q*?=sJV4?jwo8B)|IITbTHK4DYFmZ)!^iRHs?bOOV0>5H z?q2=*-P{-9N?9wuhLVm)`%VtYvOAU0KE<+=fr3bKj_&F}M(VbEW~F3biIrjy zq};Gn+&wmsSFu(c+{mlgES|Gj+>}|Wkj&GVF1Da>`ZrQ~s6(ogv6s|ZWRzyGNwFnl zry~z0wJSHpp2$vPPh=xM|kF?iDYHDChWMk|IPez*A5y+VP8QE1kf^YzK z1TqW35h++#4*@$ODkrS`rrQ*^ErBa!ZQjZ;AifbnaIqI@r{1xmRfOVIs_}j8=2f zgQiWz>3Z&&MISn!EV*sbv$9cu!HmXo-cE9hlvTg%l-a5LvR3Hj{j#)z#*n?nmm;h< zo3;4ggD^k{RlcIGMl<76-MC~2qC;QxbT$?t5XP~d)3+g?wP1!4MY(xb#5-l0;Or4D zx4iX!^etA#zW7;hkm!p)7XO7D$GcW~-kF|r+9ER$AUUF) zu%;wd^4tMOgVZ;}td?Z)X$oT(0z8v0hfuVlW<|*ZKl6}bnZ&>Ah?ym}J+8?>93;x> z$Nuz#$OIR=tGdDT@Sm%UEY?X;goTm+@Il*_D;YfTqn1^>09FRk7b}AZ>zCePeAGm^ zYKBn4_?1dv4UGcxL0BZfR#rg$G{WUoq7<%M(+F4fxpk&RxTYH=gMR*&h(1nck?q*` zsHFDXEv!=ub;q1Leb;acTZeLpT07!BQi79986P-$^P3;mNp8Hn;~=x}+$}eggB?t7 zmg#?sjO<%(=A_wz?f0SfOE91{HQFq~A&IFuLR;eJmNl)_Q>GTY;!x@bBiHUEGOgJM zqC^)5C%{9>ED1>?XlZ%bv#+|oWmey$VuFf%lOs9>E^EDbDf$An5GL)i*@fg?J8jp6 zXs_^;^`5q|vNX)5$GH1<+k~}P{PJZ!2KU4fulV?7E3Y0ckBqL|HneiZ$oS~k`0&cH zp`kt7clHeoj;+vDv+d-jyKj|~g~dE3}Xxx8|3-|&i&QP1;A z-tGK*ch>U|ab68h+xteYA6hw5zJ6eI3}AwO{lM7H@og)%5A9vPs=R%B_v&@)`nRns zZ|_~bX65k6z}|tef&Jy>V>b<#N0)c5=v~oir9j83dM|ZdM;))>=kwb*I99&CJQ5A< zFOTflGjv0A!_M+xw7qY1Y+&&EXly7N@9ui}Jfj1@R_@y~Qts=&DcUwPGBR{Sxxc0r zzZ}YL9~vn;!tU%FS-H17wsWX|RE@mOFL^i7wkvX;*T}VRls*>SqaA$%d&>Rmqpcl# z$~(rQv(Ju3)WxT5ZHyv4;my`%jqaiDJ?~jy!C&6Ypu}->p0}8*==Sf|I>$hJ`feH; zA9LK&3l3`EOb}Vebvs$g{n6GyG%z?kK2}4`SIO~k+vrZ?^VP-+{fw%ien+R@2ut2o z)Vn3Yp{AB!4oAMsSYKHlWDq;to(H#gfLA-jS;2KGj}G+T7@ZYe5MLQzuyOOX|3`5j z9O^HF_5+!ccMx2!2wZ`0LnnlXyjuaQ zbetw={i962l^xi#runUsD@l73})TceY2ZqMa^e`m148%ESI~bL67bN8d zkntmfeS4xZl6ho(1RIt|7=+`4NNiNywmoG^_LoySj!;f?oLZkSRqLuW{~h>O?R%wl ztdBhJl6=WKoigWdMhU*QZ#df7HyZU1?AQTTkgvZyJhoF>@n-TZ=K6n@_xtt_T;De) z{=W}=?f{<&ezW*pF*Fu2y7BqZR0x}=hn33)yg^Q7#is>k1Suc zqHD#PI-NdPD0!Q~=LZOI^+hW8e8!bzZ<_uI_X}#$KjnT7zrGPn3iRi|_GoChJkn>X zGBpTzpV|y(a4&eNz4B4+n2%M`zt0`Pz)Jc%+)1`=8rxYOxd8f%l`q;mJa*HS7hF9^ zOJr_r8Xw!VW5f7hzujEiH)_{SJ9dng$6SdEh7g*4+s7`KWs^SIvu9uwRd)f@-#j#Q zVYxhfVR>}m`ax>w-#Cb-8%Qs&?;E_noIJX8eDCm8V}09qZ%T|EOH^2$NIbfs zZ>(?6)q^|x2K&*hvVTTK#)rq~@T4t^ar?K$gd98-tyj|L`h}X63FBLdBiuh zY00BBeJl4fYtjcMr9VbmaO&zARYy2{_fU`U>g8ABm!>b|UiIitF1eTZyR{CsF@TwZ z-jhiiRKMyFEma4qz?+fW3wMp@llaM=Q9k9L$FG&2V2_Ls4wgq8zDt`*hSxc~JG=UR zY+!HMx^yo>bzo2u!}BgAuV`21r#jN~Ztg|{f$i1zBfL|e zrulD3@~3IpgSGF~CxVy0SD)0rfBU5OvPEj&-! z`8Cg;;l8%av!qpjT4n~B#Ybs+32F6hnm%RH`;JNJUnMP`OY>hlDSh3f^cyFoZzA1Q zQ~n2&(tm;6hXfV)f0v|1Tbmccna{U4+FndP)V-IcFXdisPt&hW-gmBAy{2nzcTexS zzHQt4%R8)}`rQETol!E|KL8KG(z|rNxjA|FCZ4OVH2rJbYwU>U^hZ$}CmIur_$}tA zF{-Z|9qSgyJI&~zvxDs3Zv(b4DButUO6yaj{EyZ&~Wj7Cdsl1mEJgre}so<;X#|Z zB{wMFn5h?fu=)UUptM~^-oL)QV|=vSe`R?D%_MDoVR>+%+z+q~Sjqp6?txJRYGqb< z)69~$AG-c2ogv-wYUaDAkY9i5H^;ujhI9kzc^ij z97@WaLEY;2spVd|FR633^Ci8Rt9&B^Tm@4$M_Lb?|J$>u=Gj@vvoy~*Y025Cxa`(! z!<3@Unrr&+mn<~v#@K(QT^eIA;1H57NypeL@K4oX{3?gk$ev-`Kx-3sC*IO>-(K|G zWP9qaIVJCP;3OTbF?{XNxQ4=@rgFo>WrQ>4ZyBS#yf?Ay@w-LNZ`DTrwESAiudhj; zMOr#{YM%@bjpCBU6PI?)*btM8EjJ*x$K=|m!rTcA(JQTE7wL|g^zKRT$4JYLNb}#A zq(PoZ+|WqsWn-GM6PFBw-X;A zPAF&3D|v6A-Zx^Gh~EdxH<$zC?C4DTVz>|U_onFV$U8_rSjc-fSM^m|?k^Jm%TyQp zNZ$=x_Lnscs=%pM>pcb>*%qzTtMRjS#R~5yJR|9yZ(i%yj*r<4@KtauWq%9|{jHCx z_m{UixNbh|#`JRXpybOpMnmIc@_lZTA{<>$x0Kaanor^@K)8{18F}J)!@%O=9pWlG zGi`UpWZAKIY~{A`fjvyBHS1BGk}t9&R`8R(E8P+C_lF6r)uh|_rRg=?3wHGDjmsLB zMbWQEZ;jsC(b%!sEEHTD5BRsx_;+R;^vty{czb@2YhQs;pkUdd=#t)oWLGukKmhyL#Q4&NZvntX{Kb zP1l;WYr5C;tm$2|uB)?aRoCjSHC+S4a)w{ZP zO>bB4+TQNop5ETxb?ZQJ9o4S`^g4>I{8rX=@n; zbt6XY-0FG1OF7xp_i+_%H4asN8{sk&w`y*OgKr@QiR-u)Mg!?+jN3tNr_f2ZN7iK2i9$;78e? zWPTdH*zoX;H@)-Dk9J=3tM7c*p+$@TYs-wwF8|SwSFAkuO>f@vnP(2(`R==a>%mWd z{*Ryd(wG12Z=U_z7ro5PS*NY)>REs0*&8o?^TBuX@((}%$6xxhuYT>>zh%>c7JIw? z%!@W`y!0*o<%4&B;6q>j>erfQo_5j3Yx>J~-u)n%pZM~3pZ(k8%`-3B*k7JF_y>=D z;qkxx=J6lg{5CK1d-wg#cUxwhJUFyy@s_vV^2tyA@nioscixhdH(Y$h zreD48O>ep7*3UfgjlcZs<3ISPk7dS-4$)B4QfQ?^8VGrLZicrtt2 zBjJMFZ9fUG&Ce;$Yna_MyJ=UhF}EOhZT^hxhQ?*A7Wczd#bucVxnel+5U<+Ky*#r# z94nj^&Ir%S_ZH5`-uB|m*22n}%fqPDHe=#lncLnszc}ZP_hwgS&&&rctql|ZVfk3o z#9u9F%1*qPo%n9k_nO0lcZNL;2i`P$;?csypP$|vHs*Q@8wyRivEq{Oy3Dl=6Suc6 zYMk3}d1m4_bDy}cX=X3qBK1oMLV&5N>&3rqc7;qKtE;OoIRn*OrkuYzv|-}aAX zpAMc2z84+Oyb%0r0HgX%r=EGv6`St*@P|K=%QtkNea;*H@#xnxvs=4+-f+#WAOGa1 z{^QzXv)=xWcYnCTe&W6>Huaa^^x4lXT$C>~7H7}vUbp^%2cP;@L(ieRAILYJdCrc3 zyMAkE%lE#2-M06C;M9(*KXmxs-@EVr2Oj?XV_(b_o8~NDf9^%E``G$t1x@1S_uUs*4+v0H5j76EH4NJ0TWG~FLoIdgK+|ta_Oh=)s=uaFv(9r<#{4LD-=k;bT%dX5c<{R?oMW<$(8oI;v*#&t%d$@9A&zj~n`4xr6 z1Fw1g6&;1s->_)*yoM_>OJ-cqGC$v#yQFYx!+7!B`1IVF*~Z-Ka(=cHW+&dcZOJ8t z#)*%;rTwB}W3Kt6b@|5bWtq~%k+b@*YPzJMal=ImFDYELc-?{ghQ`I=#T$FVmO^8W zTnD=6PkhdwvAX&859}B(PJHnx$$YgrKzoXE8#evOD zbHXs2Zl*WU(6N=+REN|(@lOl;6wwKHvzYNhUyF5)_!@cxRntna^ z@(s%lOYH~w>o$+vw1G+XRnnJcX7bF#mc2a_vG!xD_vVuhd$Z;pUeXjDTk`#7(HW#?-W+)=u0HNR zeziAD$bY%d(k%Y-FDZ7;Df#7mkP8Ao^DF+6g>NjbZ)osaGkyc3H+x2S!wf&_A$z8P z*vU7dQ`W0+ra*?qV1XY5>loyj08!^J2|~UsBAq3JKRcL<2p~6*3w}Oq43_w3Qnrbb z9ROb!W|0qhK9LYip+kj%(u;z1;Fi|0*uTWj@OiTD7yQ@xLB6T5%?}!ixl4nEK=b{c z7N7dEMSp37za!)4Kq;6XWWrL0Z5xA}kLQ-pu@;AmgC#8B^YaBiC^q=Z!yAHje?OmN zv1euY9hwiOdBF<`xyHcnoOy1hlXTYa;Ec712Kr$yFF_+*UkHMGLciJ1tGY1w(t1DZ z`Tx1i3-9!|MqX|p@G?FhnqL{9t-*bMkoDgeESS~ozosz1xFYPNZ9#CVe*shv_FdDO)30m{NK)cA+5}Ggc<+$f$s&sTYSXtp3xhw0@g+0 z(yU)Nhfg268W=JD7Cxc!Y5QS6EX*-#`u<$MB_C%0b3sj*CrZ*g%H;?D6MS-97Y0`s z^kkQ)z}qt06w$HXxujQx!I>TM6 z$_Ibcj_047d7bWQXC_-H1o?-`dt2E>_i|eV NV?zg1X+J*y{|yGP@ALow literal 0 HcmV?d00001 diff --git a/mock-enclave/src/near-test-contracts/res/test_contract_ts.wasm b/mock-enclave/src/near-test-contracts/res/test_contract_ts.wasm new file mode 100644 index 0000000000000000000000000000000000000000..d8d2e178ab0dec37cbd244fdb94e02d1ad826f09 GIT binary patch literal 13229 zcmeHOTZmjodakN-PG6>aJVzH>vPQP5d&XY*rtxiM`97t^vgHeA*YV~dkWp*Yl6t1q zGt+%$Y=uQLB+EVpvSHW6d0CdQkPss9ONc`Pao)0ILqZ;wyo5Lqh&RE+VYA?e1n2wy zI_GrvNU{_#3k#8~K6R@8`tSAEUw<8|_VAKcO6gyjIb*iB_4XO1&P3bNit*T1>{e$q zhuF_1{$1feedUa~f|dYcJmCZaCRg|e!;w79w{$J)^tY1s*|kBYB58N~>zkR9{>Gql zp*zevgQZ@luj(?q-tKpom1cW-&}pArDqz%<^bNDMLHj~y>8(LG>!@k=HHtpMtJ|b& ztKHk|U~aZK=ws#+$K%-OM8y@Qs!5zwDpg$#e{{vDBr(b;n>0)XPpU=h7=Q4i*Og8p zt#swdscr3*-TkA`cSW7t4nNzf80orOu_b!DXYWOH1uuZ*5ua zsV$MecDJwg)!FQI+QW`IjP~+cuh&`5RMVnA%eqTvF%s4GWP{5~g{(pTQznt^s`eRy?*>>Mo(=!eblI?amMS77ve>){6YVY@zbeN7M+pb9&R)v7y0z{ zcpHyTAWd{S0g?jxcM9mp@0im>(To8YZ#9#|A92xzRld8}$E#aj`#2jm6TH>DUd4z- z^T27KPJB9n_6G%8Fqk$gMHS~tGMcMv){TZ+UPlMQtPzYcB(n$;%40?&6=BX zb&ztk6>qYYqvnh~6)&1afPf&t5`a|!X5AFQ>H_9!#{uZ7kW8@E0a|l)R|_~|+pG(U z8u~5pYnNoyPpb}$z(p`Ob=*LxI&e7U6qF0FSip|MrSRvoST~^dLVbUub7f!05PzGG zfg2r+u;L=36tk>YC^n|~5@=6vfMRYipRS-M0Li>yHDM`EYfckz!$pIZ0aJp#;wqd~ zxgK^)PcXn=LdL6rv#<)`g~G^t{zdy4@t!DfK(skuD==U+cOhY>0%j_37BEu{%(zNZ zgI)~&%>c|5Q(=f&@WI-3eDJ5G5=pJL;^I?X?FNst^mFRVf`1E`xXhXNCGL{MT8i0DW{{ zajORARxvkn8uJ^_6y`_4GvVa$%+jH-rfE31SaTY)8bUil3(ABc#pPoQ&zs5yz&Y(2 z;+t4Dv9-TpbQKQe%xhS7FxJKkT+V2lqFw0j*C7H;nWKm6eZK*x!wSa=2KVr6===2o z{5PZA^4h1XFaaUZY648WG|@J}9OZw|7)^RNrvV>xdX+BaAC@RGW9gD!XRDAv)Bezi z9?&s1#4~C^oATHXyihfWVM!o}iSLMhxQL+{7ab?_P+={_%C-Na5&Y)rerCnbNQ_g@ zD=;d&A!I}C_~C$0w-_Fsewi8qi;K#umqcTW3i!nPVO9ldQ4{^(0NN31hQTn27Qyp@ z(=SYG0javASrIVAE-?#$W4HkNs(`J+zY5q8%c?oNcx&NOB*9?iHC9yvMglX40xQiV ze~DZWrjYP?<8Zmy>=?kmb3L-p)=rBiIjMZhZtj*Z!itrXzmtlmF)rE~_ zVjKAT@zs?$6SP};xPpmXlx>KHpij7B2)Z(0pbv~8Jc^4pt7u(p8gb{E;6f-baMAS& zPyQ$4_mqxb2PDGOMUc)d5RVph)h2@OCP1!ge@p8M)st(AYopK<6t#k|2M?r5Q|Kbi z;L8)s?!^os7~SogP-zRhYb(LZPhOs-6pQpwC?d`q*mi)r3g0JUIvD-H{-M?p7zzmdITALfGEU+lLD+a9XdW>Ct^#*f{#}~q1Ho^r0nnRflHW0L?I(f zIoe>LV>E(@EeS6$E%yT*-jD*>hm?9s(YFx3O&)w;-VLuL=OQxf+(42uAr3;ah#sUG z-mz(GUmLwQ_}(bq>1ULJ50XNlFGwMVF!c!n-Uv4)5jz$cCdb#p%XplRGu0u!1+AXe z3Pj=HoR5dhXR38`g;;E0#&gM-{4X#?5{2Bc49gu4n%7jrNg4c3ckQ1Uf1r^}fz>h760 zvTGyamiC3}1QH{V6%y~wB{l`?;5((nI788mw6BzWi^LcNL@_v3ObZfE&b+OhDH2c4 zyrINcfd40nArF^aZoz%IJW;_IxUEs1g9Xdgk}Hu1gRpTiXp3nV3K>t4*pwI00wW!X~Cap3O|AE z-5gSrH^7EM)^lo36$$7Eah_D;=>!cx4uLj=f6vK!*uZ5}h7!in&>O5cZs>1L&1`L^~I+%o{t; zWLFc_oI%=^-pLnKSe&Go%r@t>{gIYrw#e66omCq=R`9@qDpp{4NBf`VnK=Aivy{Qy z)9dsZFv`UKZI(+ZO}Zbfg)XlK_>ZS~oK(GfrNs5$&_~GpkD6L~J2pfNm9vO08j#K^ zCyx^V`a?j*Y(zNafv5z84fcS6u~WhYLFS;Ch=h}% zb_$b|j?=r~Q7FDpl{_(wO~Zj_G$rR1?8I~tRy0M3aHd5a4tB)+;uxdn!6aCfa*@-* z9nZ<>5ljSJUe>uT43`OOY{6!4=M+HKP0V!){{N4WNw)QsfCnlGkyL_T2$DR@F@nMy zUCfurqf#hQmIuJlhqFu3BB;qhWnNUytCaH?k4nU-!{&%<0lcGYzRymfg`MH3Y1p4hsm!3}Ujkd?gbfLg{w}eAY7LKh!in5<^=*OnIu;6JMTd*Kee?I$nCt(*UzdOcsCeEq=h8HH7_$sid@fZfI>+u zCqQDtH6mm{PCZ~V3wab{8RA-c6wW;>+Zz`Oyga=Z*1C^5M|#*9`x0tyEc(J4vT8DM zQLfJl7^$TD=wWDZQDGOMCjpKw9YMjo@k!DH*2NYzrF;c>y=8mImq7s}4SqcHX1E0I zQy7L=!ey%}rjG$xLAA?O@w3`W#Khbl;i0Vj1_MJ4kgvRJfNKl?kfCPZ)jDB;7Swe5 zAQa6F1vHV&U_3@COraY~h~3*`-KG_L)e=Epo^3(A(0*x_tZ~Jy%8rPj|0)>*i;w{k zCVdE)Ty+f7_)W-&gxwT1U+`d+Q-_HQd$>#BcQ?5COEt7rs;wtSm@)0F_czDO_;Qh$bK)@ zHdm<;WqRZb2-^=JK0_3!HG*293?5`~?kR?;e5NyW7MP#7Ba1n^O+h=s5#*|1uG&O( zTW(LnRY`$tVqOCK$Yq0zU?1i^IY*>Ll98d!01@ z@E1d||xJ67KK9t}N_=5-yiwjk~(rP$lr;DyWrrRmz zFGT?0HxihtFatm%qa~y}?WVoZoi6CYa8OgA%TA$7a$|H$GF1936=+9cCxxK7y@lSNEs5E1jeF*X&cM*ur|5aIEj2Vds%j8BREQP>h?F*4|m%LRp{k4r8D zqc@XlWy8YvBiSlrn;)XPWV95K$GspTphZNC`pTC7Ko3INTj9pE!#7s^0Xs3}bHxuE z@JI#R(tsU%mY;%$hTRKGnI!ja`ASamTngB1iaDo*6Co|e9vG6de! zGO+OdjEnvcqPc4N2;&vH9)l6!p?E@hc>gjqjhlHq@u@+2?;jyIM{L5gb`_)&?A`Du z1|@@k5&j|R#qMwzo4{dAK(Im*{H`{&?P$awV&52lwd?aoB4jkWdQztqkx4@)ycmWs zH^pi3No>dfN+=c^6;5NLdNr-?W`;ZN1h+O;(9ySzlt1R`Sclw|1bcQkT5 zY7uG~{e^~W{8;KXd}*k)iTI(1S)75eLEb_KP$gs0Q)W@rS&rxZPotmO8tX6Gf{+5J zmZ9XrUP%BF{&6x5ChW1h6S;{APF`s`Kg?T0^D$347w`*c7(g z0O_eUwTxDV$!n^QrIz8jhG!4G19d@lF!>X8bAsz?6Y!mq;PR(B7Me}-H;C^8MQg{(I`zc9cD!CRe^_!M}xJ~;w` zJA+I{rtX-S(>{0ZHTjO%&QA1q``xVD?sb2y^R>0LtTBmheb8BN4?1sPbb4}R*l7=z zFAAaC4oo1tFj#vlP@1`OVjxE*bJ9Z-L-JX3I}0N1**`IsfAqY!6lZ;N(1HDyp@mLA z+jn~bE&auZ(fdnq(b)MxCm_FlZvnovlwDr$bo=Mm?g#>GX5HRG_|}?_<@L)4!oa8x zpJ5+cUR%F>F!)$ukEJEzzq2GMoKO!`>F`jgAL(zeuXpF{KK`GNOc zlcHW~4_03sv@hR12|iqI_fPiP%d1EB6ru`U_Pf#|(v^QK{>vBfJ$!Q#OZg>v>v}pk z-|hA09u)NL0a!S@dH#H7u;AG~DebR!J8#V`ul0x7U~?JY-Ot}E&{X+3nX>R^x1XJm z8RKyG-19kb7dqKffz-VZd>-*R0lb`bUhVWRWEa15Sbz&_VYTrq`oi6gmV%3?P}?$o z-@MF%0NwtDg*W7J?9E>~b>bKdwRW!aW`Ec|-?{(p&xd-TbmrWTMdAnVx^|W@jkp7b z9|{bML+13C*Di4-p1!o+I~LZ?1Y>g&)m}fp5L_f^xYHkEsc`W=e4o$@-NL~$*D~S&1kGHPnDyaNyY0NL* zP~n|E&2rrB3ee;KmxKJD4^JHV90-Qu69=yYAkqKH(wee5C!;|A$I_ULnSIYxnbri>d!F9Olo&S3a#+~4f=)O+@IUDsyVPF)U%`(lzW@LL literal 0 HcmV?d00001 diff --git a/mock-enclave/src/near-test-contracts/src/lib.rs b/mock-enclave/src/near-test-contracts/src/lib.rs new file mode 100644 index 0000000..0fd0804 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/src/lib.rs @@ -0,0 +1,85 @@ +#![doc = include_str!("../README.md")] + +use once_cell::sync::OnceCell; +use std::fmt::Write; +use std::path::Path; + +/// Trivial contact with a do-nothing main function. +pub fn trivial_contract() -> &'static [u8] { + static CONTRACT: OnceCell> = OnceCell::new(); + CONTRACT + .get_or_init(|| wat::parse_str(r#"(module (func (export "main")))"#).unwrap()) + .as_slice() +} + +/// Standard test contract which can call various host functions. +/// +/// Note: the contract relies on the latest protocol version, and +/// might not work for tests using an older version. +pub fn rs_contract() -> &'static [u8] { + static CONTRACT: OnceCell> = OnceCell::new(); + CONTRACT.get_or_init(|| read_contract("test_contract_rs.wasm")).as_slice() +} + +pub fn rs_contract_base_protocol() -> &'static [u8] { + static CONTRACT: OnceCell> = OnceCell::new(); + CONTRACT.get_or_init(|| read_contract("test_contract_rs_base_protocol.wasm")).as_slice() +} + +pub fn nightly_rs_contract() -> &'static [u8] { + static CONTRACT: OnceCell> = OnceCell::new(); + CONTRACT.get_or_init(|| read_contract("nightly_test_contract_rs.wasm")).as_slice() +} + +pub fn ts_contract() -> &'static [u8] { + static CONTRACT: OnceCell> = OnceCell::new(); + CONTRACT.get_or_init(|| read_contract("test_contract_ts.wasm")).as_slice() +} + +pub fn fuzzing_contract() -> &'static [u8] { + static CONTRACT: OnceCell> = OnceCell::new(); + CONTRACT.get_or_init(|| read_contract("contract_for_fuzzing_rs.wasm")).as_slice() +} + +/// Read given wasm file or panic if unable to. +fn read_contract(file_name: &str) -> Vec { + let base = Path::new(env!("CARGO_MANIFEST_DIR")); + let path = base.join("res").join(file_name); + match std::fs::read(&path) { + Ok(data) => data, + Err(err) => panic!("{}: {}", path.display(), err), + } +} + +#[test] +fn smoke_test() { + assert!(!rs_contract().is_empty()); + assert!(!nightly_rs_contract().is_empty()); + assert!(!ts_contract().is_empty()); + assert!(!trivial_contract().is_empty()); + assert!(!fuzzing_contract().is_empty()); + assert!(!rs_contract_base_protocol().is_empty()); +} + +pub fn many_functions_contract(function_count: u32) -> Vec { + let mut functions = String::new(); + for i in 0..function_count { + writeln!( + &mut functions, + "(func + i32.const {} + drop + return)", + i + ) + .unwrap(); + } + + let code = format!( + r#"(module + (export "main" (func 0)) + {})"#, + functions + ); + wat::parse_str(code).unwrap() +} diff --git a/mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.lock b/mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.lock new file mode 100644 index 0000000..26eebcc --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.lock @@ -0,0 +1,97 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" + +[[package]] +name = "serde" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" + +[[package]] +name = "serde_json" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "test-contract-rs" +version = "0.1.0" +dependencies = [ + "base64", + "serde_json", + "wee_alloc", +] + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.toml b/mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.toml new file mode 100644 index 0000000..e2ceac0 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-rs/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "test-contract-rs" +version = "0.1.0" +authors = ["Near Inc "] +publish = false +# Please update rust-toolchain.toml as well when changing version here: +rust-version = "1.56.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +base64 = "0.13" +serde_json = "1" +wee_alloc = { version = "0.4.5", default-features = false } + +[profile.release] +codegen-units = 1 +# Tell `rustc` to optimize for small code size. +opt-level = "z" +lto = true +debug = false +panic = "abort" +rpath = false +debug-assertions = false +incremental = false + +[workspace] +members = [] + +[features] +nightly_protocol_features = ["protocol_feature_alt_bn128"] +protocol_feature_alt_bn128 = [] +base_protocol = [] diff --git a/mock-enclave/src/near-test-contracts/test-contract-rs/src/lib.rs b/mock-enclave/src/near-test-contracts/test-contract-rs/src/lib.rs new file mode 100644 index 0000000..8647e19 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-rs/src/lib.rs @@ -0,0 +1,804 @@ +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +use std::mem::size_of; + +#[allow(unused)] +extern "C" { + // ############# + // # Registers # + // ############# + fn read_register(register_id: u64, ptr: u64); + fn register_len(register_id: u64) -> u64; + // ############### + // # Context API # + // ############### + fn current_account_id(register_id: u64); + fn signer_account_id(register_id: u64); + fn signer_account_pk(register_id: u64); + fn predecessor_account_id(register_id: u64); + fn input(register_id: u64); + // TODO #1903 fn block_height() -> u64; + fn block_index() -> u64; + fn block_timestamp() -> u64; + fn epoch_height() -> u64; + fn storage_usage() -> u64; + // ################# + // # Economics API # + // ################# + fn account_balance(balance_ptr: u64); + fn attached_deposit(balance_ptr: u64); + fn prepaid_gas() -> u64; + fn used_gas() -> u64; + // ############ + // # Math API # + // ############ + fn random_seed(register_id: u64); + fn sha256(value_len: u64, value_ptr: u64, register_id: u64); + // ##################### + // # Miscellaneous API # + // ##################### + fn value_return(value_len: u64, value_ptr: u64); + fn panic(); + fn panic_utf8(len: u64, ptr: u64); + fn log_utf8(len: u64, ptr: u64); + fn log_utf16(len: u64, ptr: u64); + fn abort(msg_ptr: u32, filename_ptr: u32, line: u32, col: u32); + // ################ + // # Promises API # + // ################ + fn promise_create( + account_id_len: u64, + account_id_ptr: u64, + method_name_len: u64, + method_name_ptr: u64, + arguments_len: u64, + arguments_ptr: u64, + amount_ptr: u64, + gas: u64, + ) -> u64; + fn promise_then( + promise_index: u64, + account_id_len: u64, + account_id_ptr: u64, + method_name_len: u64, + method_name_ptr: u64, + arguments_len: u64, + arguments_ptr: u64, + amount_ptr: u64, + gas: u64, + ) -> u64; + fn promise_and(promise_idx_ptr: u64, promise_idx_count: u64) -> u64; + fn promise_batch_create(account_id_len: u64, account_id_ptr: u64) -> u64; + fn promise_batch_then(promise_index: u64, account_id_len: u64, account_id_ptr: u64) -> u64; + // ####################### + // # Promise API actions # + // ####################### + fn promise_batch_action_create_account(promise_index: u64); + fn promise_batch_action_deploy_contract(promise_index: u64, code_len: u64, code_ptr: u64); + fn promise_batch_action_function_call( + promise_index: u64, + method_name_len: u64, + method_name_ptr: u64, + arguments_len: u64, + arguments_ptr: u64, + amount_ptr: u64, + gas: u64, + ); + fn promise_batch_action_transfer(promise_index: u64, amount_ptr: u64); + fn promise_batch_action_stake( + promise_index: u64, + amount_ptr: u64, + public_key_len: u64, + public_key_ptr: u64, + ); + fn promise_batch_action_add_key_with_full_access( + promise_index: u64, + public_key_len: u64, + public_key_ptr: u64, + nonce: u64, + ); + fn promise_batch_action_add_key_with_function_call( + promise_index: u64, + public_key_len: u64, + public_key_ptr: u64, + nonce: u64, + allowance_ptr: u64, + receiver_id_len: u64, + receiver_id_ptr: u64, + method_names_len: u64, + method_names_ptr: u64, + ); + fn promise_batch_action_delete_key( + promise_index: u64, + public_key_len: u64, + public_key_ptr: u64, + ); + fn promise_batch_action_delete_account( + promise_index: u64, + beneficiary_id_len: u64, + beneficiary_id_ptr: u64, + ); + // ####################### + // # Promise API results # + // ####################### + fn promise_results_count() -> u64; + fn promise_result(result_idx: u64, register_id: u64) -> u64; + fn promise_return(promise_id: u64); + // ############### + // # Storage API # + // ############### + fn storage_write( + key_len: u64, + key_ptr: u64, + value_len: u64, + value_ptr: u64, + register_id: u64, + ) -> u64; + fn storage_read(key_len: u64, key_ptr: u64, register_id: u64) -> u64; + fn storage_remove(key_len: u64, key_ptr: u64, register_id: u64) -> u64; + fn storage_has_key(key_len: u64, key_ptr: u64) -> u64; + fn storage_iter_prefix(prefix_len: u64, prefix_ptr: u64) -> u64; + fn storage_iter_range(start_len: u64, start_ptr: u64, end_len: u64, end_ptr: u64) -> u64; + fn storage_iter_next(iterator_id: u64, key_register_id: u64, value_register_id: u64) -> u64; + // ################# + // # Validator API # + // ################# + fn validator_stake(account_id_len: u64, account_id_ptr: u64, stake_ptr: u64); + fn validator_total_stake(stake_ptr: u64); + // ################### + // # Math Extensions # + // ################### + #[cfg(not(feature = "base_protocol"))] + fn ripemd160(value_len: u64, value_ptr: u64, register_id: u64); + // ################# + // # alt_bn128 API # + // ################# + #[cfg(feature = "protocol_feature_alt_bn128")] + fn alt_bn128_g1_multiexp(value_len: u64, value_ptr: u64, register_id: u64); + #[cfg(feature = "protocol_feature_alt_bn128")] + fn alt_bn128_g1_sum(value_len: u64, value_ptr: u64, register_id: u64); + #[cfg(feature = "protocol_feature_alt_bn128")] + fn alt_bn128_pairing_check(value_len: u64, value_ptr: u64) -> u64; +} + +macro_rules! ext_test { + ($export_func:ident, $call_ext:expr) => { + #[no_mangle] + pub unsafe fn $export_func() { + $call_ext(0); + let result = vec![0; register_len(0) as usize]; + read_register(0, result.as_ptr() as *const u64 as u64); + value_return(result.len() as u64, result.as_ptr() as *const u64 as u64); + } + }; +} + +macro_rules! ext_test_u64 { + ($export_func:ident, $call_ext:expr) => { + #[no_mangle] + pub unsafe fn $export_func() { + let mut result = [0u8; size_of::()]; + result.copy_from_slice(&$call_ext().to_le_bytes()); + value_return(result.len() as u64, result.as_ptr() as *const u64 as u64); + } + }; +} + +macro_rules! ext_test_u128 { + ($export_func:ident, $call_ext:expr) => { + #[no_mangle] + pub unsafe fn $export_func() { + let result = &[0u8; size_of::()]; + $call_ext(result.as_ptr() as *const u64 as u64); + value_return(result.len() as u64, result.as_ptr() as *const u64 as u64); + } + }; +} + +ext_test_u64!(ext_storage_usage, storage_usage); +ext_test_u64!(ext_block_index, block_index); +ext_test_u64!(ext_block_timestamp, block_timestamp); +ext_test_u64!(ext_prepaid_gas, prepaid_gas); + +ext_test!(ext_random_seed, random_seed); +ext_test!(ext_predecessor_account_id, predecessor_account_id); +ext_test!(ext_signer_pk, signer_account_pk); +ext_test!(ext_signer_id, signer_account_id); +ext_test!(ext_account_id, current_account_id); + +ext_test_u128!(ext_account_balance, account_balance); +ext_test_u128!(ext_attached_deposit, attached_deposit); + +ext_test_u128!(ext_validator_total_stake, validator_total_stake); + +#[no_mangle] +pub unsafe fn ext_sha256() { + input(0); + let bytes = vec![0; register_len(0) as usize]; + read_register(0, bytes.as_ptr() as *const u64 as u64); + sha256(bytes.len() as u64, bytes.as_ptr() as *const u64 as u64, 0); + let result = vec![0; register_len(0) as usize]; + read_register(0, result.as_ptr() as *const u64 as u64); + value_return(result.len() as u64, result.as_ptr() as *const u64 as u64); +} + +#[no_mangle] +pub unsafe fn ext_used_gas() { + let initial_used_gas = used_gas(); + let mut a = 1; + let mut b = 1; + for _ in 0..30 { + let c = a + b; + a = b; + b = c; + } + assert_eq!(a, 1346269); + let gas = used_gas() - initial_used_gas; + let result = gas.to_le_bytes(); + value_return(result.len() as u64, result.as_ptr() as *const u64 as u64); +} + +#[cfg(feature = "protocol_feature_alt_bn128")] +#[no_mangle] +pub unsafe fn ext_alt_bn128_g1_multiexp() { + input(0); + alt_bn128_g1_multiexp(u64::MAX, 0, 1); + value_return(u64::MAX, 1); +} + +#[cfg(feature = "protocol_feature_alt_bn128")] +#[no_mangle] +pub unsafe fn ext_alt_bn128_g1_sum() { + input(0); + alt_bn128_g1_sum(u64::MAX, 0, 1); + value_return(u64::MAX, 1); +} + +#[cfg(feature = "protocol_feature_alt_bn128")] +#[no_mangle] +pub unsafe fn ext_alt_bn128_pairing_check() { + input(0); + let res = alt_bn128_pairing_check(u64::MAX, 0); + let byte = [res as u8; 1]; + value_return(1, byte.as_ptr() as _); +} + +#[no_mangle] +pub unsafe fn ext_validator_stake() { + input(0); + let account_id = vec![0; register_len(0) as usize]; + read_register(0, account_id.as_ptr() as *const u64 as u64); + let result = [0u8; size_of::()]; + validator_stake( + account_id.len() as u64, + account_id.as_ptr() as *const u64 as u64, + result.as_ptr() as *const u64 as u64, + ); + value_return(result.len() as u64, result.as_ptr() as *const u64 as u64); +} + +#[no_mangle] +pub unsafe fn write_key_value() { + input(0); + if register_len(0) != 2 * size_of::() as u64 { + panic() + } + let data = [0u8; 2 * size_of::()]; + read_register(0, data.as_ptr() as u64); + + let key = &data[0..size_of::()]; + let value = &data[size_of::()..]; + let result = storage_write( + key.len() as u64, + key.as_ptr() as u64, + value.len() as u64, + value.as_ptr() as u64, + 1, + ); + value_return(size_of::() as u64, &result as *const u64 as u64); +} + +#[no_mangle] +pub unsafe fn write_block_height() { + let block_height = block_index(); + let mut key = [0u8; size_of::()]; + key.copy_from_slice(&block_height.to_le_bytes()); + let value = b"hello"; + storage_write(key.len() as _, key.as_ptr() as _, value.len() as _, value.as_ptr() as _, 0); +} + +#[no_mangle] +pub unsafe fn write_random_value() { + random_seed(0); + let data = [0u8; 32]; + read_register(0, data.as_ptr() as u64); + let value = b"hello"; + storage_write(data.len() as _, data.as_ptr() as _, value.len() as _, value.as_ptr() as _, 1); +} + +#[no_mangle] +pub unsafe fn read_value() { + input(0); + if register_len(0) != size_of::() as u64 { + panic() + } + let key = [0u8; size_of::()]; + read_register(0, key.as_ptr() as u64); + let result = storage_read(key.len() as u64, key.as_ptr() as u64, 1); + if result == 1 { + let value = [0u8; size_of::()]; + read_register(1, value.as_ptr() as u64); + value_return(value.len() as u64, &value as *const u8 as u64); + } +} + +#[no_mangle] +pub unsafe fn log_something() { + let data = b"hello"; + log_utf8(data.len() as u64, data.as_ptr() as _); +} + +#[no_mangle] +pub unsafe fn loop_forever() { + loop {} +} + +#[no_mangle] +pub unsafe fn abort_with_zero() { + // Tries to abort with 0 ptr to check underflow handling. + abort(0, 0, 0, 0); +} + +#[no_mangle] +pub unsafe fn panic_with_message() { + let data = b"WAT?"; + panic_utf8(data.len() as u64, data.as_ptr() as _); +} + +#[no_mangle] +pub unsafe fn panic_after_logging() { + let data = b"hello"; + log_utf8(data.len() as u64, data.as_ptr() as _); + let data = b"WAT?"; + panic_utf8(data.len() as u64, data.as_ptr() as _); +} + +#[no_mangle] +pub unsafe fn run_test() { + let value: [u8; 4] = 10i32.to_le_bytes(); + value_return(value.len() as u64, value.as_ptr() as _); +} + +#[no_mangle] +pub unsafe fn run_test_with_storage_change() { + let key = b"hello"; + let value = b"world"; + storage_write(key.len() as _, key.as_ptr() as _, value.len() as _, value.as_ptr() as _, 0); +} + +#[no_mangle] +pub unsafe fn sum_with_input() { + input(0); + if register_len(0) != 2 * size_of::() as u64 { + panic() + } + let data = [0u8; 2 * size_of::()]; + read_register(0, data.as_ptr() as u64); + + let mut key = [0u8; size_of::()]; + let mut value = [0u8; size_of::()]; + key.copy_from_slice(&data[..size_of::()]); + value.copy_from_slice(&data[size_of::()..]); + let key = u64::from_le_bytes(key); + let value = u64::from_le_bytes(value); + let result = key + value; + value_return(size_of::() as u64, &result as *const u64 as u64); +} + +/// Writes and reads some data into/from storage. Uses 8-bit key/values. +#[no_mangle] +pub unsafe fn benchmark_storage_8b() { + input(0); + if register_len(0) != size_of::() as u64 { + panic() + } + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + let n: u64 = u64::from_le_bytes(data); + + let mut sum = 0u64; + for i in 0..n { + let el = i.to_le_bytes(); + storage_write(el.len() as u64, el.as_ptr() as u64, el.len() as u64, el.as_ptr() as u64, 0); + + let result = storage_read(el.len() as u64, el.as_ptr() as u64, 0); + if result == 1 { + let value = [0u8; size_of::()]; + read_register(0, value.as_ptr() as u64); + sum += u64::from_le_bytes(value); + } + } + + value_return(size_of::() as u64, &sum as *const u64 as u64); +} + +#[inline] +fn generate_data(data: &mut [u8]) { + for i in 0..data.len() { + data[i] = (i % u8::MAX as usize) as u8; + } +} + +/// Writes and reads some data into/from storage. Uses 10KiB key/values. +#[no_mangle] +pub unsafe fn benchmark_storage_10kib() { + input(0); + if register_len(0) != size_of::() as u64 { + panic() + } + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + let n: u64 = u64::from_le_bytes(data); + + let mut el = [0u8; 10 << 10]; + generate_data(&mut el); + + let mut sum = 0u64; + for i in 0..n { + el[..size_of::()].copy_from_slice(&i.to_le_bytes()); + storage_write(el.len() as u64, el.as_ptr() as u64, el.len() as u64, el.as_ptr() as u64, 0); + + let result = storage_read(el.len() as u64, el.as_ptr() as u64, 0); + if result == 1 { + let el = [0u8; 10 << 10]; + read_register(0, el.as_ptr() as u64); + let mut value = [0u8; size_of::()]; + value.copy_from_slice(&el[0..size_of::()]); + sum += u64::from_le_bytes(value); + } + } + + value_return(size_of::() as u64, &sum as *const u64 as u64); +} + +/// Passes through input into output. +#[no_mangle] +pub unsafe fn pass_through() { + input(0); + if register_len(0) != size_of::() as u64 { + panic() + } + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + value_return(data.len() as u64, data.as_ptr() as u64); +} + +/// Sums numbers. +#[no_mangle] +pub unsafe fn sum_n() { + input(0); + if register_len(0) != size_of::() as u64 { + panic() + } + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + let n = u64::from_le_bytes(data); + + let mut sum = 0u64; + for i in 0..n { + // LLVM optimizes sum += i into O(1) computation, use volatile to thwart + // that. + let new_sum = std::ptr::read_volatile(&sum).wrapping_add(i); + std::ptr::write_volatile(&mut sum, new_sum); + } + + let data = sum.to_le_bytes(); + value_return(data.len() as u64, data.as_ptr() as u64); +} + +/// Calculates Fibonacci numbers in inefficient way. Used to burn gas for the +/// sanity/max_gas_burnt_view.py test. The implementation has exponential +/// complexity (1.62^n to be exact) so even small increase in argument result in +/// large increase in gas use. +#[no_mangle] +pub unsafe fn fibonacci() { + input(0); + if register_len(0) != 1 { + panic() + } + let mut n: u8 = 0; + read_register(0, &mut n as *mut u8 as u64); + let data = fib(n).to_le_bytes(); + value_return(data.len() as u64, data.as_ptr() as u64); +} + +fn fib(n: u8) -> u64 { + if n < 2 { + n as u64 + } else { + fib(n - 2) + fib(n - 1) + } +} + +#[no_mangle] +pub unsafe fn insert_strings() { + input(0); + if register_len(0) != 2 * size_of::() as u64 { + panic() + } + let data = [0u8; 2 * size_of::()]; + read_register(0, data.as_ptr() as u64); + + let mut from = [0u8; size_of::()]; + let mut to = [0u8; size_of::()]; + from.copy_from_slice(&data[..size_of::()]); + to.copy_from_slice(&data[size_of::()..]); + let from = u64::from_le_bytes(from); + let to = u64::from_le_bytes(to); + let s = vec![b'a'; to as usize]; + for i in from..to { + let mut key = s[(to - i) as usize..].to_vec(); + key.push(b'b'); + let value = b"x"; + storage_write( + key.len() as u64, + key.as_ptr() as u64, + value.len() as u64, + value.as_ptr() as u64, + 0, + ); + } +} + +#[no_mangle] +pub unsafe fn delete_strings() { + input(0); + if register_len(0) != 2 * size_of::() as u64 { + panic() + } + let data = [0u8; 2 * size_of::()]; + read_register(0, data.as_ptr() as u64); + + let mut from = [0u8; size_of::()]; + let mut to = [0u8; size_of::()]; + from.copy_from_slice(&data[..size_of::()]); + to.copy_from_slice(&data[size_of::()..]); + let from = u64::from_le_bytes(from); + let to = u64::from_le_bytes(to); + let s = vec![b'a'; to as usize]; + for i in from..to { + let mut key = s[(to - i) as usize..].to_vec(); + key.push(b'b'); + storage_remove(key.len() as u64, key.as_ptr() as u64, 0); + } +} + +#[no_mangle] +pub unsafe fn recurse() { + input(0); + if register_len(0) != size_of::() as u64 { + panic() + } + let data = [0u8; size_of::()]; + read_register(0, data.as_ptr() as u64); + let n = u64::from_le_bytes(data); + let res = internal_recurse(n); + let data = res.to_le_bytes(); + value_return(data.len() as u64, data.as_ptr() as u64); +} + +/// Rust compiler is getting smarter and starts to optimize my deep recursion. +/// We're going to fight it with a more obscure implementations. +#[no_mangle] +fn internal_recurse(n: u64) -> u64 { + if n <= 1 { + n + } else { + let a = internal_recurse(n - 1) + 1; + if a % 2 == 1 { + (a + n) / 2 + } else { + a + } + } +} + +#[no_mangle] +pub fn out_of_memory() { + let mut vec = Vec::new(); + loop { + vec.push(vec![0; 1024]); + } +} + +// Can be used for debugging +#[no_mangle] +fn log_u64(msg: u64) { + unsafe { + log_utf8(8, &msg as *const u64 as u64); + } +} + +pub fn from_base64(s: &str) -> Vec { + base64::decode(s).unwrap() +} + +#[no_mangle] +fn call_promise() { + unsafe { + input(0); + let data = vec![0u8; register_len(0) as usize]; + read_register(0, data.as_ptr() as u64); + let input_args: serde_json::Value = serde_json::from_slice(&data).unwrap(); + for arg in input_args.as_array().unwrap() { + let actual_id = if let Some(create) = arg.get("create") { + let account_id = create["account_id"].as_str().unwrap().as_bytes(); + let method_name = create["method_name"].as_str().unwrap().as_bytes(); + let arguments = serde_json::to_vec(&create["arguments"]).unwrap(); + let amount = create["amount"].as_str().unwrap().parse::().unwrap(); + let gas = create["gas"].as_i64().unwrap() as u64; + promise_create( + account_id.len() as u64, + account_id.as_ptr() as u64, + method_name.len() as u64, + method_name.as_ptr() as u64, + arguments.len() as u64, + arguments.as_ptr() as u64, + &amount as *const u128 as *const u64 as u64, + gas, + ) + } else if let Some(then) = arg.get("then") { + let promise_index = then["promise_index"].as_i64().unwrap() as u64; + let account_id = then["account_id"].as_str().unwrap().as_bytes(); + let method_name = then["method_name"].as_str().unwrap().as_bytes(); + let arguments = serde_json::to_vec(&then["arguments"]).unwrap(); + let amount = then["amount"].as_str().unwrap().parse::().unwrap(); + let gas = then["gas"].as_i64().unwrap() as u64; + promise_then( + promise_index, + account_id.len() as u64, + account_id.as_ptr() as u64, + method_name.len() as u64, + method_name.as_ptr() as u64, + arguments.len() as u64, + arguments.as_ptr() as u64, + &amount as *const u128 as *const u64 as u64, + gas, + ) + } else if let Some(and) = arg.get("and") { + let and = and.as_array().unwrap(); + let mut curr = and[0].as_i64().unwrap() as u64; + for other in &and[1..] { + curr = promise_and(curr, other.as_i64().unwrap() as u64); + } + curr + } else if let Some(batch_create) = arg.get("batch_create") { + let account_id = batch_create["account_id"].as_str().unwrap().as_bytes(); + promise_batch_create(account_id.len() as u64, account_id.as_ptr() as u64) + } else if let Some(batch_then) = arg.get("batch_then") { + let promise_index = batch_then["promise_index"].as_i64().unwrap() as u64; + let account_id = batch_then["account_id"].as_str().unwrap().as_bytes(); + promise_batch_then( + promise_index, + account_id.len() as u64, + account_id.as_ptr() as u64, + ) + } else if let Some(action) = arg.get("action_create_account") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + promise_batch_action_create_account(promise_index); + promise_index + } else if let Some(action) = arg.get("action_deploy_contract") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let code = from_base64(action["code"].as_str().unwrap()); + promise_batch_action_deploy_contract( + promise_index, + code.len() as u64, + code.as_ptr() as u64, + ); + promise_index + } else if let Some(action) = arg.get("action_function_call") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let method_name = action["method_name"].as_str().unwrap().as_bytes(); + let arguments = serde_json::to_vec(&action["arguments"]).unwrap(); + let amount = action["amount"].as_str().unwrap().parse::().unwrap(); + let gas = action["gas"].as_i64().unwrap() as u64; + promise_batch_action_function_call( + promise_index, + method_name.len() as u64, + method_name.as_ptr() as u64, + arguments.len() as u64, + arguments.as_ptr() as u64, + &amount as *const u128 as *const u64 as u64, + gas, + ); + promise_index + } else if let Some(action) = arg.get("action_transfer") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let amount = action["amount"].as_str().unwrap().parse::().unwrap(); + promise_batch_action_transfer( + promise_index, + &amount as *const u128 as *const u64 as u64, + ); + promise_index + } else if let Some(action) = arg.get("action_stake") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let amount = action["amount"].as_str().unwrap().parse::().unwrap(); + let public_key = from_base64(action["public_key"].as_str().unwrap()); + promise_batch_action_stake( + promise_index, + &amount as *const u128 as *const u64 as u64, + public_key.len() as u64, + public_key.as_ptr() as u64, + ); + promise_index + } else if let Some(action) = arg.get("action_add_key_with_full_access") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let public_key = from_base64(action["public_key"].as_str().unwrap()); + let nonce = action["nonce"].as_i64().unwrap() as u64; + promise_batch_action_add_key_with_full_access( + promise_index, + public_key.len() as u64, + public_key.as_ptr() as u64, + nonce, + ); + promise_index + } else if let Some(action) = arg.get("action_add_key_with_function_call") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let public_key = from_base64(action["public_key"].as_str().unwrap()); + let nonce = action["nonce"].as_i64().unwrap() as u64; + let allowance = action["allowance"].as_str().unwrap().parse::().unwrap(); + let receiver_id = action["receiver_id"].as_str().unwrap().as_bytes(); + let method_names = action["method_names"].as_str().unwrap().as_bytes(); + promise_batch_action_add_key_with_function_call( + promise_index, + public_key.len() as u64, + public_key.as_ptr() as u64, + nonce, + &allowance as *const u128 as *const u64 as u64, + receiver_id.len() as u64, + receiver_id.as_ptr() as u64, + method_names.len() as u64, + method_names.as_ptr() as u64, + ); + promise_index + } else if let Some(action) = arg.get("action_delete_key") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let public_key = from_base64(action["public_key"].as_str().unwrap()); + promise_batch_action_delete_key( + promise_index, + public_key.len() as u64, + public_key.as_ptr() as u64, + ); + promise_index + } else if let Some(action) = arg.get("action_delete_account") { + let promise_index = action["promise_index"].as_i64().unwrap() as u64; + let beneficiary_id = action["beneficiary_id"].as_str().unwrap().as_bytes(); + promise_batch_action_delete_account( + promise_index, + beneficiary_id.len() as u64, + beneficiary_id.as_ptr() as u64, + ); + promise_index + } else { + unimplemented!() + }; + let expected_id = arg["id"].as_i64().unwrap() as u64; + assert_eq!(actual_id, expected_id); + if let Some(ret) = arg.get("return") { + if ret.as_bool().unwrap() == true { + promise_return(actual_id); + } + } + } + } +} + +#[cfg(not(feature = "base_protocol"))] +#[no_mangle] +fn do_ripemd() { + let data = b"tesdsst"; + unsafe { + ripemd160(data.len() as _, data.as_ptr() as _, 0); + } +} diff --git a/mock-enclave/src/near-test-contracts/test-contract-ts/.gitignore b/mock-enclave/src/near-test-contracts/test-contract-ts/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-ts/.gitignore @@ -0,0 +1 @@ +build diff --git a/mock-enclave/src/near-test-contracts/test-contract-ts/README.md b/mock-enclave/src/near-test-contracts/test-contract-ts/README.md new file mode 100644 index 0000000..575f63b --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-ts/README.md @@ -0,0 +1,31 @@ +A smart contract written in AssemblyScript that can be used to make +sure near runtime is compatible with AssemblyScript smart contracts. + +# Pre-requisites + +Switch to the smart contract directory and point npm to AssemblyScript: +```bash +npm install --save-dev AssemblyScript/assemblyscript +``` + +Then install dependencies with +```bash +npm install +``` + +# Building + +Build smart contract with: +```bash +npm run asbuild:untouched +``` + +And copy the smart contract into `res` directory: +```bash +cp build/untouched.wasm ../res/test_contract_ts.wasm +``` + +Then run the Rust integration test with: +```bash +cargo test --package near-vm-runner --test test_ts_contract "" -- --nocapture +``` diff --git a/mock-enclave/src/near-test-contracts/test-contract-ts/assembly/index.ts b/mock-enclave/src/near-test-contracts/test-contract-ts/assembly/index.ts new file mode 100644 index 0000000..7849e55 --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-ts/assembly/index.ts @@ -0,0 +1,57 @@ +@external("env", "read_register") +declare function read_register(register_id: u64, ptr: u64): void; +@external("env", "register_len") +declare function register_len(register_id: u64): u64; + +@external("env", "storage_write") +declare function storage_write(key_len: u64, key_ptr: u64, value_len: u64, value_ptr: u64, register_id: u64): u64; +@external("env", "storage_read") +declare function storage_read(key_len: u64, key_ptr: u64, register_id: u64): u64; + +@external("env", "input") +declare function input(register_id: u64): void; +@external("env", "value_return") +declare function value_return(value_len: u64, value_ptr: u64): void; + +@external("env", "panic") +declare function panic(): void; + +export function try_storage_write(): void { + input(0); + let len = register_len(0); + if (len == U64.MAX_VALUE) { + panic(); + } + let buffer = new Uint8Array(len as i32); + read_register(0, buffer.buffer as u64); + let input_str = String.UTF8.decode(buffer.buffer); + let input_split = input_str.split(" "); + let key_str = input_split[0]; + let value_str = input_split[1] + + let key = String.UTF8.encode(key_str); + let value = String.UTF8.encode(value_str); + storage_write(key.byteLength, key as u64, value.byteLength, value as u64, 0); +} + +export function try_storage_read(): void { + input(0); + let key_len = register_len(0); + if (key_len == U64.MAX_VALUE) { + panic(); + } + let key = new Uint8Array(key_len as i32); + read_register(0, key.buffer as u64); + + let res = storage_read(key.buffer.byteLength, key.buffer as u64, 1); + if (res == 1) { + let value_len = register_len(1); + let value = new Uint8Array(value_len as i32); + read_register(1, value.buffer as u64); + value_return(value.buffer.byteLength, value.buffer as u64); + } +} + +export function try_panic(): void { + panic(); +} diff --git a/mock-enclave/src/near-test-contracts/test-contract-ts/assembly/tsconfig.json b/mock-enclave/src/near-test-contracts/test-contract-ts/assembly/tsconfig.json new file mode 100644 index 0000000..c614e5c --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-ts/assembly/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../node_modules/assemblyscript/std/assembly.json", + "include": [ + "./**/*.ts" + ] +} \ No newline at end of file diff --git a/mock-enclave/src/near-test-contracts/test-contract-ts/package-lock.json b/mock-enclave/src/near-test-contracts/test-contract-ts/package-lock.json new file mode 100644 index 0000000..48e341a --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-ts/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/mock-enclave/src/near-test-contracts/test-contract-ts/package.json b/mock-enclave/src/near-test-contracts/test-contract-ts/package.json new file mode 100644 index 0000000..34f562f --- /dev/null +++ b/mock-enclave/src/near-test-contracts/test-contract-ts/package.json @@ -0,0 +1,7 @@ +{ + "scripts": { + "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug", + "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize", + "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized" + } +} diff --git a/mock-enclave/src/skw-vm-engine-cli/Cargo.lock b/mock-enclave/src/skw-vm-engine-cli/Cargo.lock index d97016d..45aa419 100644 --- a/mock-enclave/src/skw-vm-engine-cli/Cargo.lock +++ b/mock-enclave/src/skw-vm-engine-cli/Cargo.lock @@ -1451,7 +1451,6 @@ dependencies = [ "sha2", "sha3", "skw-vm-primitives", - "wasmi", ] [[package]] @@ -1461,6 +1460,7 @@ dependencies = [ "num-rational 0.3.2", "serde", "sha2", + "wasmi", ] [[package]] diff --git a/mock-enclave/src/skw-vm-engine/Cargo.lock b/mock-enclave/src/skw-vm-engine/Cargo.lock index 947f3e3..52dd68e 100644 --- a/mock-enclave/src/skw-vm-engine/Cargo.lock +++ b/mock-enclave/src/skw-vm-engine/Cargo.lock @@ -849,7 +849,6 @@ dependencies = [ [[package]] name = "near-test-contracts" version = "0.0.0" -source = "git+https://github.com/near/nearcore?tag=crates-0.11.0#8d04fa95d4cb8191e636bd24517ea7744b78ec5f" dependencies = [ "once_cell", "wat", @@ -1331,7 +1330,6 @@ dependencies = [ "sha2", "sha3", "skw-vm-primitives", - "wasmi", ] [[package]] @@ -1341,6 +1339,7 @@ dependencies = [ "num-rational 0.3.2", "serde", "sha2", + "wasmi", ] [[package]] diff --git a/mock-enclave/src/skw-vm-engine/Cargo.toml b/mock-enclave/src/skw-vm-engine/Cargo.toml index bf43ea7..2c173bb 100644 --- a/mock-enclave/src/skw-vm-engine/Cargo.toml +++ b/mock-enclave/src/skw-vm-engine/Cargo.toml @@ -36,7 +36,7 @@ tracing = { version = "0.1", default-features = false } threadpool = "1.8.1" [dev-dependencies] -near-test-contracts = { git = "https://github.com/near/nearcore", tag = "crates-0.11.0" } +near-test-contracts = { path = "../near-test-contracts" } assert_matches = "1.3" wat = "1.0.40" base64 = "0.13" diff --git a/mock-enclave/src/skw-vm-engine/src/cache.rs b/mock-enclave/src/skw-vm-engine/src/cache.rs index 06a00ed..8637c2a 100644 --- a/mock-enclave/src/skw-vm-engine/src/cache.rs +++ b/mock-enclave/src/skw-vm-engine/src/cache.rs @@ -20,17 +20,6 @@ pub fn create_module_instance(contract_code: &ContractCode, config: &VMConfig) - let code_hash = contract_code.hash; MODULE_CACHE.write().unwrap().get(&code_hash); - // match get_module_instance(&code_hash) { - // Some(Ok(module_ref)) => Ok(module_ref), - // None => {} - - // // we should not ever get here - // // toxic cache - removing - // Some(Err(_)) => { - // MODULE_CACHE.write().unwrap().pop(&code_hash); - // } - // } - let mut cache = MODULE_CACHE.write().unwrap(); match cache.get(&code_hash).map(create_instance) { Some(Ok(module_ref)) => return Ok(module_ref), @@ -56,13 +45,13 @@ pub fn create_module_instance(contract_code: &ContractCode, config: &VMConfig) - result } -// pub fn get_module_instance(code_hash: &CryptoHash) -> Option> { -// MODULE_CACHE -// .read() -// .unwrap() -// .peek(code_hash) -// .map(create_instance) -// } +pub fn get_module_instance(code_hash: &CryptoHash) -> Option> { + MODULE_CACHE + .read() + .unwrap() + .peek(code_hash) + .map(create_instance) +} pub fn create_instance(module: &wasmi::Module) -> Result { let resolver = WasmiImportResolver {}; diff --git a/mock-enclave/src/skw-vm-engine/src/externals.rs b/mock-enclave/src/skw-vm-engine/src/externals.rs index 741b05f..77ee51b 100644 --- a/mock-enclave/src/skw-vm-engine/src/externals.rs +++ b/mock-enclave/src/skw-vm-engine/src/externals.rs @@ -1,5 +1,10 @@ -use wasmi::{Externals, RuntimeArgs, RuntimeValue, Trap, TrapKind}; +use wasmi::{ + Externals, RuntimeArgs, Trap, TrapKind, HostError, + RuntimeValue, +}; + use skw_vm_host::{VMLogic}; +use skw_vm_primitives::errors::{VMLogicError}; #[derive(PartialEq, Eq)] pub enum HostFunctions { @@ -121,28 +126,342 @@ impl<'a> Externals for VMHost<'a> { args: RuntimeArgs, ) -> Result, Trap> { match HostFunctions::from(index) { - HostFunctions::ReadRegister => { - let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; - let ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; - // Some(self.0.read_register(register_id, ptr).unwrap()) - Ok(None) - }, - _ => { - Ok(None) - } - // HostFunctions::RegisterLen => { - // let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; - // self.register_len(register_id)? - // }, - // HostFunctions::WriteRegister => { - // let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; - // let data_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; - // let data_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; - // self.write_register(register_id, data_len, data_ptr)? - // }, - // _ => { - // println!("BOOOOO"); - // } + HostFunctions::ReadRegister => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.read_register(register_id, ptr) + .map(|_| None) + .map_err(|e| e.into()) + }, + HostFunctions::RegisterLen => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.register_len(register_id) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::WriteRegister => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let data_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let data_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.write_register(register_id, data_len, data_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::CurrentAccountId => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.current_account_id(register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::SignerAccountId => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.signer_account_id(register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::SignerAccountPublicKey => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.signer_account_pk(register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PredecessorAccountId => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.predecessor_account_id(register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Input => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.input(register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::BlockNumber => { + self.0.block_number() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::BlockTimestamp => { + self.0.block_timestamp() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::EpochHeight => { + self.0.epoch_height() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::StorageUsage => { + self.0.storage_usage() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::AccountBalance => { + let balance_ptr: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.account_balance(balance_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::AttachedDeposit => { + let balance_ptr: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.attached_deposit(balance_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PrepaidGas => { + self.0.prepaid_gas() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::UsedGas => { + self.0.used_gas() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::RandomSeed => { + let register_id: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.random_seed(register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Sha256 => { + let value_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.sha256(value_len, value_ptr, register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Keccak256 => { + let value_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.keccak256(value_len, value_ptr, register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Keccak512 => { + let value_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.keccak512(value_len, value_ptr, register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Ripemd160 => { + let value_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.ripemd160(value_len, value_ptr, register_id) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Ecrecover => { + let hash_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let hash_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let sign_len: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + let sig_ptr: u64 = args.nth_checked(3).map_err(|_| TrapKind::UnexpectedSignature)?; + let v: u64 = args.nth_checked(4).map_err(|_| TrapKind::UnexpectedSignature)?; + let malleability_flag: u64 = args.nth_checked(5).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(6).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.ecrecover(hash_len, hash_ptr, sign_len, sig_ptr, v, malleability_flag, register_id) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::ValueReturn => { + let value_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.value_return(value_len, value_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Panic => { + self.0.panic() + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PanicUtf8 => { + let len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.panic_utf8(len, ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::LogUtf8 => { + let len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.log_utf8(len, ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::LogUtf16 => { + let len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.log_utf16(len, ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::Abort => { + let msg_ptr: u32 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let filename_ptr: u32 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let line: u32 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + let col: u32 = args.nth_checked(3).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.abort(msg_ptr, filename_ptr, line, col) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseCreate => { + let account_id_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let account_id_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let method_name_len: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + let method_name_ptr: u64 = args.nth_checked(3).map_err(|_| TrapKind::UnexpectedSignature)?; + let arguments_len: u64 = args.nth_checked(4).map_err(|_| TrapKind::UnexpectedSignature)?; + let arguments_ptr: u64 = args.nth_checked(5).map_err(|_| TrapKind::UnexpectedSignature)?; + let amount_ptr: u64 = args.nth_checked(6).map_err(|_| TrapKind::UnexpectedSignature)?; + let gas: u64 = args.nth_checked(7).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_create(account_id_len, account_id_ptr, method_name_len, method_name_ptr, arguments_len, arguments_ptr, amount_ptr, gas) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseThen => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let account_id_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let account_id_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + let method_name_len: u64 = args.nth_checked(3).map_err(|_| TrapKind::UnexpectedSignature)?; + let method_name_ptr: u64 = args.nth_checked(4).map_err(|_| TrapKind::UnexpectedSignature)?; + let arguments_len: u64 = args.nth_checked(5).map_err(|_| TrapKind::UnexpectedSignature)?; + let arguments_ptr: u64 = args.nth_checked(6).map_err(|_| TrapKind::UnexpectedSignature)?; + let amount_ptr: u64 = args.nth_checked(7).map_err(|_| TrapKind::UnexpectedSignature)?; + let gas: u64 = args.nth_checked(8).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_then(promise_index, account_id_len, account_id_ptr, method_name_len, method_name_ptr, arguments_len, arguments_ptr, amount_ptr, gas) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseAnd => { + let promise_idx_ptr: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let promise_idx_count: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_and(promise_idx_ptr, promise_idx_count) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchCreate => { + let account_id_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let account_id_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_create(account_id_len, account_id_ptr) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchThen => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let account_id_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let account_id_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_then(promise_index, account_id_len, account_id_ptr) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchActionCreateAccount => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_action_create_account(promise_index) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchActionDeployContract => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let code_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let code_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_action_deploy_contract(promise_index, code_len, code_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchActionFunctionCall => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let method_name_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let method_name_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + let arguments_len: u64 = args.nth_checked(3).map_err(|_| TrapKind::UnexpectedSignature)?; + let arguments_ptr: u64 = args.nth_checked(4).map_err(|_| TrapKind::UnexpectedSignature)?; + let amount_ptr: u64 = args.nth_checked(5).map_err(|_| TrapKind::UnexpectedSignature)?; + let gas: u64 = args.nth_checked(6).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_action_function_call(promise_index, method_name_len, method_name_ptr, arguments_len, arguments_ptr, amount_ptr, gas) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchActionTransfer => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let amount_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_action_transfer(promise_index, amount_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseBatchActionDeleteAccount => { + let promise_index: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let beneficiary_id_len: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let beneficiary_id_ptr: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_batch_action_delete_account(promise_index, beneficiary_id_len, beneficiary_id_ptr) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseResultsCount => { + self.0.promise_results_count() + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseResult => { + let result_idx: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_result(result_idx, register_id) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::PromiseReturn => { + let promise_idx: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.promise_return(promise_idx) + .map(|_| None ) + .map_err(|e| e.into()) + }, + HostFunctions::StorageWrite => { + let key_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let key_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_len: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + let value_ptr: u64 = args.nth_checked(3).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(4).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.storage_write(key_len, key_ptr, value_len, value_ptr, register_id) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::StorageRead => { + let key_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let key_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.storage_read(key_len, key_ptr, register_id) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::StorageRemove => { + let key_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let key_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + let register_id: u64 = args.nth_checked(2).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.storage_remove(key_len, key_ptr, register_id) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::StorageHasKey => { + let key_len: u64 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + let key_ptr: u64 = args.nth_checked(1).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.storage_has_key(key_len, key_ptr) + .map(|ret| Some(ret.into()) ) + .map_err(|e| e.into()) + }, + HostFunctions::Gas => { + let gas_amount: u32 = args.nth_checked(0).map_err(|_| TrapKind::UnexpectedSignature)?; + self.0.gas(gas_amount) + .map(|_| None ) + .map_err(|e| e.into()) + }, + + _ => { + Err(Trap::new(TrapKind::Unreachable)) + } } } } diff --git a/mock-enclave/src/skw-vm-host/Cargo.toml b/mock-enclave/src/skw-vm-host/Cargo.toml index 696fb00..76c1220 100644 --- a/mock-enclave/src/skw-vm-host/Cargo.toml +++ b/mock-enclave/src/skw-vm-host/Cargo.toml @@ -25,7 +25,6 @@ parity-secp256k1 = "0.7" near-crypto = { git = "https://github.com/near/nearcore" } skw-vm-primitives = { path = "../skw-vm-primitives" } -wasmi = "0.10.0" bn = { package = "zeropool-bn", version = "0.5.9", features = [], optional = true } diff --git a/mock-enclave/src/skw-vm-primitives/Cargo.toml b/mock-enclave/src/skw-vm-primitives/Cargo.toml index cbee7ef..400f8ff 100644 --- a/mock-enclave/src/skw-vm-primitives/Cargo.toml +++ b/mock-enclave/src/skw-vm-primitives/Cargo.toml @@ -16,6 +16,7 @@ Primitives types for the SkyeKiwi Network Secret Contracts sha2 = "0.9" serde = { version = "1", optional = true } num-rational = { version = "0.3.1", default-features = false } +wasmi = "0.10.0" [features] default = ["std"] diff --git a/mock-enclave/src/skw-vm-primitives/src/errors.rs b/mock-enclave/src/skw-vm-primitives/src/errors.rs index b6a06b0..cddc0ec 100644 --- a/mock-enclave/src/skw-vm-primitives/src/errors.rs +++ b/mock-enclave/src/skw-vm-primitives/src/errors.rs @@ -223,6 +223,8 @@ pub enum VMLogicError { InconsistentStateError(InconsistentStateError), } +impl wasmi::HostError for VMLogicError {} + /// An error which can be returned when parsing a NEAR Account ID. #[derive(Eq, Clone, Debug, PartialEq)] pub struct ParseAccountError {