diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index 28f6fbfc8e2..82755e0768a 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -67,7 +67,7 @@ jobs: tags: ${{ needs.prepare.outputs.image_name }} - name: SSH into VM - uses: appleboy/ssh-action@v1.0.3 + uses: appleboy/ssh-action@v1.1.0 env: NEW_IMAGE: ${{ needs.prepare.outputs.image_name }} with: diff --git a/Cargo.lock b/Cargo.lock index 5f080df16e4..2ec6039cf82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -440,7 +440,7 @@ dependencies = [ "futures-utils-wasm", "lru 0.12.3", "pin-project", - "reqwest 0.12.4", + "reqwest", "serde", "serde_json", "thiserror", @@ -504,7 +504,7 @@ dependencies = [ "alloy-transport-ws", "futures", "pin-project", - "reqwest 0.12.4", + "reqwest", "serde", "serde_json", "tokio", @@ -730,7 +730,7 @@ checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.4", + "reqwest", "serde_json", "tower 0.5.1", "tracing", @@ -750,7 +750,7 @@ dependencies = [ "rustls 0.23.10", "serde_json", "tokio", - "tokio-tungstenite 0.24.0", + "tokio-tungstenite", "tracing", "ws_stream_wasm", ] @@ -1265,15 +1265,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - [[package]] name = "asn1-rs" version = "0.5.2" @@ -1619,6 +1610,17 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" +[[package]] +name = "atomic_enum" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "attohttpc" version = "0.24.1" @@ -1738,12 +1740,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "beef" version = "0.5.2" @@ -2045,7 +2041,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "sha2 0.10.8", "tinyvec", ] @@ -2144,16 +2139,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - [[package]] name = "bzip2-sys" version = "0.1.11+1.0.8" @@ -2577,58 +2562,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58 0.5.1", - "coins-core", - "digest 0.10.7", - "hmac 0.12.1", - "k256", - "serde", - "sha2 0.10.8", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" -dependencies = [ - "bitvec", - "coins-bip32", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.12.2", - "rand 0.8.5", - "sha2 0.10.8", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" -dependencies = [ - "base64 0.21.7", - "bech32", - "bs58 0.5.1", - "digest 0.10.7", - "generic-array 0.14.7", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2 0.10.8", - "sha3", - "thiserror", -] - [[package]] name = "color-eyre" version = "0.6.3" @@ -2988,7 +2921,7 @@ dependencies = [ "cargo-http-registry", "cargo_metadata 0.18.1", "clap 4.5.9", - "reqwest 0.11.27", + "reqwest", "serde", "tempfile", "tokio", @@ -4213,25 +4146,6 @@ dependencies = [ "dirs-sys 0.3.7", ] -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.3.7" @@ -4506,48 +4420,12 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enr" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" -dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256", - "log", - "rand 0.8.5", - "rlp", - "serde", - "sha3", - "zeroize", -] - [[package]] name = "enum-as-inner" version = "0.5.1" @@ -4669,370 +4547,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ "darling 0.20.10", - "proc-macro2", - "quote", - "syn 2.0.71", -] - -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "environmental" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "etc" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b241177c7107d9829286c2ffdc5eee98d992d6356f3515e7f412f988b1a72fd" - -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes 0.8.4", - "ctr 0.9.2", - "digest 0.10.7", - "hex", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "rand 0.8.5", - "scrypt", - "serde", - "serde_json", - "sha2 0.10.8", - "sha3", - "thiserror", - "uuid 0.8.2", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" -dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", - "ethers-solc", -] - -[[package]] -name = "ethers-addressbook" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "ethers-etherscan", - "eyre", - "prettyplease 0.2.15", - "proc-macro2", - "quote", - "regex", - "reqwest 0.11.27", - "serde", - "serde_json", - "syn 2.0.71", - "toml 0.8.14", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.71", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec 0.7.4", - "bytes", - "cargo_metadata 0.18.1", - "chrono", - "const-hex", - "elliptic-curve", - "ethabi", - "generic-array 0.14.7", - "k256", - "num_enum 0.7.2", - "once_cell", - "open-fastrlp", - "rand 0.8.5", - "rlp", - "serde", - "serde_json", - "strum 0.26.2", - "syn 2.0.71", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-etherscan" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" -dependencies = [ - "chrono", - "ethers-core", - "reqwest 0.11.27", - "semver 1.0.18", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" -dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", -] - -[[package]] -name = "ethers-providers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.9", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite 0.20.1", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", + "proc-macro2", + "quote", + "syn 2.0.71", ] [[package]] -name = "ethers-signers" -version = "2.0.14" +name = "env_logger" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "const-hex", - "elliptic-curve", - "eth-keystore", - "ethers-core", - "rand 0.8.5", - "sha2 0.10.8", - "thiserror", - "tracing", + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", ] [[package]] -name = "ethers-solc" -version = "2.0.14" +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "cfg-if", - "const-hex", - "dirs 5.0.1", - "dunce", - "ethers-core", - "glob 0.3.1", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver 1.0.18", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi", + "libc", + "windows-sys 0.52.0", ] +[[package]] +name = "etc" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b241177c7107d9829286c2ffdc5eee98d992d6356f3515e7f412f988b1a72fd" + [[package]] name = "ethexe-cli" version = "1.6.2" @@ -5167,7 +4727,7 @@ dependencies = [ "gprimitives", "log", "parity-scale-codec", - "reqwest 0.11.27", + "reqwest", "tokio", "wabt", ] @@ -5286,9 +4846,9 @@ dependencies = [ name = "ethexe-signer" version = "1.6.2" dependencies = [ + "alloy", "anyhow", "derive_more 0.99.18", - "ethers", "ethexe-common", "gprimitives", "hex", @@ -6085,16 +5645,6 @@ dependencies = [ "pin-project-lite 0.2.13", ] -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - [[package]] name = "futures-macro" version = "0.3.30" @@ -6156,10 +5706,6 @@ name = "futures-timer" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" -dependencies = [ - "gloo-timers", - "send_wrapper 0.4.0", -] [[package]] name = "futures-util" @@ -6253,7 +5799,7 @@ dependencies = [ "demo-messenger", "demo-new-meta", "demo-waiter", - "dirs 4.0.0", + "dirs", "env_logger", "etc", "gclient", @@ -6269,7 +5815,7 @@ dependencies = [ "keyring", "log", "rand 0.8.5", - "reqwest 0.11.27", + "reqwest", "scale-info", "serde", "thiserror", @@ -6420,6 +5966,7 @@ name = "gear-cli" version = "1.6.2" dependencies = [ "clap 4.5.9", + "derive_more 0.99.18", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -6653,7 +6200,7 @@ dependencies = [ "parking_lot 0.12.3", "primitive-types", "rand 0.8.5", - "reqwest 0.11.27", + "reqwest", "subxt", "thiserror", "tokio", @@ -6842,19 +6389,21 @@ dependencies = [ name = "gear-sandbox-host" version = "1.6.2" dependencies = [ + "atomic_enum", "defer", "environmental", "gear-sandbox-env", "gear-wasmer-cache", "log", "parity-scale-codec", + "region", "sp-allocator", "sp-wasm-interface-common", "tempfile", "thiserror", "wasmer", "wasmer-types", - "wasmi 0.13.2", + "wasmi 0.38.0", ] [[package]] @@ -7278,18 +6827,6 @@ dependencies = [ "regex", ] -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "gmeta" version = "1.6.2" @@ -7338,7 +6875,7 @@ dependencies = [ "base64 0.21.7", "clap 4.5.9", "colored", - "dirs 4.0.0", + "dirs", "gear-ss58", "hex", "nacl", @@ -7616,15 +7153,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - [[package]] name = "hashlink" version = "0.8.4" @@ -8002,16 +7530,21 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ - "bytes", - "hyper 0.14.27", - "native-tls", + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.10", + "rustls-pki-types", "tokio", - "tokio-native-tls", + "tokio-rustls 0.26.0", + "tower-service", + "webpki-roots 0.26.3", ] [[package]] @@ -8173,15 +7706,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - [[package]] name = "impl-serde" version = "0.4.0" @@ -8321,7 +7845,7 @@ dependencies = [ "socket2 0.5.7", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -8350,15 +7874,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -8662,7 +8177,7 @@ checksum = "7e5f9fabdd5d79344728521bb65e3106b49ec405a78b66fbff073b72b389fa43" dependencies = [ "async-trait", "hyper 0.14.27", - "hyper-rustls", + "hyper-rustls 0.24.1", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", "rustc-hash 1.1.0", @@ -8681,7 +8196,7 @@ checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", "hyper 0.14.27", - "hyper-rustls", + "hyper-rustls 0.24.1", "jsonrpsee-core 0.22.5", "jsonrpsee-types 0.22.5", "serde", @@ -8845,20 +8360,6 @@ dependencies = [ "url", ] -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem 1.1.1", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "junit-common" version = "0.1.0" @@ -8877,7 +8378,6 @@ dependencies = [ "elliptic-curve", "once_cell", "sha2 0.10.8", - "signature", ] [[package]] @@ -8950,34 +8450,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "lalrpop" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" -dependencies = [ - "ascii-canvas", - "bit-set", - "diff", - "ena", - "is-terminal", - "itertools 0.10.5", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax 0.7.5", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" - [[package]] name = "lazy-pages-fuzzer" version = "0.1.0" @@ -8992,7 +8464,7 @@ dependencies = [ "log", "region", "wasmer", - "wasmi 0.13.2", + "wasmi 0.38.0", "wasmprinter", "wat", ] @@ -10245,16 +9717,6 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest 0.10.7", -] - [[package]] name = "memchr" version = "2.7.2" @@ -10472,6 +9934,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" +[[package]] +name = "multi-stash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f" + [[package]] name = "multiaddr" version = "0.17.1" @@ -10743,12 +10211,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nix" version = "0.22.3" @@ -11007,7 +10469,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 2.0.71", @@ -11089,31 +10550,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec 0.7.4", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "openssl" version = "0.10.60" @@ -12473,17 +11909,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle 2.6.1", -] - [[package]] name = "paste" version = "1.0.15" @@ -12496,12 +11921,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - [[package]] name = "pathdiff" version = "0.2.1" @@ -12517,18 +11936,6 @@ dependencies = [ "crypto-mac 0.11.0", ] -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", - "password-hash", - "sha2 0.10.8", -] - [[package]] name = "pbkdf2" version = "0.12.2" @@ -12536,7 +11943,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", - "hmac 0.12.1", ] [[package]] @@ -12634,57 +12040,6 @@ dependencies = [ "rustc_version 0.4.0", ] -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.71", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher 0.3.11", -] - [[package]] name = "pin-project" version = "1.1.5" @@ -12881,12 +12236,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "predicates" version = "2.1.5" @@ -12955,7 +12304,6 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "impl-rlp", "impl-serde", "scale-info", "uint", @@ -13632,13 +12980,7 @@ dependencies = [ name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" @@ -13685,63 +13027,21 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.21", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper-rustls", - "hyper-tls 0.5.0", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite 0.2.13", - "rustls 0.21.7", - "rustls-pemfile 1.0.3", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.2", - "winreg 0.50.0", -] - -[[package]] -name = "reqwest" -version = "0.12.4" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", + "futures-channel", "futures-core", "futures-util", "http 1.1.0", "http-body 1.0.0", "http-body-util", "hyper 1.4.1", - "hyper-tls 0.6.0", + "hyper-rustls 0.27.3", + "hyper-tls", "hyper-util", "ipnet", "js-sys", @@ -13751,19 +13051,24 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite 0.2.13", + "quinn", + "rustls 0.23.10", "rustls-pemfile 2.1.2", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tokio-native-tls", + "tokio-rustls 0.26.0", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.52.0", + "webpki-roots 0.26.3", + "windows-registry", ] [[package]] @@ -13833,15 +13138,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "rkyv" version = "0.7.42" @@ -13857,7 +13153,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid 1.4.1", + "uuid", ] [[package]] @@ -13878,21 +13174,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", - "rlp-derive", "rustc-hex", ] -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rocksdb" version = "0.21.0" @@ -14340,15 +13624,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher 0.4.4", -] - [[package]] name = "same-file" version = "1.0.6" @@ -14997,7 +14272,7 @@ dependencies = [ "futures", "futures-timer", "hyper 0.14.27", - "hyper-rustls", + "hyper-rustls 0.24.1", "libp2p 0.51.4", "log", "num_cpus", @@ -15527,9 +14802,9 @@ dependencies = [ [[package]] name = "schnellru" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" dependencies = [ "ahash 0.8.11", "cfg-if", @@ -15591,18 +14866,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac 0.12.1", - "pbkdf2 0.11.0", - "salsa20", - "sha2 0.10.8", -] - [[package]] name = "sct" version = "0.7.0" @@ -15772,12 +15035,6 @@ dependencies = [ "pest", ] -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - [[package]] name = "send_wrapper" version = "0.6.0" @@ -16085,18 +15342,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - [[package]] name = "siphasher" version = "0.3.11" @@ -16314,20 +15559,6 @@ dependencies = [ "sha1", ] -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror", - "unicode-xid", -] - [[package]] name = "sp-allocator" version = "4.1.0-dev" @@ -17329,16 +16560,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e75b72ee54e2f93c3ea1354066162be893ee5e25773ab743de3e088cecbb4f31" [[package]] -name = "string_cache" -version = "0.8.7" +name = "string-interner" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e" dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.3", - "phf_shared 0.10.0", - "precomputed-hash", + "cfg-if", + "hashbrown 0.14.5", + "serde", ] [[package]] @@ -17710,26 +16939,6 @@ dependencies = [ "sp-crypto-hashing", ] -[[package]] -name = "svm-rs" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" -dependencies = [ - "dirs 5.0.1", - "fs2", - "hex", - "once_cell", - "reqwest 0.11.27", - "semver 1.0.18", - "serde", - "serde_json", - "sha2 0.10.8", - "thiserror", - "url", - "zip", -] - [[package]] name = "syn" version = "1.0.109" @@ -17770,6 +16979,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -17874,17 +17092,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - [[package]] name = "termcolor" version = "1.2.0" @@ -18152,21 +17359,6 @@ dependencies = [ "tokio-stream", ] -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.7", - "tokio", - "tokio-rustls 0.24.1", - "tungstenite 0.20.1", - "webpki-roots 0.25.2", -] - [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -18179,7 +17371,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", - "tungstenite 0.24.0", + "tungstenite", "webpki-roots 0.26.3", ] @@ -18306,7 +17498,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite 0.2.13", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower-layer", "tower-service", ] @@ -18613,26 +17805,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.9", - "httparse", - "log", - "rand 0.8.5", - "rustls 0.21.7", - "sha1", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.24.0" @@ -18832,16 +18004,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.15", - "serde", -] - [[package]] name = "uuid" version = "1.4.1" @@ -19474,6 +18636,22 @@ dependencies = [ "wasmparser-nostd", ] +[[package]] +name = "wasmi" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07e84e3bcdab2f4301827623260ada2557596ca462f7470b60f5182a25270b1" +dependencies = [ + "arrayvec 0.7.4", + "multi-stash", + "smallvec", + "spin 0.9.8", + "wasmi_collections", + "wasmi_core 0.38.0", + "wasmi_ir", + "wasmparser-nostd", +] + [[package]] name = "wasmi-validation" version = "0.5.0" @@ -19488,6 +18666,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" +[[package]] +name = "wasmi_collections" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0fd5f4f2c4fe0c98554bb7293108ed2b1d0c124dce0974f999de7d517d37bc" +dependencies = [ + "ahash 0.8.11", + "hashbrown 0.14.5", + "string-interner", +] + [[package]] name = "wasmi_core" version = "0.2.1" @@ -19513,6 +18702,27 @@ dependencies = [ "paste", ] +[[package]] +name = "wasmi_core" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5f7bbd933a0fb3bac6c541f8bd90c0c8adcd91bb3ac088a2088995325b3d9" +dependencies = [ + "downcast-rs", + "libm", + "num-traits", + "paste", +] + +[[package]] +name = "wasmi_ir" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3345445247388df2b5b35250a30c9209c27c8d2c6db1bf4c89b65636264bf9" +dependencies = [ + "wasmi_core 0.38.0", +] + [[package]] name = "wasmparser" version = "0.102.0" @@ -20029,6 +19239,36 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.33.0" @@ -20314,16 +19554,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wit-parser" version = "0.6.4" @@ -20351,7 +19581,7 @@ dependencies = [ "log", "pharos", "rustc_version 0.4.0", - "send_wrapper 0.6.0", + "send_wrapper", "thiserror", "wasm-bindgen", "wasm-bindgen-futures", @@ -20598,26 +19828,6 @@ dependencies = [ "syn 2.0.71", ] -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes 0.8.4", - "byteorder", - "bzip2", - "constant_time_eq 0.1.5", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd 0.11.2+zstd.1.5.2", -] - [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index d8ed67f243c..564b668f00b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -162,7 +162,7 @@ rand = { version = "0.8", default-features = false } rayon = "1.10" regex = "^1.9" region = "3.0.2" -reqwest = { version = "0.11.27", default-features = false } +reqwest = { version = "0.12.8", default-features = false } scale-info = { version = "2.5.0", default-features = false } serde = { version = "^1", default-features = false } serde_json = "^1" @@ -308,9 +308,7 @@ ethexe-rpc = { path = "ethexe/rpc", default-features = false } ethexe-common = { path = "ethexe/common" } # Common executor between `sandbox-host` and `lazy-pages-fuzzer` -sandbox-wasmi = { package = "wasmi", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", features = [ - "virtual_memory", -] } +wasmi = { package = "wasmi", version = "0.38"} # Substrate deps binary-merkle-tree = { version = "4.0.0-dev", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-v1.4.0", default-features = false } @@ -503,6 +501,7 @@ demo-wat = { path = "examples/wat" } # # TODO: remove these dependencies (from this file?) or add more docs. +atomic_enum = "0.3.0" cfg-if = "1.0.0" # gear-lazy-pages cargo-http-registry = "0.1.6" # crates-io errno = "0.3" # gear-lazy-pages diff --git a/ethexe/cli/src/tests.rs b/ethexe/cli/src/tests.rs index 9146bd20a3f..f2fc1ecaf86 100644 --- a/ethexe/cli/src/tests.rs +++ b/ethexe/cli/src/tests.rs @@ -828,8 +828,7 @@ mod utils { (rpc_url, None) } Err(_) => { - let mut anvil = Anvil::new().try_spawn().unwrap(); - drop(anvil.child_mut().stdout.take()); //temp fix for alloy#1078 + let anvil = Anvil::new().try_spawn().unwrap(); log::info!("📍 Anvil started at {}", anvil.ws_endpoint()); (anvil.ws_endpoint(), Some(anvil)) } diff --git a/ethexe/signer/Cargo.toml b/ethexe/signer/Cargo.toml index a1559d5262d..4c4fbdb4681 100644 --- a/ethexe/signer/Cargo.toml +++ b/ethexe/signer/Cargo.toml @@ -20,7 +20,7 @@ derive_more.workspace = true tempfile.workspace = true secp256k1 = { version = "0.30", features = ["rand", "global-context", "hashes", "recovery"] } -sha3 = { version = "0.10.0", default-features = false } +sha3 = { version = "0.10", default-features = false } [dev-dependencies] -ethers = "2" +alloy.workspace = true diff --git a/ethexe/signer/src/lib.rs b/ethexe/signer/src/lib.rs index 6b8778e652d..973b153d668 100644 --- a/ethexe/signer/src/lib.rs +++ b/ethexe/signer/src/lib.rs @@ -290,11 +290,9 @@ impl Signer { #[cfg(test)] mod tests { - use std::env::temp_dir; - use super::*; - - use ethers::utils::keccak256; + use alloy::primitives::{keccak256, Signature}; + use std::env::temp_dir; #[test] fn test_signer_with_known_vectors() { @@ -323,10 +321,11 @@ mod tests { let hash = keccak256(message); // Recover the address using the signature - let ethers_sig = ethers::core::types::Signature::try_from(signature.as_ref()) - .expect("failed to parse sig"); + let alloy_sig = Signature::try_from(signature.as_ref()).expect("failed to parse sig"); - let recovered_address = ethers_sig.recover(hash).expect("Failed to recover address"); + let recovered_address = alloy_sig + .recover_address_from_prehash(&hash) + .expect("Failed to recover address"); // Verify the recovered address matches the expected address assert_eq!( @@ -360,11 +359,11 @@ mod tests { let hash = keccak256(message); // Recover the address using the signature - // TODO: remove the deprecated ethers crate in favor of alloy #4197 - let ethers_sig = ethers::core::types::Signature::try_from(signature.as_ref()) - .expect("failed to parse sig"); + let alloy_sig = Signature::try_from(signature.as_ref()).expect("failed to parse sig"); - let recovered_address = ethers_sig.recover(hash).expect("Failed to recover address"); + let recovered_address = alloy_sig + .recover_address_from_prehash(&hash) + .expect("Failed to recover address"); // Verify the recovered address matches the expected address assert_eq!( @@ -404,7 +403,7 @@ mod tests { .sign(public_key, message) .expect("Failed to sign message"); - let hash = keccak256(message); + let hash = keccak256(message).0; let recovered_public_key = signature .recover_from_digest(hash.into()) diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 3de1a1494d6..4fc0a0f4ce0 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -23,6 +23,7 @@ clap = { workspace = true, features = ["derive"] } mimalloc = { workspace = true, default-features = false } log = { workspace = true, features = ["std"] } futures.workspace = true +derive_more.workspace = true # Gear runtime-primitives.workspace = true diff --git a/node/cli/src/cli.rs b/node/cli/src/cli.rs index e5af588fc9c..0f1b0f40fba 100644 --- a/node/cli/src/cli.rs +++ b/node/cli/src/cli.rs @@ -17,6 +17,29 @@ // along with this program. If not, see . use clap::Parser; +use std::str::FromStr; + +#[allow(missing_docs)] +#[derive(Debug, Clone, Parser, derive_more::Display)] +pub enum SandboxBackend { + #[display(fmt = "wasmer")] + Wasmer, + #[display(fmt = "wasmi")] + Wasmi, +} + +// TODO: use `derive_more::FromStr` when derive_more dependency is updated to 1.0 +impl FromStr for SandboxBackend { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "wasmer" => Ok(SandboxBackend::Wasmer), + "wasmi" => Ok(SandboxBackend::Wasmi), + _ => Err(format!("Unknown sandbox executor: {}", s)), + } + } +} #[allow(missing_docs)] #[derive(Debug, Parser)] @@ -26,6 +49,10 @@ pub struct RunCmd { #[command(flatten)] pub base: sc_cli::RunCmd, + /// The Wasm host executor to use in program sandbox. + #[arg(long, default_value_t = SandboxBackend::Wasmer)] + pub sandbox_backend: SandboxBackend, + /// The upper limit for the amount of gas a validator can burn in one block. #[arg(long)] pub max_gas: Option, diff --git a/node/cli/src/command.rs b/node/cli/src/command.rs index 3b1e57182cc..19eb0d854a7 100644 --- a/node/cli/src/command.rs +++ b/node/cli/src/command.rs @@ -16,7 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::cli::{Cli, Subcommand}; +use crate::{ + cli::{Cli, Subcommand}, + SandboxBackend, +}; use runtime_primitives::Block; use sc_cli::{ChainSpec, SubstrateCli}; use sc_service::config::BasePath; @@ -130,6 +133,11 @@ macro_rules! unwrap_client { pub fn run() -> sc_cli::Result<()> { let cli = Cli::from_args(); + gear_runtime_interface::sandbox_init(match cli.run.sandbox_backend { + SandboxBackend::Wasmer => gear_runtime_interface::SandboxBackend::Wasmer, + SandboxBackend::Wasmi => gear_runtime_interface::SandboxBackend::Wasmi, + }); + let old_base = BasePath::from_project("", "", "gear-node"); let new_base = BasePath::from_project("", "", &Cli::executable_name()); if old_base.path().exists() && !new_base.path().exists() { diff --git a/pallets/gear-builtin/src/bls12_381.rs b/pallets/gear-builtin/src/bls12_381.rs index c1ed6aa4638..2d11c18f46a 100644 --- a/pallets/gear-builtin/src/bls12_381.rs +++ b/pallets/gear-builtin/src/bls12_381.rs @@ -30,9 +30,10 @@ const IS_VALIDATED: Validate = ark_scale::is_validated(HOST_CALL); pub struct Actor(PhantomData); impl BuiltinActor for Actor { - type Error = BuiltinActorError; - - fn handle(dispatch: &StoredDispatch, gas_limit: u64) -> (Result, u64) { + fn handle( + dispatch: &StoredDispatch, + gas_limit: u64, + ) -> (Result, u64) { let message = dispatch.message(); let payload = message.payload_bytes(); let (result, gas_spent) = match payload.first().copied() { diff --git a/pallets/gear-builtin/src/lib.rs b/pallets/gear-builtin/src/lib.rs index 4109567c7ad..9e2fc0c61f3 100644 --- a/pallets/gear-builtin/src/lib.rs +++ b/pallets/gear-builtin/src/lib.rs @@ -79,6 +79,8 @@ type CallOf = ::RuntimeCall; const LOG_TARGET: &str = "gear::builtin"; +pub type ActorErrorHandleFn = HandleFn; + /// Built-in actor error type #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, derive_more::Display)] pub enum BuiltinActorError { @@ -113,10 +115,11 @@ impl From for ActorExecutionErrorReplyReason { /// A trait representing an interface of a builtin actor that can handle a message /// from message queue (a `StoredDispatch`) to produce an outcome and gas spent. pub trait BuiltinActor { - type Error; - /// Handles a message and returns a result and the actual gas spent. - fn handle(dispatch: &StoredDispatch, gas_limit: u64) -> (Result, u64); + fn handle( + dispatch: &StoredDispatch, + gas_limit: u64, + ) -> (Result, u64); } /// A marker struct to associate a builtin actor with its unique ID. @@ -125,33 +128,29 @@ pub struct ActorWithId(PhantomData); /// Glue trait to implement `BuiltinCollection` for a tuple of `ActorWithId`. trait BuiltinActorWithId { const ID: u64; - - type Error; - type Actor: BuiltinActor; + type Actor: BuiltinActor; } impl BuiltinActorWithId for ActorWithId { const ID: u64 = ID; - - type Error = A::Error; type Actor = A; } /// A trait defining a method to convert a tuple of `BuiltinActor` types into /// a in-memory collection of builtin actors. -pub trait BuiltinCollection { +pub trait BuiltinCollection { fn collect( - registry: &mut BTreeMap>>, + registry: &mut BTreeMap>, id_converter: &dyn Fn(u64) -> ProgramId, ); } // Assuming as many as 16 builtin actors for the meantime #[impl_for_tuples(16)] -#[tuple_types_custom_trait_bound(BuiltinActorWithId + 'static)] -impl BuiltinCollection for Tuple { +#[tuple_types_custom_trait_bound(BuiltinActorWithId + 'static)] +impl BuiltinCollection for Tuple { fn collect( - registry: &mut BTreeMap>>, + registry: &mut BTreeMap>, id_converter: &dyn Fn(u64) -> ProgramId, ) { for_tuples!( @@ -199,7 +198,7 @@ pub mod pallet { + GetDispatchInfo; /// The builtin actor type. - type Builtins: BuiltinCollection; + type Builtins: BuiltinCollection; /// Weight cost incurred by builtin actors calls. type WeightInfo: WeightInfo; @@ -261,6 +260,7 @@ pub mod pallet { impl BuiltinDispatcherFactory for Pallet { type Error = BuiltinActorError; + type Output = BuiltinRegistry; fn create() -> (BuiltinRegistry, u64) { @@ -272,7 +272,7 @@ impl BuiltinDispatcherFactory for Pallet { } pub struct BuiltinRegistry { - pub registry: BTreeMap>>, + pub registry: BTreeMap>, pub _phantom: sp_std::marker::PhantomData, } impl BuiltinRegistry { @@ -290,13 +290,13 @@ impl BuiltinRegistry { impl BuiltinDispatcher for BuiltinRegistry { type Error = BuiltinActorError; - fn lookup<'a>(&'a self, id: &ProgramId) -> Option<&'a HandleFn> { + fn lookup<'a>(&'a self, id: &ProgramId) -> Option<&'a ActorErrorHandleFn> { self.registry.get(id).map(|f| &**f) } fn run( &self, - f: &HandleFn, + f: &ActorErrorHandleFn, dispatch: StoredDispatch, gas_limit: u64, ) -> Vec { diff --git a/pallets/gear-builtin/src/mock.rs b/pallets/gear-builtin/src/mock.rs index 77d22b0809b..0b585917290 100644 --- a/pallets/gear-builtin/src/mock.rs +++ b/pallets/gear-builtin/src/mock.rs @@ -229,8 +229,6 @@ pallet_gear::impl_config!( // A builtin actor who always returns success (even if not enough gas is provided). pub struct SuccessBuiltinActor {} impl BuiltinActor for SuccessBuiltinActor { - type Error = BuiltinActorError; - fn handle( dispatch: &StoredDispatch, _gas_limit: u64, @@ -256,8 +254,6 @@ impl BuiltinActor for SuccessBuiltinActor { // A builtin actor that always returns an error. pub struct ErrorBuiltinActor {} impl BuiltinActor for ErrorBuiltinActor { - type Error = BuiltinActorError; - fn handle( dispatch: &StoredDispatch, _gas_limit: u64, @@ -279,8 +275,6 @@ impl BuiltinActor for ErrorBuiltinActor { // An honest bulitin actor that actually checks whether the gas is sufficient. pub struct HonestBuiltinActor {} impl BuiltinActor for HonestBuiltinActor { - type Error = BuiltinActorError; - fn handle( dispatch: &StoredDispatch, gas_limit: u64, diff --git a/pallets/gear-builtin/src/proxy.rs b/pallets/gear-builtin/src/proxy.rs index 0a68ca2c5c2..06beaa17a01 100644 --- a/pallets/gear-builtin/src/proxy.rs +++ b/pallets/gear-builtin/src/proxy.rs @@ -75,9 +75,10 @@ where ::ProxyType: From, CallOf: From>, { - type Error = BuiltinActorError; - - fn handle(dispatch: &StoredDispatch, gas_limit: u64) -> (Result, u64) { + fn handle( + dispatch: &StoredDispatch, + gas_limit: u64, + ) -> (Result, u64) { let Ok(request) = Request::decode(&mut dispatch.payload_bytes()) else { return (Err(BuiltinActorError::DecodingError), 0); }; diff --git a/pallets/gear-builtin/src/staking.rs b/pallets/gear-builtin/src/staking.rs index a5a24370cd5..913640203da 100644 --- a/pallets/gear-builtin/src/staking.rs +++ b/pallets/gear-builtin/src/staking.rs @@ -104,9 +104,10 @@ where T::AccountId: Origin, CallOf: From>, { - type Error = BuiltinActorError; - - fn handle(dispatch: &StoredDispatch, gas_limit: u64) -> (Result, u64) { + fn handle( + dispatch: &StoredDispatch, + gas_limit: u64, + ) -> (Result, u64) { let message = dispatch.message(); let origin = dispatch.source(); let mut payload = message.payload_bytes(); diff --git a/pallets/gear-builtin/src/tests/bad_builtin_ids.rs b/pallets/gear-builtin/src/tests/bad_builtin_ids.rs index bef2567d7d2..37dd5e42d69 100644 --- a/pallets/gear-builtin/src/tests/bad_builtin_ids.rs +++ b/pallets/gear-builtin/src/tests/bad_builtin_ids.rs @@ -99,8 +99,6 @@ pallet_gear::impl_config!( pub struct SomeBuiltinActor {} impl BuiltinActor for SomeBuiltinActor { - type Error = BuiltinActorError; - fn handle( _dispatch: &StoredDispatch, _gas_limit: u64, diff --git a/pallets/gear-eth-bridge/src/builtin.rs b/pallets/gear-eth-bridge/src/builtin.rs index 68223d976d0..32c887fe407 100644 --- a/pallets/gear-eth-bridge/src/builtin.rs +++ b/pallets/gear-eth-bridge/src/builtin.rs @@ -39,9 +39,10 @@ impl BuiltinActor for Actor where T::AccountId: Origin, { - type Error = BuiltinActorError; - - fn handle(dispatch: &StoredDispatch, gas_limit: u64) -> (Result, u64) { + fn handle( + dispatch: &StoredDispatch, + gas_limit: u64, + ) -> (Result, u64) { if !dispatch.value().is_zero() { return ( Err(BuiltinActorError::Custom(LimitedStr::from_small_str( diff --git a/runtime-interface/sandbox/src/detail.rs b/runtime-interface/sandbox/src/detail.rs index 647b0b76d1e..28ac3f1127a 100644 --- a/runtime-interface/sandbox/src/detail.rs +++ b/runtime-interface/sandbox/src/detail.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use core::cell::RefCell; +use core::{cell::RefCell, sync::atomic::Ordering}; use codec::{Decode, Encode}; use gear_sandbox_host::sandbox::{self as sandbox_env, env::Instantiate}; @@ -32,10 +32,10 @@ struct Sandboxes { } impl Sandboxes { - pub fn new() -> Self { + pub fn new(sandbox_backend: sandbox_env::SandboxBackend) -> Self { Self { store_data_key: 0, - store: sandbox_env::SandboxComponents::new(sandbox_env::SandboxBackend::Wasmer), + store: sandbox_env::SandboxComponents::new(sandbox_backend), } } @@ -61,8 +61,21 @@ impl Sandboxes { } } +// Global sandbox backend type selector +static SANDBOX_BACKEND_TYPE: sandbox_env::AtomicSandboxBackend = + sandbox_env::AtomicSandboxBackend::new(sandbox_env::SandboxBackend::Wasmer); + thread_local! { - static SANDBOXES: RefCell = RefCell::new(Sandboxes::new()); + static SANDBOXES: RefCell = { + let sandbox_backend = SANDBOX_BACKEND_TYPE.load(Ordering::SeqCst); + RefCell::new(Sandboxes::new(sandbox_backend)) + } +} + +/// Sets the global sandbox backend type. +/// Buy default, it's set to `Wasmer`, so in case of `Wasmer` it's not necessary to call this function. +pub fn init(sandbox_backend: sandbox_env::SandboxBackend) { + SANDBOX_BACKEND_TYPE.store(sandbox_backend, Ordering::SeqCst); } struct SupervisorContext<'a, 'b> { diff --git a/runtime-interface/sandbox/src/lib.rs b/runtime-interface/sandbox/src/lib.rs index cac05370ae2..4830f369266 100644 --- a/runtime-interface/sandbox/src/lib.rs +++ b/runtime-interface/sandbox/src/lib.rs @@ -21,13 +21,16 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] -pub use gear_sandbox_host::sandbox::env::Instantiate; +pub use gear_sandbox_host::sandbox::{env::Instantiate, SandboxBackend}; use sp_runtime_interface::{runtime_interface, Pointer}; use sp_wasm_interface::HostPointer; #[cfg(feature = "std")] pub mod detail; +#[cfg(feature = "std")] +pub use detail::init; + /// Wasm-only interface that provides functions for interacting with the sandbox. #[runtime_interface(wasm_only)] pub trait Sandbox { diff --git a/runtime-interface/src/lib.rs b/runtime-interface/src/lib.rs index 5ce2809ca84..4eb02cc090c 100644 --- a/runtime-interface/src/lib.rs +++ b/runtime-interface/src/lib.rs @@ -50,7 +50,9 @@ use { pub use gear_sandbox_interface::sandbox; #[cfg(feature = "std")] -pub use gear_sandbox_interface::{detail as sandbox_detail, Instantiate}; +pub use gear_sandbox_interface::{ + detail as sandbox_detail, init as sandbox_init, Instantiate, SandboxBackend, +}; const _: () = assert!(size_of::() >= size_of::()); diff --git a/sandbox/host/Cargo.toml b/sandbox/host/Cargo.toml index df634883545..ac7a4949df5 100644 --- a/sandbox/host/Cargo.toml +++ b/sandbox/host/Cargo.toml @@ -15,6 +15,7 @@ rust-version.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +atomic_enum.workspace = true codec = { workspace = true, features = ["std"] } defer.workspace = true environmental.workspace = true @@ -22,13 +23,16 @@ thiserror.workspace = true log = { workspace = true, features = ["std"] } wasmer.workspace = true wasmer-types.workspace = true -sandbox-wasmi.workspace = true +wasmi.workspace = true sp-allocator = { workspace = true, features = ["std"] } sp-wasm-interface-common = { workspace = true, features = ["std"] } gear-sandbox-env = { workspace = true, features = ["std"] } gear-wasmer-cache = { workspace = true, optional = true } tempfile = { workspace = true, optional = true } +region.workspace = true [features] default = ["wasmer-cache"] wasmer-cache = ["gear-wasmer-cache", "tempfile"] +# See wasmi/extra-checks for more information. +wasmi-extra-checks = ["wasmi/extra-checks"] diff --git a/sandbox/host/src/error.rs b/sandbox/host/src/error.rs index 28d1945e88e..e39dfac783b 100644 --- a/sandbox/host/src/error.rs +++ b/sandbox/host/src/error.rs @@ -26,7 +26,7 @@ pub type Result = std::result::Result; #[allow(missing_docs)] pub enum Error { #[error(transparent)] - Wasmi(#[from] sandbox_wasmi::Error), + Wasmi(#[from] wasmi::Error), #[error("Sandbox error: {0}")] Sandbox(String), @@ -107,10 +107,10 @@ pub enum Error { AbortedDueToTrap(MessageWithBacktrace), } -impl sandbox_wasmi::HostError for Error {} +impl wasmi::core::HostError for Error {} -impl From<&'static str> for Error { - fn from(err: &'static str) -> Error { +impl From<&'_ str> for Error { + fn from(err: &'_ str) -> Error { Error::Other(err.into()) } } diff --git a/sandbox/host/src/lib.rs b/sandbox/host/src/lib.rs index 24997b5e6f2..f144ded1301 100644 --- a/sandbox/host/src/lib.rs +++ b/sandbox/host/src/lib.rs @@ -25,4 +25,6 @@ pub mod error; pub mod sandbox; pub mod util; +pub(crate) mod store_refcell; + use log as _; diff --git a/sandbox/host/src/sandbox.rs b/sandbox/host/src/sandbox.rs index 2efdc0093de..b323b31a110 100644 --- a/sandbox/host/src/sandbox.rs +++ b/sandbox/host/src/sandbox.rs @@ -44,8 +44,8 @@ use self::{ }, wasmi_backend::{ get_global as wasmi_get_global, instantiate as wasmi_instantiate, invoke as wasmi_invoke, - new_memory as wasmi_new_memory, set_global as wasmi_set_global, - MemoryWrapper as WasmiMemoryWrapper, + new_memory as wasmi_new_memory, set_global as wasmi_set_global, Backend as WasmiBackend, + MemoryWrapper as WasmiMemoryWrapper, StoreRefCell as WasmiStoreRefCell, }, }; @@ -165,19 +165,15 @@ pub trait SupervisorContext { fn deallocate_memory(&mut self, ptr: Pointer) -> SandboxResult<()>; } -/// Implementation of [`Externals`] that allows execution of guest module with -/// [externals][`Externals`] that might refer functions defined by supervisor. -/// -/// [`Externals`]: ../wasmi/trait.Externals.html -pub struct GuestExternals<'a> { - /// Instance of sandboxed module to be dispatched - sandbox_instance: &'a SandboxInstance, -} - /// Module instance in terms of selected backend enum BackendInstanceBundle { /// Wasmi module instance - Wasmi(sandbox_wasmi::ModuleRef), + Wasmi { + /// Wasmer module instance + instance: wasmi::Instance, + /// Wasmer store + store: Rc, + }, /// Wasmer module instance and store Wasmer { @@ -204,7 +200,6 @@ enum BackendInstanceBundle { /// [`invoke`]: #method.invoke pub struct SandboxInstance { backend_instance: BackendInstanceBundle, - guest_to_supervisor_mapping: GuestToSupervisorFunctionMapping, } impl SandboxInstance { @@ -219,8 +214,8 @@ impl SandboxInstance { supervisor_context: &mut dyn SupervisorContext, ) -> std::result::Result, error::Error> { match &self.backend_instance { - BackendInstanceBundle::Wasmi(wasmi_instance) => { - wasmi_invoke(self, wasmi_instance, export_name, args, supervisor_context) + BackendInstanceBundle::Wasmi { instance, store } => { + wasmi_invoke(instance, store, export_name, args, supervisor_context) } BackendInstanceBundle::Wasmer { instance, store } => { @@ -234,7 +229,9 @@ impl SandboxInstance { /// Returns `Some(_)` if the global could be found. pub fn get_global_val(&self, name: &str) -> Option { match &self.backend_instance { - BackendInstanceBundle::Wasmi(wasmi_instance) => wasmi_get_global(wasmi_instance, name), + BackendInstanceBundle::Wasmi { instance, store } => { + wasmi_get_global(instance, &store.borrow(), name) + } BackendInstanceBundle::Wasmer { instance, store } => { wasmer_get_global(instance, &mut store.borrow_mut(), name) @@ -251,8 +248,8 @@ impl SandboxInstance { value: Value, ) -> std::result::Result, error::Error> { match &self.backend_instance { - BackendInstanceBundle::Wasmi(wasmi_instance) => { - wasmi_set_global(wasmi_instance, name, value) + BackendInstanceBundle::Wasmi { instance, store } => { + wasmi_set_global(instance, &mut store.borrow_mut(), name, value) } BackendInstanceBundle::Wasmer { instance, store } => { @@ -270,7 +267,9 @@ impl SandboxInstance { /// Expected to be called only from signal handler. pub unsafe fn signal_handler_get_global_val(&self, name: &str) -> Option { match &self.backend_instance { - BackendInstanceBundle::Wasmi(wasmi_instance) => wasmi_get_global(wasmi_instance, name), + BackendInstanceBundle::Wasmi { instance, store } => unsafe { + wasmi_get_global(instance, &*store.as_ptr(), name) + }, BackendInstanceBundle::Wasmer { instance, store } => unsafe { // We cannot use `store.borrow_mut()` in signal handler context because it's already borrowed during `invoke` call. @@ -292,9 +291,10 @@ impl SandboxInstance { value: Value, ) -> Result> { match &self.backend_instance { - BackendInstanceBundle::Wasmi(wasmi_instance) => { - wasmi_set_global(wasmi_instance, name, value) - } + BackendInstanceBundle::Wasmi { instance, store } => unsafe { + // We cannot use `store.borrow_mut()` in signal handler context because it's already borrowed during `invoke` call. + wasmi_set_global(instance, &mut *store.as_ptr(), name, value) + }, BackendInstanceBundle::Wasmer { instance, store } => unsafe { // We cannot use `store.borrow_mut()` in signal handler context because it's already borrowed during `invoke` call. @@ -405,6 +405,7 @@ impl UnregisteredInstance { } /// Sandbox backend to use +#[atomic_enum::atomic_enum] pub enum SandboxBackend { /// Wasm interpreter Wasmi, @@ -497,7 +498,7 @@ impl util::MemoryTransfer for Memory { /// Information specific to a particular execution backend enum BackendContext { /// Wasmi specific context - Wasmi, + Wasmi(WasmiBackend), /// Wasmer specific context Wasmer(WasmerBackend), @@ -506,7 +507,7 @@ enum BackendContext { impl BackendContext { pub fn new(backend: SandboxBackend) -> BackendContext { match backend { - SandboxBackend::Wasmi => BackendContext::Wasmi, + SandboxBackend::Wasmi => BackendContext::Wasmi(WasmiBackend::new()), SandboxBackend::Wasmer => BackendContext::Wasmer(WasmerBackend::new()), } @@ -550,7 +551,9 @@ impl SandboxComponents
{ self.memories.clear(); match self.backend_context { - BackendContext::Wasmi => (), + BackendContext::Wasmi(_) => { + self.backend_context = BackendContext::Wasmi(WasmiBackend::new()); + } BackendContext::Wasmer(_) => { self.backend_context = BackendContext::Wasmer(WasmerBackend::new()); } @@ -565,15 +568,15 @@ impl SandboxComponents
{ /// Typically happens if `initial` is more than `maximum`. pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result { let memories = &mut self.memories; - let backend_context = &self.backend_context; + let backend_context = &mut self.backend_context; let maximum = match maximum { sandbox_env::MEM_UNLIMITED => None, specified_limit => Some(specified_limit), }; - let memory = match &backend_context { - BackendContext::Wasmi => wasmi_new_memory(initial, maximum)?, + let memory = match backend_context { + BackendContext::Wasmi(backend) => wasmi_new_memory(backend, initial, maximum)?, BackendContext::Wasmer(backend) => { wasmer_new_memory(backend.store().clone(), initial, maximum)? @@ -684,7 +687,9 @@ impl SandboxComponents
{ supervisor_context: &mut dyn SupervisorContext, ) -> std::result::Result { let sandbox_instance = match self.backend_context { - BackendContext::Wasmi => wasmi_instantiate(wasm, guest_env, supervisor_context)?, + BackendContext::Wasmi(ref context) => { + wasmi_instantiate(version, context, wasm, guest_env, supervisor_context)? + } BackendContext::Wasmer(ref context) => { wasmer_instantiate(version, context, wasm, guest_env, supervisor_context)? diff --git a/sandbox/host/src/sandbox/wasmer_backend.rs b/sandbox/host/src/sandbox/wasmer_backend.rs index d94a0c6f0ed..41300013a71 100644 --- a/sandbox/host/src/sandbox/wasmer_backend.rs +++ b/sandbox/host/src/sandbox/wasmer_backend.rs @@ -31,11 +31,11 @@ use crate::{ BackendInstanceBundle, GuestEnvironment, InstantiationError, Memory, SandboxInstance, SupervisorContext, SupervisorFuncIndex, }, + store_refcell, util::MemoryTransfer, }; -pub use store_refcell::StoreRefCell; -mod store_refcell; +pub type StoreRefCell = store_refcell::StoreRefCell; #[cfg(feature = "gear-wasmer-cache")] use gear_wasmer_cache::*; @@ -296,7 +296,6 @@ pub fn instantiate( instance, store: context.store().clone(), }, - guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, }) } diff --git a/sandbox/host/src/sandbox/wasmi_backend.rs b/sandbox/host/src/sandbox/wasmi_backend.rs index eccab3efef2..b0c1d142756 100644 --- a/sandbox/host/src/sandbox/wasmi_backend.rs +++ b/sandbox/host/src/sandbox/wasmi_backend.rs @@ -18,393 +18,561 @@ //! Wasmi specific impls for sandbox -use std::fmt; +use std::{ + rc::{Rc, Weak}, + slice, +}; use codec::{Decode, Encode}; -use gear_sandbox_env::HostError; -use sandbox_wasmi::{ - memory_units::Pages, ImportResolver, MemoryInstance, Module, ModuleInstance, RuntimeArgs, - RuntimeValue, Trap, TrapCode, +use gear_sandbox_env::{HostError, Instantiate, WasmReturnValue, GLOBAL_NAME_GAS}; +use region::{Allocation, Protection}; +use wasmi::{ + AsContext, AsContextMut, Engine, ExternType, Linker, MemoryType, Module, StackLimits, Val, }; -use sp_wasm_interface_common::{util, Pointer, ReturnValue, Value, WordSize}; + +use sp_wasm_interface_common::{Pointer, ReturnValue, Value, WordSize}; use crate::{ error::{self, Error}, sandbox::{ - BackendInstanceBundle, GuestEnvironment, GuestExternals, GuestFuncIndex, Imports, - InstantiationError, Memory, SandboxInstance, SupervisorContext, + BackendInstanceBundle, GuestEnvironment, InstantiationError, Memory, SandboxInstance, + SupervisorContext, }, + store_refcell, util::MemoryTransfer, }; +use super::SupervisorFuncIndex; + +type Store = wasmi::Store>; +pub type StoreRefCell = store_refcell::StoreRefCell; + environmental::environmental!(SupervisorContextStore: trait SupervisorContext); -#[derive(Debug)] -struct CustomHostError(String); +pub struct FuncEnv { + store: Weak, + gas_global: wasmi::Global, +} -impl fmt::Display for CustomHostError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "HostError: {}", self.0) +impl FuncEnv { + pub fn new(store: Weak, gas_global: wasmi::Global) -> Self { + Self { store, gas_global } } } -impl sandbox_wasmi::HostError for CustomHostError {} - /// Construct trap error from specified message -fn trap(msg: &'static str) -> Trap { - Trap::host(CustomHostError(msg.into())) +fn host_trap(msg: impl Into) -> wasmi::Error { + wasmi::Error::host(msg.into()) } -impl ImportResolver for Imports { - fn resolve_func( - &self, - module_name: &str, - field_name: &str, - signature: &sandbox_wasmi::Signature, - ) -> std::result::Result { - let idx = self.func_by_name(module_name, field_name).ok_or_else(|| { - sandbox_wasmi::Error::Instantiation(format!( - "Export {}:{} not found", - module_name, field_name - )) - })?; - - Ok(sandbox_wasmi::FuncInstance::alloc_host( - signature.clone(), - idx.0, - )) +fn into_wasmi_val(value: Value) -> wasmi::Val { + match value { + Value::I32(val) => wasmi::Val::I32(val), + Value::I64(val) => wasmi::Val::I64(val), + Value::F32(val) => wasmi::Val::F32(wasmi::core::F32::from_bits(val)), + Value::F64(val) => wasmi::Val::F64(wasmi::core::F64::from_bits(val)), } +} - fn resolve_memory( - &self, - module_name: &str, - field_name: &str, - _memory_type: &sandbox_wasmi::MemoryDescriptor, - ) -> std::result::Result { - let mem = self - .memory_by_name(module_name, field_name) - .ok_or_else(|| { - sandbox_wasmi::Error::Instantiation(format!( - "Export {}:{} not found", - module_name, field_name - )) - })?; - - let wrapper = mem.as_wasmi().ok_or_else(|| { - sandbox_wasmi::Error::Instantiation(format!( - "Unsupported non-wasmi export {}:{}", - module_name, field_name - )) - })?; - - // Here we use inner memory reference only to resolve the imports - // without accessing the memory contents. All subsequent memory accesses - // should happen through the wrapper, that enforces the memory access protocol. - let mem = wrapper.0; - - Ok(mem) +fn into_wasmi_result(value: ReturnValue) -> Vec { + match value { + ReturnValue::Value(v) => vec![into_wasmi_val(v)], + ReturnValue::Unit => vec![], } +} - fn resolve_global( - &self, - module_name: &str, - field_name: &str, - _global_type: &sandbox_wasmi::GlobalDescriptor, - ) -> std::result::Result { - Err(sandbox_wasmi::Error::Instantiation(format!( - "Export {}:{} not found", - module_name, field_name - ))) +fn into_value(value: &wasmi::Val) -> Option { + match value { + wasmi::Val::I32(val) => Some(Value::I32(*val)), + wasmi::Val::I64(val) => Some(Value::I64(*val)), + wasmi::Val::F32(val) => Some(Value::F32(val.to_bits())), + wasmi::Val::F64(val) => Some(Value::F64(val.to_bits())), + _ => None, } +} + +/// Wasmi specific context +pub struct Backend { + store: Rc, + // Allocation should be dropped right after the store is dropped + allocations: Vec, +} - fn resolve_table( - &self, - module_name: &str, - field_name: &str, - _table_type: &sandbox_wasmi::TableDescriptor, - ) -> std::result::Result { - Err(sandbox_wasmi::Error::Instantiation(format!( - "Export {}:{} not found", - module_name, field_name - ))) +impl Default for Backend { + fn default() -> Self { + Self::new() } } -/// Allocate new memory region -pub fn new_memory(initial: u32, maximum: Option) -> crate::error::Result { - let memory = Memory::Wasmi(MemoryWrapper::new( - MemoryInstance::alloc(Pages(initial as usize), maximum.map(|m| Pages(m as usize))) - .map_err(|error| Error::Sandbox(error.to_string()))?, - )); +impl Drop for Backend { + fn drop(&mut self) { + // Ensure what we actually dropping the store and not just the RC reference to it. + // This is important because it enforces the drop order of the store and its allocations. + assert_eq!( + Rc::strong_count(&self.store), + 1, + "Attempt to drop Backend while references to Store still exist" + ); + } +} + +impl Backend { + pub fn new() -> Self { + const DEFAULT_MAX_RECURSION_DEPTH: usize = 10 * 1024; + + // Increase recursion limit because it was not enough for some programs on testnet to run + let mut config = wasmi::Config::default(); + config.set_stack_limits(StackLimits { + maximum_recursion_depth: DEFAULT_MAX_RECURSION_DEPTH, + ..Default::default() + }); + + let engine = Engine::new(&config); + let store = Store::new(&engine, None); + + Backend { + store: Rc::new(StoreRefCell::new(store)), + allocations: Vec::new(), + } + } + + pub fn store(&self) -> &Rc { + &self.store + } - Ok(memory) + pub fn add_allocation(&mut self, alloc: Allocation) { + self.allocations.push(alloc); + } +} + +/// Allocate new memory region +pub fn new_memory( + backend: &mut Backend, + initial: u32, + maximum: Option, +) -> crate::error::Result { + let store = backend.store().clone(); + + let ty = + MemoryType::new(initial, maximum).map_err(|error| Error::Sandbox(error.to_string()))?; + let mut alloc = region::alloc(u32::MAX as usize, Protection::READ_WRITE) + .unwrap_or_else(|err| unreachable!("Failed to allocate memory: {err}")); + + // # Safety: + // + // `wasmi::Memory::new_static()` requires static lifetime so we convert our buffer to it + // but actual lifetime of the buffer is lifetime of `wasmi::Store` itself, + // because the store might hold reference to the memory. + // + // So in accordance with the Rust's drop order rules, the memory will be dropped right after the store is dropped. + // This order ensured by `Backend` structure which contains these fields. + let raw = unsafe { slice::from_raw_parts_mut::<'static, u8>(alloc.as_mut_ptr(), alloc.len()) }; + let memory = wasmi::Memory::new_static(&mut *store.borrow_mut(), ty, raw) + .map_err(|error| Error::Sandbox(error.to_string()))?; + + backend.add_allocation(alloc); + + Ok(Memory::Wasmi(MemoryWrapper::new(memory, store))) } /// Wasmi provides direct access to its memory using slices. /// /// This wrapper limits the scope where the slice can be taken to -#[derive(Debug, Clone)] -pub struct MemoryWrapper(sandbox_wasmi::MemoryRef); +#[derive(Clone)] +pub struct MemoryWrapper { + memory: wasmi::Memory, + store: Rc, +} + +impl std::fmt::Debug for MemoryWrapper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MemoryWrapper") + .field("memory", &self.memory) + .finish() + } +} impl MemoryWrapper { /// Take ownership of the memory region and return a wrapper object - fn new(memory: sandbox_wasmi::MemoryRef) -> Self { - Self(memory) + fn new(memory: wasmi::Memory, store: Rc) -> Self { + Self { memory, store } } } impl MemoryTransfer for MemoryWrapper { fn read(&self, source_addr: Pointer, size: usize) -> error::Result> { - self.0.with_direct_access(|source| { - let range = util::checked_range(source_addr.into(), size, source.len()) - .ok_or_else(|| error::Error::Other("memory read is out of bounds".into()))?; + let mut buffer = vec![0; size]; + let ctx = self.store.borrow(); + self.memory + .read(&*ctx, source_addr.into(), &mut buffer) + .map_err(|_| error::Error::Other("memory read is out of bounds".into()))?; - Ok(Vec::from(&source[range])) - }) + Ok(buffer) } fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> error::Result<()> { - self.0.with_direct_access(|source| { - let range = util::checked_range(source_addr.into(), destination.len(), source.len()) - .ok_or_else(|| error::Error::Other("memory read is out of bounds".into()))?; + let ctx = self.store.borrow(); + self.memory + .read(&*ctx, source_addr.into(), destination) + .map_err(|_| error::Error::Other("memory read is out of bounds".into()))?; - destination.copy_from_slice(&source[range]); - Ok(()) - }) + Ok(()) } fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> error::Result<()> { - self.0.with_direct_access_mut(|destination| { - let range = util::checked_range(dest_addr.into(), source.len(), destination.len()) - .ok_or_else(|| error::Error::Other("memory write is out of bounds".into()))?; + let mut ctx = self.store.borrow_mut(); + self.memory + .write(&mut *ctx, dest_addr.into(), source) + .map_err(|_| error::Error::Other("memory write is out of bounds".into()))?; - destination[range].copy_from_slice(source); - Ok(()) - }) + Ok(()) } fn memory_grow(&mut self, pages: u32) -> error::Result { - self.0 - .grow(Pages(pages as usize)) - .map_err(|e| { - Error::Sandbox(format!( - "Cannot grow memory in masmi sandbox executor: {}", - e - )) - }) - .map(|p| p.0 as u32) + let mut ctx = self.store.borrow_mut(); + self.memory.grow(&mut *ctx, pages).map_err(|e| { + Error::Sandbox(format!("Cannot grow memory in wasmi sandbox executor: {e}",)) + }) } fn memory_size(&mut self) -> u32 { - self.0.current_size().0 as u32 + let ctx = self.store.borrow(); + self.memory.size(&*ctx) } fn get_buff(&mut self) -> *mut u8 { - self.0.direct_access_mut().as_mut().as_mut_ptr() + let ctx = self.store.borrow_mut(); + self.memory.data_ptr(&*ctx) } } -impl<'a> sandbox_wasmi::Externals for GuestExternals<'a> { - fn invoke_index( - &mut self, - index: usize, - args: RuntimeArgs, - ) -> std::result::Result, Trap> { - SupervisorContextStore::with(|supervisor_context| { - // Make `index` typesafe again. - let index = GuestFuncIndex(index); - - // Convert function index from guest to supervisor space - let func_idx = self.sandbox_instance - .guest_to_supervisor_mapping - .func_by_guest_index(index) - .expect( - "`invoke_index` is called with indexes registered via `FuncInstance::alloc_host`; - `FuncInstance::alloc_host` is called with indexes that were obtained from `guest_to_supervisor_mapping`; - `func_by_guest_index` called with `index` can't return `None`; - qed" - ); - - // Serialize arguments into a byte vector. - let invoke_args_data: Vec = args - .as_ref() - .iter() - .cloned() - .map(Value::from) - .collect::>() - .encode(); - - // Move serialized arguments inside the memory, invoke dispatch thunk and - // then free allocated memory. - let invoke_args_len = invoke_args_data.len() as WordSize; - let invoke_args_ptr = supervisor_context - .allocate_memory(invoke_args_len) - .map_err(|_| trap("Can't allocate memory in supervisor for the arguments"))?; - - let deallocate = |supervisor_context: &mut dyn SupervisorContext, ptr, fail_msg| { - supervisor_context.deallocate_memory(ptr).map_err(|_| trap(fail_msg)) - }; - - if supervisor_context - .write_memory(invoke_args_ptr, &invoke_args_data) - .is_err() - { - deallocate( - supervisor_context, - invoke_args_ptr, - "Failed deallocation after failed write of invoke arguments", - )?; - return Err(trap("Can't write invoke args into memory")) - } - - let result = supervisor_context.invoke( - invoke_args_ptr, - invoke_args_len, - func_idx, - ); - - deallocate( - supervisor_context, - invoke_args_ptr, - "Can't deallocate memory for dispatch thunk's invoke arguments", - )?; - let result = result?; - - // dispatch_thunk returns pointer to serialized arguments. - // Unpack pointer and len of the serialized result data. - let (serialized_result_val_ptr, serialized_result_val_len) = { - // Cast to u64 to use zero-extension. - let v = result as u64; - let ptr = (v >> 32) as u32; - let len = (v & 0xFFFFFFFF) as u32; - (Pointer::new(ptr), len) - }; - - let serialized_result_val = supervisor_context - .read_memory(serialized_result_val_ptr, serialized_result_val_len) - .map_err(|_| trap("Can't read the serialized result from dispatch thunk")); - - deallocate( - supervisor_context, - serialized_result_val_ptr, - "Can't deallocate memory for dispatch thunk's result", - ) - .and(serialized_result_val) - .and_then(|serialized_result_val| { - let result_val = std::result::Result::::decode(&mut serialized_result_val.as_slice()) - .map_err(|_| trap("Decoding Result failed!"))?; - - match result_val { - Ok(return_value) => Ok(match return_value { - ReturnValue::Unit => None, - ReturnValue::Value(typed_value) => Some(From::from(typed_value)), - }), - Err(HostError) => Err(trap("Supervisor function returned sandbox::HostError")), - } - }) - }).expect("SandboxContextStore is set when invoking sandboxed functions; qed") - } +/// Get global value by name +pub fn get_global(instance: &wasmi::Instance, store: &Store, name: &str) -> Option { + into_value(&instance.get_global(store, name)?.get(store)) } -fn with_guest_externals(sandbox_instance: &SandboxInstance, f: F) -> R -where - F: FnOnce(&mut GuestExternals) -> R, -{ - f(&mut GuestExternals { sandbox_instance }) +/// Set global value by name +pub fn set_global( + instance: &wasmi::Instance, + store: &mut Store, + name: &str, + value: Value, +) -> Result, error::Error> { + let Some(global) = instance.get_global(&*store, name) else { + return Ok(None); + }; + + global + .set(store, into_wasmi_val(value)) + .map(Some) + .map_err(|e| Error::Sandbox(e.to_string())) } /// Instantiate a module within a sandbox context pub fn instantiate( + version: Instantiate, + context: &Backend, wasm: &[u8], guest_env: GuestEnvironment, supervisor_context: &mut dyn SupervisorContext, -) -> std::result::Result { - let wasmi_module = Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?; - let wasmi_instance = ModuleInstance::new(&wasmi_module, &guest_env.imports) - .map_err(|_| InstantiationError::Instantiation)?; - - let sandbox_instance = SandboxInstance { - // In general, it's not a very good idea to use `.not_started_instance()` for - // anything but for extracting memory and tables. But in this particular case, we - // are extracting for the purpose of running `start` function which should be ok. - backend_instance: BackendInstanceBundle::Wasmi( - wasmi_instance.not_started_instance().clone(), - ), - guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping, - }; +) -> Result { + let mut store = context.store().borrow_mut(); + + let module = + Module::new(store.engine(), wasm).map_err(|_| InstantiationError::ModuleDecoding)?; + let mut linker = Linker::new(store.engine()); + + for import in module.imports() { + let module = import.module(); + let name = import.name(); + + match import.ty() { + ExternType::Global(_) | ExternType::Table(_) => {} + ExternType::Memory(_mem_ty) => { + let memory = guest_env + .imports + .memory_by_name(module, name) + .ok_or(InstantiationError::ModuleDecoding)?; + + let wasmi_memory = memory.as_wasmi().expect( + "memory is created by wasmi; \ + exported by the same module and backend; \ + thus the operation can't fail; \ + qed", + ); + + linker + .define(module, name, wasmi_memory.memory) + .map_err(|_| InstantiationError::EnvironmentDefinitionCorrupted)?; + } + ExternType::Func(func_ty) => { + let guest_func_index = guest_env.imports.func_by_name(module, name); + + let Some(guest_func_index) = guest_func_index else { + // Missing import (should we abort here?) + continue; + }; + + let supervisor_func_index = guest_env + .guest_to_supervisor_mapping + .func_by_guest_index(guest_func_index) + .ok_or(InstantiationError::ModuleDecoding)?; + + let function = match version { + Instantiate::Version1 => { + dispatch_function(supervisor_func_index, &mut store, func_ty) + } + Instantiate::Version2 => { + dispatch_function_v2(supervisor_func_index, &mut store, func_ty) + } + }; + + // Filter out duplicate imports + if linker.get(&*store, module, name).is_none() { + linker + .define(module, name, function) + .map_err(|_| InstantiationError::ModuleDecoding)?; + } + } + } + } - with_guest_externals(&sandbox_instance, |guest_externals| { - SupervisorContextStore::using(supervisor_context, || { - wasmi_instance - .run_start(guest_externals) - .map_err(|_| InstantiationError::StartTrapped) + let instance_pre = linker.instantiate(&mut *store, &module).map_err(|error| { + log::trace!("Failed to call wasmi instantiate: {error:?}"); + InstantiationError::Instantiation + })?; + + let instance = SupervisorContextStore::using(supervisor_context, || { + instance_pre.start(&mut *store).map_err(|error| { + log::trace!("Failed to call wasmi start: {error:?}"); + InstantiationError::StartTrapped }) })?; - Ok(sandbox_instance) + Ok(SandboxInstance { + backend_instance: BackendInstanceBundle::Wasmi { + instance, + store: context.store().clone(), + }, + }) } -/// Invoke a function within a sandboxed module -pub fn invoke( - instance: &SandboxInstance, - module: &sandbox_wasmi::ModuleRef, - export_name: &str, - args: &[Value], - supervisor_context: &mut dyn SupervisorContext, -) -> std::result::Result, error::Error> { - with_guest_externals(instance, |guest_externals| { - SupervisorContextStore::using(supervisor_context, || { - let args = args.iter().cloned().map(From::from).collect::>(); - - module - .invoke_export(export_name, &args, guest_externals) - .map(|result| result.map(Into::into)) - .map_err(|error| { - if matches!(error, sandbox_wasmi::Error::Trap(Trap::Code(TrapCode::StackOverflow))) { - // Panic stops process queue execution in that case. - // This allows to avoid error lead to consensus failures, that must be handled - // in node binaries forever. If this panic occur, then we must increase stack memory size, - // or tune stack limit injection. - // see also https://github.com/wasmerio/wasmer/issues/4181 - let err_msg = format!( - "invoke: Suppose that this can not happen, because we have a stack limit instrumentation in programs. \ - Export name - {export_name}, args - {args:?}", - ); - - log::error!("{err_msg}"); - unreachable!("{err_msg}") - } - error::Error::Sandbox(error.to_string()) - }) - }) - }) +fn dispatch_function( + supervisor_func_index: SupervisorFuncIndex, + store: &mut Store, + func_ty: &wasmi::FuncType, +) -> wasmi::Func { + wasmi::Func::new( + store, + func_ty.clone(), + move |_caller, params, results| -> Result<(), wasmi::Error> { + SupervisorContextStore::with(|supervisor_context| { + let invoke_args_data = params + .iter() + .map(|value| { + into_value(value).ok_or_else(|| { + host_trap(format!("Unsupported function argument: {:?}", value)) + }) + }) + .collect::, _>>()? + .encode(); + + let serialized_result_val = + dispatch_common(supervisor_func_index, supervisor_context, invoke_args_data)?; + + let deserialized_result = + Result::::decode(&mut serialized_result_val.as_slice()) + .map_err(|_| host_trap("Decoding Result failed!"))? + .map_err(|_| { + host_trap("Supervisor function returned sandbox::HostError") + })?; + + for (idx, result_val) in into_wasmi_result(deserialized_result) + .into_iter() + .enumerate() + { + results[idx] = result_val; + } + + Ok(()) + }) + .expect("SupervisorContextStore is set when invoking sandboxed functions; qed") + }, + ) } -/// Get global value by name -pub fn get_global(instance: &sandbox_wasmi::ModuleRef, name: &str) -> Option { - Some(Into::into( - instance.export_by_name(name)?.as_global()?.get(), - )) +fn dispatch_function_v2( + supervisor_func_index: SupervisorFuncIndex, + store: &mut Store, + func_ty: &wasmi::FuncType, +) -> wasmi::Func { + wasmi::Func::new( + store, + func_ty.clone(), + move |mut caller, params, results| -> Result<(), wasmi::Error> { + SupervisorContextStore::with(|supervisor_context| { + let func_env = caller.data().as_ref().expect("func env should be set"); + let store_ref_cell = func_env.store.upgrade().expect("store should be alive"); + let gas_global = func_env.gas_global; + + let gas = gas_global.get(caller.as_context()); + let store_ctx_mut = caller.as_context_mut(); + + let deserialized_result = store_ref_cell + .borrow_scope(store_ctx_mut, move || { + let invoke_args_data = [gas] + .iter() + .chain(params.iter()) + .map(|value| { + into_value(value).ok_or_else(|| { + host_trap(format!("Unsupported function argument: {:?}", value)) + }) + }) + .collect::, _>>()? + .encode(); + + let serialized_result_val = dispatch_common( + supervisor_func_index, + supervisor_context, + invoke_args_data, + )?; + + Result::::decode( + &mut serialized_result_val.as_slice(), + ) + .map_err(|_| host_trap("Decoding Result failed!"))? + .map_err(|_| host_trap("Supervisor function returned sandbox::HostError")) + }) + .map_err(|_| host_trap("StoreRefCell borrow scope error"))??; + + for (idx, result_val) in into_wasmi_result(deserialized_result.inner) + .into_iter() + .enumerate() + { + results[idx] = result_val; + } + + gas_global + .set(caller, Val::I64(deserialized_result.gas)) + .map_err(|e| host_trap(format!("Failed to set gas global: {:?}", e)))?; + + Ok(()) + }) + .expect("SandboxContextStore is set when invoking sandboxed functions; qed") + }, + ) } -/// Set global value by name -pub fn set_global( - instance: &sandbox_wasmi::ModuleRef, - name: &str, - value: Value, -) -> std::result::Result, error::Error> { - let export = match instance.export_by_name(name) { - Some(e) => e, - None => return Ok(None), +fn dispatch_common( + supervisor_func_index: SupervisorFuncIndex, + supervisor_context: &mut dyn SupervisorContext, + invoke_args_data: Vec, +) -> Result, wasmi::Error> { + // Move serialized arguments inside the memory, invoke dispatch thunk and + // then free allocated memory. + let invoke_args_len = invoke_args_data.len() as WordSize; + let invoke_args_ptr = supervisor_context + .allocate_memory(invoke_args_len) + .map_err(|_| host_trap("Can't allocate memory in supervisor for the arguments"))?; + + let deallocate = |fe: &mut dyn SupervisorContext, ptr, fail_msg| { + fe.deallocate_memory(ptr).map_err(|_| host_trap(fail_msg)) }; - let global = match export.as_global() { - Some(g) => g, - None => return Ok(None), + if supervisor_context + .write_memory(invoke_args_ptr, &invoke_args_data) + .is_err() + { + deallocate( + supervisor_context, + invoke_args_ptr, + "Failed deallocation after failed write of invoke arguments", + )?; + + return Err(host_trap("Can't write invoke args into memory")); + } + + // Perform the actual call + let serialized_result = supervisor_context + .invoke(invoke_args_ptr, invoke_args_len, supervisor_func_index) + .map_err(|e| host_trap(e.to_string())); + + deallocate( + supervisor_context, + invoke_args_ptr, + "Failed deallocation after invoke", + )?; + + let serialized_result = serialized_result?; + + // TODO #3038 + // dispatch_thunk returns pointer to serialized arguments. + // Unpack pointer and len of the serialized result data. + let (serialized_result_val_ptr, serialized_result_val_len) = { + // Cast to u64 to use zero-extension. + let v = serialized_result as u64; + let ptr = (v >> 32) as u32; + let len = (v & 0xFFFFFFFF) as u32; + (Pointer::new(ptr), len) }; - global - .set(From::from(value)) - .map(|_| Some(())) - .map_err(error::Error::Wasmi) + let serialized_result_val = supervisor_context + .read_memory(serialized_result_val_ptr, serialized_result_val_len) + .map_err(|_| host_trap("Can't read the serialized result from dispatch thunk")); + + deallocate( + supervisor_context, + serialized_result_val_ptr, + "Can't deallocate memory for dispatch thunk's result", + )?; + + serialized_result_val +} + +/// Invoke a function within a sandboxed module +pub fn invoke( + instance: &wasmi::Instance, + store: &Rc, + export_name: &str, + args: &[Value], + supervisor_context: &mut dyn SupervisorContext, +) -> Result, Error> { + let function = instance + .get_func(&*store.borrow(), export_name) + .ok_or_else(|| Error::Sandbox(format!("function {export_name} export error")))?; + + let args: Vec = args.iter().copied().map(into_wasmi_val).collect(); + let func_ty = function.ty(&*store.borrow()); + + let mut outputs = + vec![wasmi::Val::ExternRef(wasmi::ExternRef::null()); func_ty.results().len()]; + + // Init func env + { + let gas_global = instance + .get_global(&*store.borrow(), GLOBAL_NAME_GAS) + .ok_or_else(|| Error::Sandbox("Failed to get gas global".into()))?; + + store + .borrow_mut() + .data_mut() + .replace(FuncEnv::new(Rc::downgrade(store), gas_global)); + } + + SupervisorContextStore::using(supervisor_context, || { + function + .call(&mut *store.borrow_mut(), &args, &mut outputs) + .map_err(|error| Error::Sandbox(error.to_string())) + })?; + + match outputs.as_slice() { + [] => Ok(None), + [val] => match into_value(val) { + None => Err(Error::Sandbox(format!("Unsupported return value: {val:?}"))), + Some(v) => Ok(Some(v)), + }, + _outputs => Err(Error::Sandbox( + "multiple return types are not supported yet".into(), + )), + } } diff --git a/sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs b/sandbox/host/src/store_refcell.rs similarity index 80% rename from sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs rename to sandbox/host/src/store_refcell.rs index 548ec2de725..970c9819f8d 100644 --- a/sandbox/host/src/sandbox/wasmer_backend/store_refcell.rs +++ b/sandbox/host/src/store_refcell.rs @@ -18,7 +18,7 @@ //! # Description //! -//! Custom implementation of `RefCell` for the `wasmer::Store` type, +//! Custom implementation of `RefCell` for the `wasmer::Store`/`wasmi::Store` types, //! enabling safe repeated mutable borrowing of `StoreRefCell` higher up the call stack //! when the mutable borrow of `StoreRefCell` still exists. //! @@ -55,7 +55,7 @@ //! //! # Why is this necessary? Can't we do without repeated mutable borrowing? //! -//! The issue arises because when handling syscalls within an instance of a program running in Wasmer, +//! The issue arises because when handling syscalls within an instance of a program running in the sandbox, //! a runtime interface call occurs, leading to a situation where we have two nested runtime interface calls. //! The first call `sandbox::invoke` initiates the program execution, the second occurs during the syscall processing. //! @@ -69,7 +69,7 @@ //! ----------------------------------- //! | runtime executes syscall | //! --------runtime boundary----------- -//! | syscall_callback | Wasmer calls syscall callback from inside his VM +//! | syscall_callback | Wasmer/Wasmi calls syscall callback from inside its VM //! ----------------------------------- //! | Wasmer's Func::call | Sandbox starts to executes program function (Borrows Store mutably) //! -------native boundary----------- | @@ -83,20 +83,18 @@ //! Therefore, since it is not possible to pass a reference to Store through nested runtime interface call //! or cancel previous mutable borrow, it is necessary to use `StoreRefCell` for safe repeated mutable borrowing of `Store`. //! - use std::{ cell::{Cell, UnsafeCell}, - num::NonZero, + num::NonZeroUsize, ops::{Deref, DerefMut}, ptr::NonNull, }; use defer::defer; -use wasmer::{AsStoreMut, AsStoreRef, Store, StoreRef}; #[derive(Debug, Clone, Copy)] enum BorrowState { - Shared(NonZero), + Shared(NonZeroUsize), Mutable, NonShared, } @@ -104,17 +102,22 @@ enum BorrowState { /// Custom implementation of `RefCell` which allows to safely borrow store /// mutably/immutably second time inside the scope. #[derive(Debug)] -pub struct StoreRefCell { - store: UnsafeCell, +pub struct StoreRefCell { + store: UnsafeCell, state: Cell, } +trait GenericAsStoreMut {} + +impl<'r, 's> GenericAsStoreMut for &'r mut wasmer::StoreMut<'s> {} +impl<'s, T> GenericAsStoreMut for wasmi::StoreContextMut<'s, T> {} + #[derive(Debug)] pub struct BorrowScopeError; -impl StoreRefCell { +impl StoreRefCell { /// Create new `StoreRefCell` with provided `Store` - pub fn new(store: Store) -> Self { + pub fn new(store: S) -> Self { Self { store: UnsafeCell::new(store), state: Cell::new(BorrowState::NonShared), @@ -123,17 +126,16 @@ impl StoreRefCell { /// Borrow store immutably, same semantics as `RefCell::borrow` #[track_caller] - pub fn borrow(&self) -> Ref<'_> { + pub fn borrow(&self) -> Ref<'_, S> { match self.state.get() { BorrowState::Shared(n) => { self.state.set(BorrowState::Shared( - NonZero::::new(n.get() + 1).expect("non zero"), + NonZeroUsize::new(n.get() + 1).expect("non zero"), )); } BorrowState::NonShared => { - self.state.set(BorrowState::Shared( - NonZero::::new(1).expect("non zero"), - )); + self.state + .set(BorrowState::Shared(NonZeroUsize::new(1).expect("non zero"))); } BorrowState::Mutable => { panic!("store already borrowed mutably"); @@ -148,7 +150,7 @@ impl StoreRefCell { /// Borrow store mutably, same semantics as `RefCell::borrow_mut` #[track_caller] - pub fn borrow_mut(&self) -> RefMut<'_> { + pub fn borrow_mut(&self) -> RefMut<'_, S> { match self.state.get() { BorrowState::NonShared => { self.state.set(BorrowState::Mutable); @@ -165,17 +167,12 @@ impl StoreRefCell { } /// Provide borrow scope where store can be borrowed mutably second time safely (or borrowed immutably multiple times). + #[allow(private_bounds)] pub fn borrow_scope R>( &self, - store: impl AsStoreMut, + store: impl GenericAsStoreMut, f: F, ) -> Result { - // We expect the same store - debug_assert!( - self.compare_stores(store.as_store_ref()), - "stores are different" - ); - // Caller just returned borrowed mutably reference to the store, now we can safely borrow it mutably again let _store = store; @@ -197,29 +194,19 @@ impl StoreRefCell { Ok(result) } - #[allow(unused)] - fn compare_stores(&self, returned_store: StoreRef) -> bool { - // SAFETY: - // Verified with Miri, it seems safe. - // Carefully compare the stores while don't using/holding mutable references to them in the same time. - let orig_store_ref: StoreRef = unsafe { &*self.store.get() }.as_store_ref(); - - StoreRef::same(&orig_store_ref, &returned_store) - } - /// Returns store ptr, same semantics as `RefCell::as_ptr` - pub unsafe fn as_ptr(&self) -> *mut Store { + pub unsafe fn as_ptr(&self) -> *mut S { self.store.get() } } -pub struct Ref<'b> { - store: NonNull, +pub struct Ref<'b, S> { + store: NonNull, state: &'b Cell, } -impl Deref for Ref<'_> { - type Target = Store; +impl Deref for Ref<'_, S> { + type Target = S; #[inline] fn deref(&self) -> &Self::Target { @@ -228,7 +215,7 @@ impl Deref for Ref<'_> { } } -impl Drop for Ref<'_> { +impl Drop for Ref<'_, S> { fn drop(&mut self) { match self.state.get() { BorrowState::Shared(n) if n.get() == 1 => { @@ -236,7 +223,7 @@ impl Drop for Ref<'_> { } BorrowState::Shared(n) => { self.state.set(BorrowState::Shared( - NonZero::::new(n.get() - 1).expect("non zero"), + NonZeroUsize::new(n.get() - 1).expect("non zero"), )); } _ => unreachable!(), @@ -244,13 +231,13 @@ impl Drop for Ref<'_> { } } -pub struct RefMut<'b> { - store: NonNull, +pub struct RefMut<'b, S> { + store: NonNull, state: &'b Cell, } -impl<'a> Deref for RefMut<'a> { - type Target = Store; +impl<'a, S> Deref for RefMut<'a, S> { + type Target = S; #[inline] fn deref(&self) -> &Self::Target { @@ -259,7 +246,7 @@ impl<'a> Deref for RefMut<'a> { } } -impl DerefMut for RefMut<'_> { +impl DerefMut for RefMut<'_, S> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { // SAFETY: we ensure that store isn't borrowed before @@ -267,7 +254,7 @@ impl DerefMut for RefMut<'_> { } } -impl Drop for RefMut<'_> { +impl Drop for RefMut<'_, S> { fn drop(&mut self) { match self.state.get() { BorrowState::Mutable => { @@ -280,15 +267,15 @@ impl Drop for RefMut<'_> { #[cfg(test)] mod tests { + use super::*; use std::rc::Rc; - use wasmer::StoreMut; - - use super::*; + struct Store; + impl<'r> GenericAsStoreMut for &'r mut Store {} #[test] fn test_store_refcell_borrow() { - let store = Store::default(); + let store = Store; let store_refcell = StoreRefCell::new(store); { @@ -307,19 +294,19 @@ mod tests { #[test] fn test_store_refcell_borrow_scope() { struct Env { - store: Rc, + store: Rc>, } - let store = Store::default(); + let store = Store; let rc = Rc::new(StoreRefCell::new(store)); let env = Env { store: rc.clone() }; - let callback = |env: Env, mut storemut: StoreMut| { + let callback = |env: Env, storemut: &mut Store| { // do something with `storemut` // .. let rc = rc.clone(); - let _ = env.store.borrow_scope(&mut storemut, move || { + let _ = env.store.borrow_scope(storemut, move || { // Callback is called and it allowed to borrow store mutably/immutably { let _borrow = rc.borrow_mut(); @@ -339,6 +326,6 @@ mod tests { }; let mut borrow = rc.borrow_mut(); - callback(env, borrow.as_store_mut()) + callback(env, &mut borrow) } } diff --git a/sandbox/sandbox/src/embedded_executor.rs b/sandbox/sandbox/src/embedded_executor.rs index 6a3b08f387a..e319cf38bcd 100644 --- a/sandbox/sandbox/src/embedded_executor.rs +++ b/sandbox/sandbox/src/embedded_executor.rs @@ -26,7 +26,10 @@ use alloc::string::String; use gear_sandbox_env::GLOBAL_NAME_GAS; use gear_wasmer_cache::get_or_compile_with_cache; use sp_wasm_interface_common::HostPointer; -use std::{collections::btree_map::BTreeMap, fs, marker::PhantomData, path::PathBuf, ptr::NonNull}; +use std::{ + collections::btree_map::BTreeMap, fs, marker::PhantomData, path::PathBuf, ptr::NonNull, + sync::OnceLock, +}; use wasmer::{ sys::{BaseTunables, VMConfig}, vm::{ @@ -39,12 +42,17 @@ use wasmer::{ use wasmer_types::{ExternType, Target}; fn fs_cache() -> PathBuf { - let out_dir = PathBuf::from(env!("OUT_DIR")); - let cache = out_dir.join("wasmer-cache"); - if !cache.exists() { - fs::create_dir(&cache).unwrap(); - } - cache + static CACHE_DIR: OnceLock = OnceLock::new(); + CACHE_DIR + .get_or_init(|| { + let out_dir = PathBuf::from(env!("OUT_DIR")); + let cache = out_dir.join("wasmer-cache"); + if !cache.exists() { + fs::create_dir(&cache).unwrap(); + } + cache + }) + .into() } struct CustomTunables { diff --git a/utils/gear-replay-cli/src/cmd/mod.rs b/utils/gear-replay-cli/src/cmd/mod.rs index 0557362be4c..89c5c6396b0 100644 --- a/utils/gear-replay-cli/src/cmd/mod.rs +++ b/utils/gear-replay-cli/src/cmd/mod.rs @@ -63,6 +63,8 @@ pub enum Command { impl Command { pub async fn run(&self, shared: &SharedParams) -> sc_cli::Result<()> { + gear_runtime_interface::sandbox_init(gear_runtime_interface::SandboxBackend::Wasmer); + match &self { Command::ReplayBlock(cmd) => { replay_block::run::(shared.clone(), cmd.clone()).await diff --git a/utils/lazy-pages-fuzzer/Cargo.toml b/utils/lazy-pages-fuzzer/Cargo.toml index ae84c472580..4405740707e 100644 --- a/utils/lazy-pages-fuzzer/Cargo.toml +++ b/utils/lazy-pages-fuzzer/Cargo.toml @@ -15,6 +15,6 @@ gear-lazy-pages-common.workspace = true log.workspace = true region.workspace = true wasmer.workspace = true -sandbox-wasmi.workspace = true +wasmi.workspace = true wasmprinter.workspace = true wat.workspace = true diff --git a/utils/lazy-pages-fuzzer/src/generate/globals.rs b/utils/lazy-pages-fuzzer/src/generate/globals.rs index bd71156ca9e..b2705a4a389 100644 --- a/utils/lazy-pages-fuzzer/src/generate/globals.rs +++ b/utils/lazy-pages-fuzzer/src/generate/globals.rs @@ -182,34 +182,30 @@ mod tests { let module = Module::from_bytes(wasm).unwrap(); let (module, _) = globals.inject(module).unwrap(); - let module = sandbox_wasmi::Module::from_buffer(module.into_bytes().unwrap()).unwrap(); - let instance = - sandbox_wasmi::ModuleInstance::new(&module, &sandbox_wasmi::ImportsBuilder::default()) - .unwrap() - .assert_no_start(); + let engine = wasmi::Engine::default(); + let mut store = wasmi::Store::new(&engine, ()); - let gear_fuzz_a: i64 = instance - .export_by_name("gear_fuzz_a") - .unwrap() - .as_global() + let module = wasmi::Module::new(&engine, &module.into_bytes().unwrap()).unwrap(); + let instance = wasmi::Instance::new(&mut store, &module, &[]).unwrap(); + + let gear_fuzz_a = instance + .get_global(&store, "gear_fuzz_a") .unwrap() - .get() - .try_into() + .get(&store) + .i64() .unwrap(); assert_eq!(gear_fuzz_a, INITIAL_GLOBAL_VALUE); - let _ = instance - .invoke_export("main", &[], &mut sandbox_wasmi::NopExternals) + let func = instance.get_func(&store, "main").unwrap(); + func.call(&mut store, &[], &mut [wasmi::Val::I64(0)]) .unwrap(); // Assert that global was modified (initially 0) - let gear_fuzz_a: i64 = instance - .export_by_name("gear_fuzz_a") - .unwrap() - .as_global() + let gear_fuzz_a = instance + .get_global(&store, "gear_fuzz_a") .unwrap() - .get() - .try_into() + .get(&store) + .i64() .unwrap(); assert_eq!(gear_fuzz_a, EXPECTED_GLOBAL_VALUE); } diff --git a/utils/lazy-pages-fuzzer/src/generate/mem_accesses.rs b/utils/lazy-pages-fuzzer/src/generate/mem_accesses.rs index aafef772fd2..7d70b66d8c8 100644 --- a/utils/lazy-pages-fuzzer/src/generate/mem_accesses.rs +++ b/utils/lazy-pages-fuzzer/src/generate/mem_accesses.rs @@ -151,6 +151,8 @@ impl<'u> InjectMemoryAccesses<'u> { mod tests { use std::hash::{DefaultHasher, Hash, Hasher}; + use crate::MODULE_ENV; + use super::*; const TEST_PROGRAM_WAT: &str = r#" @@ -162,20 +164,6 @@ mod tests { ) "#; - struct Resolver { - memory: sandbox_wasmi::MemoryRef, - } - - impl sandbox_wasmi::ModuleImportResolver for Resolver { - fn resolve_memory( - &self, - _field_name: &str, - _memory_type: &sandbox_wasmi::MemoryDescriptor, - ) -> Result { - Ok(self.memory.clone()) - } - } - fn calculate_slice_hash(slice: &[u8]) -> u64 { let mut s = DefaultHasher::new(); for b in slice { @@ -198,29 +186,34 @@ mod tests { .inject(module) .unwrap(); - let memory = - sandbox_wasmi::MemoryInstance::alloc(sandbox_wasmi::memory_units::Pages(1), None) - .unwrap(); + let engine = wasmi::Engine::default(); + let mut store = wasmi::Store::new(&engine, ()); + let module = wasmi::Module::new(&engine, &module.into_bytes().unwrap()).unwrap(); + + let ty = wasmi::MemoryType::new(1, None).unwrap(); + let memory = wasmi::Memory::new(&mut store, ty).unwrap(); let original_mem_hash = { - let mem_slice = memory.direct_access(); - calculate_slice_hash(mem_slice.as_ref()) + let mem_slice = memory.data(&store); + calculate_slice_hash(mem_slice) }; - let resolver = Resolver { memory }; - let imports = sandbox_wasmi::ImportsBuilder::new().with_resolver("env", &resolver); + let mut linker = >::new(&engine); + linker.define(MODULE_ENV, "memory", memory).unwrap(); - let module = sandbox_wasmi::Module::from_buffer(module.into_bytes().unwrap()).unwrap(); - let instance = sandbox_wasmi::ModuleInstance::new(&module, &imports) + let instance = linker + .instantiate(&mut store, &module) .unwrap() - .assert_no_start(); - let _ = instance - .invoke_export("main", &[], &mut sandbox_wasmi::NopExternals) + .ensure_no_start(&mut store) + .unwrap(); + let func = instance.get_func(&store, "main").unwrap(); + + func.call(&mut store, &[], &mut [wasmi::Val::I32(0)]) .unwrap(); let mem_hash = { - let mem_slice = resolver.memory.direct_access(); - calculate_slice_hash(mem_slice.as_ref()) + let mem_slice = memory.data(&store); + calculate_slice_hash(mem_slice) }; assert_ne!(original_mem_hash, mem_hash); diff --git a/utils/lazy-pages-fuzzer/src/wasmer_backend.rs b/utils/lazy-pages-fuzzer/src/wasmer_backend.rs index b12ae31f233..b234659e896 100644 --- a/utils/lazy-pages-fuzzer/src/wasmer_backend.rs +++ b/utils/lazy-pages-fuzzer/src/wasmer_backend.rs @@ -34,6 +34,12 @@ use crate::{ #[derive(Clone)] struct InstanceBundle { instance: Instance, + // NOTE: Due to the implementation of lazy pages, which need to access the Store to retrieve globals, + // we have to use a second mutable reference to the Store in the form of a raw pointer + // to use it within the lazy pages' signal handler context. + // + // We consider it relatively safe because we rely on the fact that during an external function call, + // Wasmer does not access globals mutably, allowing us to access them mutably from the lazy pages' signal handler. store: *mut Store, } diff --git a/utils/lazy-pages-fuzzer/src/wasmi_backend.rs b/utils/lazy-pages-fuzzer/src/wasmi_backend.rs index c03403fa270..ea2d1c6e694 100644 --- a/utils/lazy-pages-fuzzer/src/wasmi_backend.rs +++ b/utils/lazy-pages-fuzzer/src/wasmi_backend.rs @@ -16,14 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use anyhow::{bail, Context}; +use std::slice; + +use anyhow::{anyhow, bail, Context}; use gear_wasm_gen::SyscallName; use gear_wasm_instrument::{parity_wasm::elements::Module, GLOBAL_NAME_GAS}; -use sandbox_wasmi::{ - memory_units::Pages, ExternVal, FuncInstance, FuncRef, ImportsBuilder, MemoryInstance, - MemoryRef, Module as WasmiModule, ModuleImportResolver, ModuleInstance, ModuleRef, - RuntimeValue, Trap, TrapCode, ValueType, +use region::{Allocation, Protection}; +use wasmi::{ + core::UntypedVal, Caller, Config, Engine, Error, Instance, Linker, Memory, MemoryType, + Module as WasmiModule, StackLimits, Store, Val, }; use crate::{ @@ -35,127 +37,151 @@ use crate::{ use error::CustomHostError; mod error; -struct Resolver { - memory: MemoryRef, +#[derive(Clone)] +struct InstanceBundle { + instance: Instance, + // NOTE: Due to the implementation of lazy pages, which need to access the Store to retrieve globals, + // we have to use a second mutable reference to the Store in the form of a raw pointer + // to use it within the lazy pages' signal handler context. + // + // We consider it relatively safe because we rely on the fact that during an external function call, + // Wasmi does not access globals mutably, allowing us to access them mutably from the lazy pages' signal handler. + store: *mut Store<()>, } -impl ModuleImportResolver for Resolver { - fn resolve_func( - &self, - field_name: &str, - _signature: &sandbox_wasmi::Signature, - ) -> Result { - if field_name == SyscallName::SystemBreak.to_str() { - Ok(FuncInstance::alloc_host( - sandbox_wasmi::Signature::new([ValueType::I32].as_slice(), None), - 0, - )) - } else { - Err(sandbox_wasmi::Error::Instantiation(format!( - "Export '{field_name}' not found" - ))) - } - } - - fn resolve_memory( - &self, - _field_name: &str, - _memory_type: &sandbox_wasmi::MemoryDescriptor, - ) -> Result { - Ok(self.memory.clone()) +impl InstanceAccessGlobal for InstanceBundle { + fn set_global(&self, name: &str, value: i64) -> anyhow::Result<()> { + let global = self + .instance + .get_global(unsafe { &*self.store }, name) + .ok_or_else(|| anyhow!("failed to get global {name}"))?; + global.set(unsafe { &mut *self.store }, Val::I64(value))?; + Ok(()) } -} -struct Externals { - gr_system_break_idx: usize, -} + fn get_global(&self, name: &str) -> anyhow::Result { + let global = self + .instance + .get_global(unsafe { &*self.store }, name) + .ok_or_else(|| anyhow!("failed to get global {name}"))?; + let Val::I64(v) = global.get(unsafe { &mut *self.store }) else { + bail!("global {name} is not an i64") + }; -impl sandbox_wasmi::Externals for Externals { - fn invoke_index( - &mut self, - index: usize, - _args: sandbox_wasmi::RuntimeArgs, - ) -> Result, sandbox_wasmi::Trap> { - Err(if index == self.gr_system_break_idx { - sandbox_wasmi::Trap::host(CustomHostError::from("out of gas")) - } else { - TrapCode::Unreachable.into() - }) + Ok(v) } } -impl InstanceAccessGlobal for ModuleRef { - fn set_global(&self, name: &str, value: i64) -> anyhow::Result<()> { - let Some(ExternVal::Global(global)) = self.export_by_name(name) else { - bail!("global '{name}' not found"); - }; +fn config() -> Config { + let register_len = size_of::(); - Ok(global.set(RuntimeValue::I64(value))?) - } + const DEFAULT_MIN_VALUE_STACK_HEIGHT: usize = 1024; + const DEFAULT_MAX_VALUE_STACK_HEIGHT: usize = 1024 * DEFAULT_MIN_VALUE_STACK_HEIGHT; + const DEFAULT_MAX_RECURSION_DEPTH: usize = 16384; - fn get_global(&self, name: &str) -> anyhow::Result { - let Some(ExternVal::Global(global)) = self.export_by_name(name) else { - bail!("global '{name}' not found"); - }; + let mut config = Config::default(); + config.set_stack_limits( + StackLimits::new( + DEFAULT_MIN_VALUE_STACK_HEIGHT / register_len, + DEFAULT_MAX_VALUE_STACK_HEIGHT / register_len, + DEFAULT_MAX_RECURSION_DEPTH, + ) + .expect("infallible"), + ); - let RuntimeValue::I64(v) = global.get() else { - bail!("global is not an i64"); - }; + config +} - Ok(v) - } +fn memory(store: &mut Store<()>) -> anyhow::Result<(Memory, Allocation)> { + let mut alloc = region::alloc(u32::MAX as usize, Protection::READ_WRITE) + .unwrap_or_else(|err| unreachable!("Failed to allocate memory: {err}")); + // # Safety: + // + // `wasmi::Memory::new_static()` requires static lifetime so we convert our buffer to it + // but actual lifetime of the buffer is lifetime of `wasmi::Store` itself, + // because the store might hold reference to the memory. + let memref = + unsafe { slice::from_raw_parts_mut::<'static, u8>(alloc.as_mut_ptr(), alloc.len()) }; + let ty = MemoryType::new(INITIAL_PAGES, None).context("failed to create memory type")?; + let memref = Memory::new_static(store, ty, memref).context("failed to create memory")?; + + Ok((memref, alloc)) } pub struct WasmiRunner; impl Runner for WasmiRunner { fn run(module: &Module) -> anyhow::Result { - let wasmi_module = - WasmiModule::from_buffer(module.clone().into_bytes().map_err(anyhow::Error::msg)?) - .context("failed to load wasm")?; - - let memory = MemoryInstance::alloc(Pages(INITIAL_PAGES as usize), None) - .context("failed to allocate memory")?; - - let mem_ptr = memory.direct_access().as_ref().as_ptr() as usize; - let mem_size = memory.direct_access().as_ref().len(); - - let resolver = Resolver { memory }; - let imports = ImportsBuilder::new().with_resolver(MODULE_ENV, &resolver); - - let instance = ModuleInstance::new(&wasmi_module, &imports) + let engine = Engine::new(&config()); + + let wasmi_module = WasmiModule::new( + &engine, + &module.clone().into_bytes().map_err(anyhow::Error::msg)?, + ) + .context("failed to load wasm")?; + + let mut store = Store::new(&engine, ()); + + // NOTE: alloc should be dropped after exit of this function's scope + let (memory, _alloc) = memory(&mut store)?; + let mem_ptr = memory.data_ptr(&store) as usize; + let mem_size = memory.data_size(&store); + + let mut linker: Linker<()> = >::new(&engine); + linker + .func_wrap( + MODULE_ENV, + SyscallName::SystemBreak.to_str(), + |_caller: Caller<()>, _param: i32| -> Result<(), Error> { + Err(Error::host(CustomHostError::from("out of gas"))) + }, + ) + .context("failed to define host function")?; + + linker + .define(MODULE_ENV, "memory", memory) + .context("failed to define memory")?; + + let instance = linker + .instantiate(&mut store, &wasmi_module) .context("failed to instantiate wasm module")? - .assert_no_start(); + .ensure_no_start(&mut store) + .context("failed to ensure no start")?; - instance - .set_global(GLOBAL_NAME_GAS, PROGRAM_GAS) + let gas = instance + .get_global(&store, GLOBAL_NAME_GAS) + .context("failed to get gas")?; + gas.set(&mut store, Val::I64(PROGRAM_GAS)) .context("failed to set gas")?; + let global_accessor = InstanceBundle { + instance, + store: &mut store, + }; + + let init_fn = instance + .get_func(&store, "init") + .context("failed to get export fn")?; + lazy_pages::init_fuzzer_lazy_pages(FuzzerLazyPagesContext { - instance: Box::new(instance.clone()), + instance: Box::new(global_accessor.clone()), memory_range: mem_ptr..(mem_ptr + mem_size), pages: Default::default(), globals_list: globals_list(module), }); - if let Err(error) = instance.invoke_export( - "init", - &[], - &mut Externals { - gr_system_break_idx: 0, - }, - ) { - if let sandbox_wasmi::Error::Trap(Trap::Host(_)) = error { - log::info!("out of gas"); + if let Err(error) = init_fn.call(&mut store, &[], &mut []) { + if let Some(custom_error) = error.downcast_ref::() { + log::info!("{custom_error}"); } else { Err(error)?; } } let result = RunResult { - gas_global: instance.get_global(GLOBAL_NAME_GAS)?, + gas_global: gas.get(&store).i64().context("failed to get gas global")?, pages: lazy_pages::get_touched_pages(), - globals: get_globals(&instance, module).context("failed to get globals")?, + globals: get_globals(&global_accessor, module).context("failed to get globals")?, }; Ok(result) diff --git a/utils/lazy-pages-fuzzer/src/wasmi_backend/error.rs b/utils/lazy-pages-fuzzer/src/wasmi_backend/error.rs index 1369aecaea0..6d58488f287 100644 --- a/utils/lazy-pages-fuzzer/src/wasmi_backend/error.rs +++ b/utils/lazy-pages-fuzzer/src/wasmi_backend/error.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use derive_more::Display; -use sandbox_wasmi::HostError; +use wasmi::core::HostError; #[derive(Debug, Display)] #[display(fmt = "{message}")]