diff --git a/.config/hakari.toml b/.config/hakari.toml index 340fc06cd54..49dbf46fb4f 100644 --- a/.config/hakari.toml +++ b/.config/hakari.toml @@ -28,47 +28,60 @@ platforms = [ workspace-hack-line-style = "workspace-dotted" [final-excludes] +workspace-members = [ + "sc-executor", + "sc-executor-common", + "sc-executor-polkavm", + "sc-executor-wasmtime", + "sc-mixnet", + "sp-allocator", + "sp-runtime-interface-proc-macro", + "sp-wasm-interface", + "sp-wasm-interface-common", + "substrate-wasm-builder", +] + third-party = [ # we have to exclude these deps because of their `try-runtime` and `runtime-benchmarks` features, # because we cannot, for example, run `cargo build --package gear-cli` without `--all-features` flag - { name = "frame-benchmarking", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "frame-benchmarking-cli", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "frame-election-provider-support", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "frame-executive", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "frame-support", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "frame-system", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "frame-try-runtime", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-authority-discovery", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-authorship", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-babe", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-bags-list", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-balances", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-bounties", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-child-bounties", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-conviction-voting", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-election-provider-multi-phase", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-grandpa", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-identity", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-im-online", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-multisig", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-nomination-pools", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-offences", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-preimage", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-proxy", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-ranked-collective", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-referenda", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-scheduler", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-session", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-staking", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-sudo", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-timestamp", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-transaction-payment", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-treasury", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-utility", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-vesting", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "pallet-whitelist", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "sc-client-db", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "sc-service", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "sp-runtime", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, - { name = "sp-staking", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" }, + { name = "frame-benchmarking", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "frame-benchmarking-cli", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "frame-election-provider-support", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "frame-executive", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "frame-support", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "frame-system", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "frame-try-runtime", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-authority-discovery", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-authorship", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-babe", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-bags-list", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-balances", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-bounties", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-child-bounties", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-conviction-voting", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-election-provider-multi-phase", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-grandpa", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-identity", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-im-online", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-multisig", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-nomination-pools", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-offences", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-preimage", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-proxy", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-ranked-collective", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-referenda", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-scheduler", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-session", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-staking", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-sudo", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-timestamp", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-transaction-payment", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-treasury", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-utility", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-vesting", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "pallet-whitelist", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "sc-client-db", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "sc-service", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "sp-runtime", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, + { name = "sp-staking", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" }, ] diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0b44f15cbee..21ee0226d14 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -234,6 +234,16 @@ jobs: - name: "Install: Setup linker" uses: ./.github/actions/setup-linker + - name: "Install: protobuf compiler" + uses: nick-fields/retry@v3 + with: + timeout_minutes: 15 + max_attempts: 5 + retry_wait_seconds: 10 + command: | + sudo apt update + sudo apt install -y protobuf-compiler + - name: "Install: Rust toolchain" uses: ./.github/actions/install-rust diff --git a/.gitignore b/.gitignore index 7e706d12c13..5a9616f158e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,3 @@ utils/**/fuzz/fuzz/* fuzz_run lazy_pages_fuzz_run seed.bin - diff --git a/Cargo.lock b/Cargo.lock index cfbf64cdc60..68c6425c3e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2299,11 +2299,13 @@ checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] name = "binary-merkle-tree" -version = "15.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "16.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6d867f1ffee8b07e7bee466f4f33a043b91f868f5c7b1d22d8a02f86e92bee8" dependencies = [ "hash-db", "log", + "parity-scale-codec", ] [[package]] @@ -2586,8 +2588,8 @@ dependencies = [ [[package]] name = "bp-header-chain" -version = "0.18.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.18.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "bp-runtime", "finality-grandpa", @@ -2604,7 +2606,7 @@ dependencies = [ [[package]] name = "bp-runtime" version = "0.18.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -4121,15 +4123,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "uuid", -] - [[package]] name = "defer" version = "0.2.1" @@ -5340,15 +5333,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "enum-as-inner" version = "0.5.1" @@ -6313,7 +6297,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fork-tree" version = "13.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", ] @@ -6345,8 +6329,8 @@ checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" [[package]] name = "frame-benchmarking" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.1.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-support-procedural", @@ -6369,8 +6353,8 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" -version = "43.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "43.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "Inflector", "array-bytes", @@ -6436,7 +6420,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "14.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -6447,7 +6431,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -6462,8 +6446,8 @@ dependencies = [ [[package]] name = "frame-executive" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.0.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "aquamarine", "frame-support", @@ -6505,7 +6489,7 @@ dependencies = [ [[package]] name = "frame-metadata-hash-extension" version = "0.6.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "docify", @@ -6520,7 +6504,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.46.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "futures", "indicatif 0.17.11", @@ -6529,7 +6513,7 @@ dependencies = [ "parity-scale-codec", "serde", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-io", "sp-runtime", "sp-state-machine", @@ -6541,8 +6525,8 @@ dependencies = [ [[package]] name = "frame-support" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.2.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "aquamarine", "array-bytes", @@ -6559,7 +6543,7 @@ dependencies = [ "paste", "scale-info", "serde", - "serde-json-wasm", + "serde_json", "smallvec", "sp-api", "sp-arithmetic", @@ -6582,8 +6566,8 @@ dependencies = [ [[package]] name = "frame-support-procedural" -version = "30.0.3" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "30.0.6" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "Inflector", "cfg-expr", @@ -6596,14 +6580,14 @@ dependencies = [ "proc-macro-warning 1.84.1", "proc-macro2", "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "syn 2.0.114", ] [[package]] name = "frame-support-procedural-tools" version = "13.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate 3.4.0", @@ -6615,7 +6599,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "12.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "proc-macro2", "quote", @@ -6625,7 +6609,7 @@ dependencies = [ [[package]] name = "frame-support-test" version = "3.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-executive", @@ -6653,7 +6637,7 @@ dependencies = [ [[package]] name = "frame-support-test-pallet" version = "4.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -6666,7 +6650,7 @@ dependencies = [ [[package]] name = "frame-system" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "cfg-if", "docify", @@ -6686,7 +6670,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -6700,7 +6684,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "parity-scale-codec", @@ -6710,7 +6694,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "parity-scale-codec", @@ -6927,20 +6911,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "fxprof-processed-profile" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25234f20a3ec0a962a61770cfe39ecf03cb529a6e474ad8cff025ed497eda557" -dependencies = [ - "bitflags 2.10.0", - "debugid", - "rustc-hash 2.1.1", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "galloc" version = "2.0.0" @@ -7135,7 +7105,6 @@ dependencies = [ "gear-runtime-primitives", "gear-service", "gear-workspace-hack", - "log", "mimalloc", "pallet-gear-payment", "pallet-gear-staking-rewards", @@ -7541,6 +7510,7 @@ dependencies = [ "gear-sandbox-host", "gear-workspace-hack", "log", + "sc-executor", "sp-runtime-interface", "sp-wasm-interface", ] @@ -7844,6 +7814,8 @@ dependencies = [ "concurrent-queue", "const-hex", "cranelift-bitset", + "cranelift-codegen", + "cranelift-codegen-meta", "crc32fast", "crossbeam-channel", "crossbeam-epoch", @@ -7853,6 +7825,7 @@ dependencies = [ "curve25519-dalek", "data-encoding", "der", + "derive_more 0.99.20", "derive_more 2.1.1", "digest 0.10.7", "digest 0.9.0", @@ -7992,7 +7965,6 @@ dependencies = [ "parity-wasm", "pbkdf2", "percent-encoding", - "petgraph", "pkcs8", "polkavm-common", "portable-atomic", @@ -8019,7 +7991,6 @@ dependencies = [ "ring 0.17.14", "rocksdb", "ruint", - "rustc-demangle", "rustc-hash 1.1.0", "rustc-hash 2.1.1", "rustc-hex", @@ -8053,7 +8024,6 @@ dependencies = [ "signature", "smallvec", "soketto", - "sp-allocator", "sp-api", "sp-api-proc-macro", "sp-application-crypto", @@ -8066,7 +8036,7 @@ dependencies = [ "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", @@ -8087,8 +8057,6 @@ dependencies = [ "sp-transaction-pool", "sp-trie", "sp-version", - "sp-wasm-interface", - "sp-wasm-interface-common", "sp-weights", "spki", "ss58-registry", @@ -8101,7 +8069,6 @@ dependencies = [ "subxt-metadata", "syn 1.0.109", "syn 2.0.114", - "target-lexicon", "thiserror 2.0.17", "time", "tiny-keccak", @@ -8126,17 +8093,11 @@ dependencies = [ "unsigned-varint 0.7.2", "unsigned-varint 0.8.0", "url", - "uuid", "wasm-bindgen", "wasm-encoder 0.230.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-encoder 0.246.2", - "wasmi 0.13.2", "wasmi 0.38.0", - "wasmi_core 0.2.1", "wasmparser 0.230.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.246.2", "wasmtime", - "wasmtime-environ", "wasmtime-internal-core", "wasmtime-internal-cranelift", "winnow", @@ -8163,7 +8124,7 @@ checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc" [[package]] name = "generate-bags" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "chrono", "frame-election-provider-support", @@ -9242,12 +9203,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -9653,26 +9608,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" -[[package]] -name = "ittapi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" -dependencies = [ - "anyhow", - "ittapi-sys", - "log", -] - -[[package]] -name = "ittapi-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" -dependencies = [ - "cc", -] - [[package]] name = "jiff" version = "0.2.18" @@ -12512,7 +12447,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -12527,7 +12462,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -12540,7 +12475,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -12563,7 +12498,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "aquamarine", "docify", @@ -12583,8 +12518,8 @@ dependencies = [ [[package]] name = "pallet-balances" -version = "39.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "39.0.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "frame-benchmarking", @@ -12598,8 +12533,8 @@ dependencies = [ [[package]] name = "pallet-bounties" -version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "37.0.2" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -12616,7 +12551,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -12634,7 +12569,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "assert_matches", "frame-benchmarking", @@ -12650,7 +12585,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -12672,7 +12607,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -13200,7 +13135,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13240,7 +13175,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "enumflags2", "frame-benchmarking", @@ -13256,7 +13191,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13275,7 +13210,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13289,8 +13224,8 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" -version = "35.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "35.0.3" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -13307,8 +13242,8 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" -version = "33.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "33.0.2" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -13318,7 +13253,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -13334,7 +13269,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13350,7 +13285,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13363,8 +13298,8 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.2.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13382,7 +13317,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "assert_matches", "frame-benchmarking", @@ -13399,8 +13334,8 @@ dependencies = [ [[package]] name = "pallet-scheduler" -version = "39.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "39.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "frame-benchmarking", @@ -13417,7 +13352,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -13437,8 +13372,8 @@ dependencies = [ [[package]] name = "pallet-staking" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.0.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -13460,7 +13395,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "22.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "log", "sp-arithmetic", @@ -13469,7 +13404,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "24.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "sp-api", @@ -13479,7 +13414,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "frame-benchmarking", @@ -13494,7 +13429,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "frame-benchmarking", @@ -13512,8 +13447,8 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.0.2" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-support", "frame-system", @@ -13528,7 +13463,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "41.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -13544,7 +13479,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -13556,7 +13491,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "frame-benchmarking", @@ -13574,7 +13509,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13589,7 +13524,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -13603,7 +13538,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-benchmarking", "frame-support", @@ -15803,7 +15738,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "futures", @@ -15833,7 +15768,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.42.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "sp-api", @@ -15848,7 +15783,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "docify", @@ -15864,7 +15799,7 @@ dependencies = [ "serde_json", "sp-blockchain", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-genesis-builder", "sp-io", "sp-runtime", @@ -15875,7 +15810,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "12.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -15886,7 +15821,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.47.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "chrono", @@ -15927,7 +15862,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "fnv", "futures", @@ -15953,8 +15888,8 @@ dependencies = [ [[package]] name = "sc-client-db" -version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.44.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "hash-db", "kvdb", @@ -15980,7 +15915,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "futures", @@ -16004,7 +15939,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "fork-tree", @@ -16029,7 +15964,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-slots", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-inherents", "sp-keystore", "sp-runtime", @@ -16040,7 +15975,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "futures", "jsonrpsee", @@ -16062,7 +15997,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "fork-tree", "parity-scale-codec", @@ -16075,7 +16010,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.30.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "ahash", "array-bytes", @@ -16109,7 +16044,7 @@ dependencies = [ "sp-consensus", "sp-consensus-grandpa", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-keystore", "sp-runtime", "substrate-prometheus-endpoint", @@ -16119,7 +16054,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.30.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "finality-grandpa", "futures", @@ -16139,7 +16074,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "futures", @@ -16162,7 +16097,6 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.40.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "parity-scale-codec", "parking_lot 0.12.5", @@ -16180,26 +16114,23 @@ dependencies = [ "sp-version", "sp-wasm-interface", "tracing", - "wasmi 0.13.2", ] [[package]] name = "sc-executor-common" version = "0.35.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "polkavm", "sp-allocator", "sp-maybe-compressed-blob", "sp-wasm-interface", - "thiserror 1.0.69", + "thiserror 2.0.17", "wasm-instrument", ] [[package]] name = "sc-executor-polkavm" version = "0.32.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "log", "polkavm", @@ -16210,25 +16141,28 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.35.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ - "anyhow", - "cfg-if", - "libc", + "cargo_metadata", "log", + "parity-scale-codec", "parking_lot 0.12.5", + "paste", "rustix 1.1.3", "sc-executor-common", + "sc-runtime-test", "sp-allocator", + "sp-io", "sp-runtime-interface", "sp-wasm-interface", + "tempfile", "wasmtime", + "wat", ] [[package]] name = "sc-informant" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "console 0.15.11", "futures", @@ -16245,7 +16179,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "33.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "parking_lot 0.12.5", @@ -16259,7 +16193,6 @@ dependencies = [ [[package]] name = "sc-mixnet" version = "0.15.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "array-bytes", "arrayvec 0.7.6", @@ -16269,7 +16202,6 @@ dependencies = [ "futures-timer", "log", "mixnet", - "multiaddr 0.18.2", "parity-scale-codec", "parking_lot 0.12.5", "sc-client-api", @@ -16282,13 +16214,13 @@ dependencies = [ "sp-keystore", "sp-mixnet", "sp-runtime", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "sc-network" -version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.45.6" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "async-channel 1.9.0", @@ -16339,7 +16271,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "bitflags 1.3.2", @@ -16357,7 +16289,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "ahash", "futures", @@ -16375,8 +16307,8 @@ dependencies = [ [[package]] name = "sc-network-light" -version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.44.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "async-channel 1.9.0", @@ -16396,8 +16328,8 @@ dependencies = [ [[package]] name = "sc-network-sync" -version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.44.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "async-channel 1.9.0", @@ -16433,8 +16365,8 @@ dependencies = [ [[package]] name = "sc-network-transactions" -version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.44.1" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "futures", @@ -16453,7 +16385,7 @@ dependencies = [ [[package]] name = "sc-network-types" version = "0.12.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "bs58 0.5.1", "ed25519-dalek", @@ -16470,7 +16402,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "40.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "bytes", @@ -16504,7 +16436,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.18.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -16513,7 +16445,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "40.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "futures", "jsonrpsee", @@ -16545,7 +16477,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -16564,8 +16496,8 @@ dependencies = [ [[package]] name = "sc-rpc-server" -version = "17.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "17.1.2" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "dyn-clone", "forwarded-header-value", @@ -16589,7 +16521,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "futures", @@ -16618,10 +16550,22 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "sc-runtime-test" +version = "2.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" +dependencies = [ + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "substrate-wasm-builder", +] + [[package]] name = "sc-service" version = "0.46.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "directories", @@ -16685,7 +16629,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.36.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "log", "parity-scale-codec", @@ -16696,7 +16640,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.45.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -16715,7 +16659,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "derive_more 0.99.20", "futures", @@ -16728,7 +16672,7 @@ dependencies = [ "serde", "serde_json", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-io", "sp-std", ] @@ -16736,7 +16680,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "25.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "chrono", "futures", @@ -16756,7 +16700,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "37.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "chrono", "console 0.15.11", @@ -16785,7 +16729,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "11.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", @@ -16796,7 +16740,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "futures", @@ -16812,7 +16756,7 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-runtime", "sp-tracing", "sp-transaction-pool", @@ -16823,7 +16767,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "futures", @@ -16839,7 +16783,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "17.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-channel 1.9.0", "futures", @@ -17821,18 +17765,17 @@ dependencies = [ [[package]] name = "sp-allocator" version = "29.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "log", "parity-scale-codec", "sp-wasm-interface-common", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] name = "sp-api" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "hash-db", @@ -17853,8 +17796,8 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" -version = "20.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "20.0.3" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "Inflector", "blake2 0.10.6", @@ -17868,7 +17811,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -17880,7 +17823,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "26.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "integer-sqrt", @@ -17894,7 +17837,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -17906,7 +17849,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "sp-api", "sp-inherents", @@ -17916,7 +17859,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "37.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "futures", "parity-scale-codec", @@ -17935,7 +17878,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.40.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "futures", @@ -17950,7 +17893,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.40.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "parity-scale-codec", @@ -17968,7 +17911,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "21.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "finality-grandpa", "log", @@ -17985,7 +17928,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.40.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -17996,7 +17939,7 @@ dependencies = [ [[package]] name = "sp-core" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "bitflags 1.3.2", @@ -18025,7 +17968,7 @@ dependencies = [ "secp256k1 0.28.2", "secrecy", "serde", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -18042,7 +17985,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.14.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -18076,7 +18019,7 @@ dependencies = [ [[package]] name = "sp-crypto-hashing" version = "0.1.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "blake2b_simd", "byteorder", @@ -18089,17 +18032,17 @@ dependencies = [ [[package]] name = "sp-crypto-hashing-proc-macro" version = "0.1.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "quote", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "syn 2.0.114", ] [[package]] name = "sp-database" version = "10.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "kvdb", "parking_lot 0.12.5", @@ -18108,7 +18051,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "proc-macro2", "quote", @@ -18118,7 +18061,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.29.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "environmental", "parity-scale-codec", @@ -18128,7 +18071,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.15.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -18140,7 +18083,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -18152,8 +18095,8 @@ dependencies = [ [[package]] name = "sp-io" -version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "38.0.2" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "bytes", "docify", @@ -18165,7 +18108,7 @@ dependencies = [ "rustversion", "secp256k1 0.28.2", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-externalities", "sp-keystore", "sp-runtime-interface", @@ -18179,7 +18122,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "39.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "sp-core", "sp-runtime", @@ -18189,7 +18132,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.40.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "parking_lot 0.12.5", @@ -18200,7 +18143,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "11.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "thiserror 1.0.69", "zstd 0.12.4", @@ -18209,7 +18152,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.7.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "frame-metadata 16.0.0", "parity-scale-codec", @@ -18219,7 +18162,7 @@ dependencies = [ [[package]] name = "sp-mixnet" version = "0.12.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -18230,7 +18173,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -18243,7 +18186,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "sp-api", "sp-core", @@ -18253,7 +18196,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "13.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "backtrace", "lazy_static", @@ -18263,7 +18206,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "32.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "rustc-hash 1.1.0", "serde", @@ -18272,8 +18215,8 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "39.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "39.0.5" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "either", @@ -18299,7 +18242,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "28.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -18318,7 +18261,6 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "18.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "Inflector", "expander", @@ -18331,7 +18273,7 @@ dependencies = [ [[package]] name = "sp-session" version = "36.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "scale-info", @@ -18345,7 +18287,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "36.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -18358,7 +18300,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.43.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "hash-db", "log", @@ -18378,7 +18320,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "18.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "aes-gcm", "curve25519-dalek", @@ -18391,7 +18333,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-core", - "sp-crypto-hashing 0.1.0 (git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime)", + "sp-crypto-hashing 0.1.0 (git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c)", "sp-externalities", "sp-runtime", "sp-runtime-interface", @@ -18402,12 +18344,12 @@ dependencies = [ [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" [[package]] name = "sp-storage" version = "21.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "impl-serde 0.4.0", "parity-scale-codec", @@ -18419,7 +18361,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "parity-scale-codec", @@ -18431,7 +18373,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "17.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "tracing", @@ -18442,7 +18384,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "sp-api", "sp-runtime", @@ -18451,7 +18393,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "34.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "parity-scale-codec", @@ -18465,7 +18407,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "ahash", "hash-db", @@ -18488,7 +18430,7 @@ dependencies = [ [[package]] name = "sp-version" version = "37.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "impl-serde 0.4.0", "parity-scale-codec", @@ -18505,7 +18447,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "14.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -18516,7 +18458,6 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "21.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -18530,7 +18471,6 @@ dependencies = [ [[package]] name = "sp-wasm-interface-common" version = "7.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" dependencies = [ "parity-scale-codec", "sp-std", @@ -18540,7 +18480,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "31.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "bounded-collections", "parity-scale-codec", @@ -18816,7 +18756,7 @@ dependencies = [ [[package]] name = "substrate-bip39" version = "0.6.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "hmac 0.12.1", "pbkdf2", @@ -18828,12 +18768,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "11.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" [[package]] name = "substrate-frame-rpc-system" version = "39.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "docify", "frame-system-rpc-runtime-api", @@ -18852,8 +18792,8 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" -version = "0.17.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "0.17.5" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "http-body-util", "hyper 1.8.1", @@ -18867,7 +18807,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.44.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "async-trait", "jsonrpsee", @@ -18880,7 +18820,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "38.0.0" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -18897,7 +18837,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +source = "git+https://github.com/paritytech/polkadot-sdk.git?rev=298f676c91d64f15f38ea7fd78f125c5889ab09c#298f676c91d64f15f38ea7fd78f125c5889ab09c" dependencies = [ "array-bytes", "async-trait", @@ -18923,8 +18863,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" -version = "24.0.1" -source = "git+https://github.com/gear-tech/polkadot-sdk.git?branch=gear-polkadot-stable2409-updated-wasmtime#27e4faf64a8103d8eddae3dea5c3991427b7baaf" +version = "24.0.2" dependencies = [ "array-bytes", "build-helper", @@ -20569,23 +20508,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-compose" -version = "0.246.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05a2b3bad87cc1ce45b63425ec09a854cc4cb369231c9fed1fee31538103efb" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.14.0", - "log", - "petgraph", - "smallvec", - "wasm-encoder 0.246.2", - "wasmparser 0.246.2", - "wat", -] - [[package]] name = "wasm-encoder" version = "0.230.0" @@ -20683,6 +20605,7 @@ dependencies = [ "gear-workspace-hack", "log", "tracing-subscriber", + "wasmparser 0.230.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -20789,7 +20712,6 @@ dependencies = [ "memory_units", "num-rational", "num-traits", - "region", ] [[package]] @@ -20928,11 +20850,6 @@ dependencies = [ "bumpalo", "cc", "cfg-if", - "encoding_rs", - "futures", - "fxprof-processed-profile", - "gimli 0.33.0", - "ittapi", "libc", "log", "mach2 0.4.3", @@ -20943,20 +20860,13 @@ dependencies = [ "pulley-interpreter", "rayon", "rustix 1.1.3", - "semver 1.0.27", "serde", "serde_derive", - "serde_json", "smallvec", "target-lexicon", - "tempfile", - "wasm-compose", - "wasm-encoder 0.246.2", "wasmparser 0.246.2", "wasmtime-environ", "wasmtime-internal-cache", - "wasmtime-internal-component-macro", - "wasmtime-internal-component-util", "wasmtime-internal-core", "wasmtime-internal-cranelift", "wasmtime-internal-fiber", @@ -20965,7 +20875,6 @@ dependencies = [ "wasmtime-internal-unwinder", "wasmtime-internal-versioned-export-macros", "wasmtime-internal-winch", - "wat", "windows-sys 0.61.2", ] @@ -20987,7 +20896,6 @@ dependencies = [ "object 0.39.1", "postcard", "rustc-demangle", - "semver 1.0.27", "serde", "serde_derive", "sha2 0.10.9", @@ -20996,7 +20904,6 @@ dependencies = [ "wasm-encoder 0.246.2", "wasmparser 0.246.2", "wasmprinter 0.246.2", - "wasmtime-internal-component-util", "wasmtime-internal-core", ] @@ -21020,27 +20927,6 @@ dependencies = [ "zstd 0.13.3", ] -[[package]] -name = "wasmtime-internal-component-macro" -version = "44.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c223bd503db76df8d74d1fcca39e734d25f7a0c1dcaf1509b67f3855d1b0f803" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.114", - "wasmtime-internal-component-util", - "wasmtime-internal-wit-bindgen", - "wit-parser", -] - -[[package]] -name = "wasmtime-internal-component-util" -version = "44.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab123ad511483a1b918399789d0cc7dea7c5c6476743df73949007b5b225fc74" - [[package]] name = "wasmtime-internal-core" version = "44.0.2" @@ -21102,8 +20988,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f364747aa74c686b18925918e5cfd615a73c9613c7a31fc1cd86f42df12fbe" dependencies = [ "cc", - "object 0.39.1", - "rustix 1.1.3", "wasmtime-internal-versioned-export-macros", ] @@ -21160,19 +21044,6 @@ dependencies = [ "winch-codegen", ] -[[package]] -name = "wasmtime-internal-wit-bindgen" -version = "44.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f08787948e3c983799d616ef7dd57463253e9ca8bab6607eef8134f12353f70" -dependencies = [ - "anyhow", - "bitflags 2.10.0", - "heck 0.5.0", - "indexmap 2.14.0", - "wit-parser", -] - [[package]] name = "wasmtimer" version = "0.4.3" @@ -21804,25 +21675,6 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" -[[package]] -name = "wit-parser" -version = "0.246.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd979042b5ff288607ccf3b314145435453f20fc67173195f91062d2289b204d" -dependencies = [ - "anyhow", - "hashbrown 0.16.1", - "id-arena", - "indexmap 2.14.0", - "log", - "semver 1.0.27", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser 0.246.2", -] - [[package]] name = "writeable" version = "0.6.2" diff --git a/Cargo.toml b/Cargo.toml index b0efbdfda1e..ea9efda81ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,17 @@ default-members = ["vara/node/cli"] exclude = ["ethexe/contracts", "ethexe/docker", "ethexe/malachite", "ethexe/scripts"] members = [ + # substrate + "substrate/runtime-executor", + "substrate/runtime-executor/common", + "substrate/runtime-executor/polkavm", + "substrate/runtime-executor/wasmtime", + "substrate/sc-mixnet", + "substrate/sp-allocator", + "substrate/sp-runtime-interface-proc-macro", + "substrate/sp-wasm-interface", + "substrate/sp-wasm-interface-common", + "substrate/substrate-wasm-builder", # protocol "protocol/*", "protocol/lazy-pages", @@ -135,6 +146,7 @@ alloy-primitives = { version = "1.5.7", default-features = false } alloy-sol-types = { version = "1.5.7", default-features = false } advisory-lock = "0.3.0" anyhow = { version = "1.0.86", default-features = false } +array-bytes = { version = "6.2.2", default-features = false } arbitrary = "1.3.2" async-recursion = "1.1.1" async-trait = "0.1.81" @@ -144,10 +156,12 @@ bytemuck = "1.23.2" byteorder = { version = "1.5.0", default-features = false } blake2 = { version = "0.10.6", default-features = false } bs58 = { version = "0.5.1", default-features = false } +build-helper = "0.1.1" cargo_toml = "0.21.0" cargo_metadata = "0.20.0" clap = "4.5.8" colored = "2.1.0" +console = "0.15.8" const-str = "0.5" criterion = "0.8.2" crossbeam = "0.8.4" @@ -160,25 +174,36 @@ dirs = "4.0.0" dyn-clonable = "0.9.0" enum-iterator = "1.5.0" environmental = "1.1.3" +expander = "2.0.0" +filetime = "0.2.16" flate2 = "1" futures = { version = "0.3", default-features = false } futures-timer = "3.0.3" future-timing = "0.1.0" # measure the futures execution hashbrown = "0.14.5" +hash-db = { version = "0.16.0", default-features = false } hex = { version = "0.4.3", default-features = false } hex-literal = "0.4.1" impl-trait-for-tuples = "0.2.2" impl-serde = "0.4.0" +Inflector = "0.11.4" indoc = "2.0.7" jsonrpsee = { version = "^0.24" } +jobserver = "0.1.26" libc = { version = "0.2", default-features = false } log = { version = "0.4.22", default-features = false } +merkleized-metadata = "0.1.0" +mixnet = "0.7.0" +multiaddr = "0.18.1" num_enum = { version = "0.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.7.5", default-features = false } numerated = { version = "2.0.1", default-features = false } +parity-wasm = "0.45.0" parity-scale-codec = { version = "3.7.5", default-features = false } parking_lot = "0.12.3" path-clean = "1.0.1" primitive-types = { version = "0.12.2", default-features = false } +proc-macro-crate = "3.0.0" proc-macro2 = { version = "1", default-features = false } prometheus = { version = "0.14.0", default-features = false } proptest = "1.5.0" @@ -192,6 +217,7 @@ reqwest = { version = "0.12.8", default-features = false } scale-info = { version = "2.11", default-features = false } scale-decode = "0.16.0" scale-encode = "0.10.0" +schnellru = "0.2.3" serde = { version = "^1", default-features = false } serde_json = { version = "1.0.135", default-features = false, features = [ "alloc", @@ -207,7 +233,7 @@ tokio = { version = "1.38.0" } lru = "0.16.1" url = "2.5.2" wat = "1.0.71" -wasmtime = { version = "44.0.1", features = ["winch"] } +wasmtime = { version = "44.0.1", default-features = false, features = ["anyhow", "winch"] } wasmparser = { version = "0.230", default-features = false, features = ["validate", "features"] } which = "4.4.2" winapi = "0.3.9" @@ -223,6 +249,9 @@ sha2 = { version = "0.10.8", default-features = false } sha3 = { version = "0.10.8", default-features = false } arrayvec = { version = "0.7.4", default-features = false } indexmap = { version = "2.2.6", default-features = false } +polkavm = { version = "0.9.3", default-features = false } +rustix = { version = "1.0.8", default-features = false } +strum = { version = "0.26.2", default-features = false } tracing = { version = "0.1.40", default-features = false } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } assert_matches = "1.5.0" @@ -369,127 +398,138 @@ malachitebft-test = { package = "arc-malachitebft-test", gi wasmi = { version = "0.38" } # Substrate deps -bp-header-chain = { version = "0.18.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -binary-merkle-tree = { version = "15.0.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-benchmarking = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-benchmarking-cli = { version = "43.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -frame-election-provider-support = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-executive = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-support = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-support-test = { version = "3.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-system = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-system-benchmarking = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-remote-externalities = { version = "0.46.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -frame-try-runtime = { version = "0.44.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -frame-system-rpc-runtime-api = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } - -frame-metadata-hash-extension = { default-features = false, git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } - - -generate-bags = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -pallet-authorship = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-authority-discovery = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-babe = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-bags-list = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-bounties = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-child-bounties = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-balances = { version = "39.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-conviction-voting = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-election-provider-multi-phase = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-grandpa = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-identity = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-im-online = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-multisig = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-nomination-pools = { version = "35.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-nomination-pools-runtime-api = { version = "33.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-offences = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-preimage = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-proxy = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-ranked-collective = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-referenda = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-scheduler = { version = "39.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-session = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-staking = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-staking-runtime-api = { version = "24.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-staking-reward-fn = { version = "22.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-sudo = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-timestamp = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-transaction-payment = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-transaction-payment-rpc = { version = "41.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-transaction-payment-rpc-runtime-api = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-treasury = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-utility = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-vesting = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -pallet-whitelist = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.17.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-authority-discovery = { version = "0.45.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-block-builder = { version = "0.42.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-consensus = { version = "0.44.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-consensus-babe = { version = "0.45.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-consensus-babe-rpc = { version = "0.45.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-consensus-slots = { version = "0.44.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-crypto-ec-utils = { version = "0.14.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-debug-derive = { version = "14.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sc-chain-spec = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-cli = { version = "0.47.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-client-api = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-executor = { version = "0.40.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-executor-common = { version = "0.35.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-consensus-grandpa = { version = "0.30.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-consensus-grandpa-rpc = { version = "0.30.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-network = { version = "0.45.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-network-sync = { version = "0.44.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-offchain = { version = "40.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-proposer-metrics = { version = "0.18.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-service = { version = "0.46.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-telemetry = { version = "25.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-rpc = { version = "40.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-sync-state-rpc = { version = "0.45.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-sysinfo = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-transaction-pool = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-transaction-pool-api = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sc-tracing = { version = "37.0.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-allocator = { version = "29.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-api = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-authority-discovery = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-arithmetic = { version = "26.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-blockchain = { version = "37.0.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-block-builder = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-core = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-consensus = { version = "0.40.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-consensus-babe = { version = "0.40.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-consensus-slots = { version = "0.40.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-application-crypto = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-externalities = { version = "0.29.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-consensus-grandpa = { version = "21.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-genesis-builder = { version = "0.15.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-inherents = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-io = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-keyring = { version = "39.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-keystore = { version = "0.40.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-npos-elections = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-offchain = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-rpc = { version = "32.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-runtime = { version = "39.0.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-runtime-interface = { version = "28.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-session = { version = "36.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-std = { version = "14.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-state-machine = { version = "0.43.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-staking = { version = "36.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-storage = { version = "21.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-timestamp = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-transaction-pool = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-transaction-storage-proof = { version = "34.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-trie = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-version = { version = "37.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-wasm-interface = { version = "21.0.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -sp-wasm-interface-common = { version = "7.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false } -substrate-build-script-utils = { version = "11.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -substrate-frame-rpc-system = { version = "39.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -substrate-rpc-client = { version = "0.44.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -substrate-state-trie-migration-rpc = { version = "38.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -substrate-test-client = { version = "2.0.0", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -substrate-wasm-builder = { version = "24.0.1", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +bp-header-chain = { version = "0.18.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +binary-merkle-tree = { version = "16.1.1", default-features = false } +frame-benchmarking = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-benchmarking-cli = { version = "43.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +frame-election-provider-support = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-executive = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-support = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-support-test = { version = "3.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-system = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-system-benchmarking = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-remote-externalities = { version = "0.46.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +frame-try-runtime = { version = "0.44.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-system-rpc-runtime-api = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +frame-metadata = { version = "16.0.0", default-features = false } + +frame-metadata-hash-extension = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +polkavm-linker = "0.9.2" + + +generate-bags = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +pallet-authorship = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-authority-discovery = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-babe = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-bags-list = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-bounties = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-child-bounties = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-balances = { version = "39.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-conviction-voting = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-election-provider-multi-phase = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-grandpa = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-identity = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-im-online = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-multisig = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-nomination-pools = { version = "35.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-nomination-pools-runtime-api = { version = "33.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-offences = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-preimage = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-proxy = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-ranked-collective = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-referenda = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-scheduler = { version = "39.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-session = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-staking = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-staking-runtime-api = { version = "24.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-staking-reward-fn = { version = "22.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-sudo = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-timestamp = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-transaction-payment = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-transaction-payment-rpc = { version = "41.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-treasury = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-utility = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-vesting = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +pallet-whitelist = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.17.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-authority-discovery = { version = "0.45.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-block-builder = { version = "0.42.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-consensus = { version = "0.44.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-consensus-babe = { version = "0.45.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-consensus-babe-rpc = { version = "0.45.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-consensus-slots = { version = "0.44.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-crypto-ec-utils = { version = "0.14.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-debug-derive = { version = "14.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sc-chain-spec = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-cli = { version = "0.47.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-client-api = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-executor = { path = "substrate/runtime-executor" } +sc-executor-common = { path = "substrate/runtime-executor/common" } +sc-executor-polkavm = { path = "substrate/runtime-executor/polkavm" } +sc-executor-wasmtime = { path = "substrate/runtime-executor/wasmtime" } +sc-mixnet = { path = "substrate/sc-mixnet", default-features = false } +sc-consensus-grandpa = { version = "0.30.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-consensus-grandpa-rpc = { version = "0.30.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-network = { version = "0.45.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-network-sync = { version = "0.44.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-network-types = { version = "0.12.1", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-offchain = { version = "40.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-proposer-metrics = { version = "0.18.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-service = { version = "0.46.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-telemetry = { version = "25.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-rpc = { version = "40.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-runtime-test = { version = "2.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-sync-state-rpc = { version = "0.45.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-sysinfo = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-transaction-pool = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-transaction-pool-api = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sc-tracing = { version = "37.0.1", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-allocator = { path = "substrate/sp-allocator", default-features = false } +sp-api = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-authority-discovery = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-arithmetic = { version = "26.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-blockchain = { version = "37.0.1", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-block-builder = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-core = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-consensus = { version = "0.40.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-consensus-babe = { version = "0.40.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-consensus-slots = { version = "0.40.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-application-crypto = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-externalities = { version = "0.29.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-consensus-grandpa = { version = "21.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-genesis-builder = { version = "0.15.1", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-inherents = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-io = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-keyring = { version = "39.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-keystore = { version = "0.40.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-maybe-compressed-blob = { version = "11.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-mixnet = { version = "0.12.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-npos-elections = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-offchain = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-rpc = { version = "32.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-runtime = { version = "39.0.1", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-runtime-interface = { version = "28.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-session = { version = "36.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-std = { version = "14.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-state-machine = { version = "0.43.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-staking = { version = "36.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-storage = { version = "21.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-timestamp = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-tracing = { version = "17.0.1", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-transaction-pool = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-transaction-storage-proof = { version = "34.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-trie = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-version = { version = "37.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false } +sp-wasm-interface = { path = "substrate/sp-wasm-interface", default-features = false } +sp-panic-handler = { version = "13.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-wasm-interface-common = { path = "substrate/sp-wasm-interface-common", default-features = false } +substrate-build-script-utils = { version = "11.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +substrate-frame-rpc-system = { version = "39.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +substrate-rpc-client = { version = "0.44.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +substrate-state-trie-migration-rpc = { version = "38.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +substrate-test-client = { version = "2.0.0", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +substrate-wasm-builder = { path = "substrate/substrate-wasm-builder" } # Examples test-syscalls = { path = "sdk/examples/syscalls", default-features = false } @@ -587,7 +627,9 @@ tower = "0.4.13" # ethexe/rpc tower-http = "0.5.2" # ethexe/rpc tracing-appender = "0.2" # vara/tools/node-loader trybuild = "1" # sdk/gstd/codegen +wasm-opt = "0.116" # substrate-wasm-builder wasmprinter = "0.230" # protocol/wasm-gen +walkdir = "2.5.0" # substrate-wasm-builder fail = "0.5" # gear-common heck = "0.5.0" # gsdk-api-gen etc = "0.1.19" # vara/sdk/gcli @@ -601,6 +643,7 @@ wasm-smith = { version = "0.230", features = ["wasmparser"] } # protocol/wasm-ge wasm-encoder = { version = "0.230", default-features = false, features = [ "wasmparser", ] } # protocol/wasm-instrument +wasm-instrument = { version = "0.4.0", default-features = false } # sc-executor-common async-broadcast = "0.7.2" # ethexe/service ip_network = "0.4.1" # ethexe/network @@ -609,6 +652,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(fuzz)', 'cfg(loom)', 'cfg(substrate_runtime)', + 'cfg(build_type, values("debug"))', ] } [workspace.metadata.cargo-shear] @@ -627,6 +671,9 @@ ignored = [ "ethexe-sdk", ] +[profile.dev.package.wasmtime-internal-cranelift] +opt-level = 3 + [profile.release] panic = "unwind" @@ -665,8 +712,17 @@ core2 = { git = "https://github.com/bbqsrc/core2", rev = "545e84bcb0f235b12e2135 # these patched dependecies force their `sign_ext` feature to be used by Substrate dependencies parity-wasm = { version = "0.45.0", git = "https://github.com/gear-tech/parity-wasm", branch = "v0.45.0-sign-ext" } -wasmi-validation = { version = "0.5.0", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext" } wasm-instrument = { version = "0.4.0", git = "https://github.com/gear-tech/wasm-instrument", branch = "v0.4.0-sign-ext" } # there are patches to disable `memory.grow` and to add offset of reserved memory wasm-smith = { version = "0.230", git = "https://github.com/gear-tech/wasm-tools", branch = "gear-stable-1.230" } + +[patch."https://github.com/paritytech/polkadot-sdk.git"] +sc-executor = { path = "substrate/runtime-executor" } +sc-executor-common = { path = "substrate/runtime-executor/common" } +sc-executor-polkavm = { path = "substrate/runtime-executor/polkavm" } +sc-executor-wasmtime = { path = "substrate/runtime-executor/wasmtime" } +sc-mixnet = { path = "substrate/sc-mixnet" } +sp-runtime-interface-proc-macro = { path = "substrate/sp-runtime-interface-proc-macro" } +sp-wasm-interface = { path = "substrate/sp-wasm-interface" } +substrate-wasm-builder = { path = "substrate/substrate-wasm-builder" } diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 00000000000..cabf140e2c4 --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,25 @@ +# Third-Party Notices + +## Polkadot SDK Copied Sources + +Some local crates contain copied or modified source files from `paritytech/polkadot-sdk`: + +- `substrate/sp-allocator` (`sp-allocator`, published by Gear as `gsp-allocator`; derived from upstream `sc-allocator` through the Gear Polkadot SDK fork) +- `substrate/runtime-executor/common` (`sc-executor-common`, published by Gear as `gsc-executor-common`) +- `substrate/runtime-executor/polkavm` (`sc-executor-polkavm`, published by Gear as `gsc-executor-polkavm`) +- `substrate/runtime-executor/wasmtime` (`sc-executor-wasmtime`, published by Gear as `gsc-executor-wasmtime`) +- `substrate/runtime-executor` (`sc-executor`, not published by Gear) +- `substrate/substrate-wasm-builder` (`substrate-wasm-builder`, published by Gear as `gsubstrate-wasm-builder`) + +Source reference: + +`substrate/sp-allocator` was sourced from the Gear Polkadot SDK fork `gear-polkadot-stable2409-wasm32v1-none` at `1d1b394647eb26c094cf50c759b900dc5faa3b80`, derived from Parity Polkadot SDK `sc-allocator`. + +These copied source files retain the upstream copyright notices and their original SPDX headers. See [`substrate/README.md`](substrate/README.md) for the shared fork, provenance, and publishing notice. + +Related Gear-authored compatibility crate: `substrate/sp-wasm-interface-common` keeps the upstream-compatible local package name `sp-wasm-interface-common` and is published by Gear as `gsp-wasm-interface-common`, but its source files are not copied Polkadot SDK source. + +Additional third-party file: `substrate/runtime-executor/wasmtime/src/test-guard-page-skip.wat` is a modified WebAssembly testsuite fixture from , licensed under Apache-2.0. + +Apache-2.0 license text: +GPL-3.0-or-later WITH Classpath-exception-2.0 license text: [`LICENSE`](LICENSE) diff --git a/ethexe/malachite/core/src/context.rs b/ethexe/malachite/core/src/context.rs index c2b0e8e120d..85b11a35b0f 100644 --- a/ethexe/malachite/core/src/context.rs +++ b/ethexe/malachite/core/src/context.rs @@ -218,7 +218,7 @@ impl malachitebft_core_types::ValidatorSet for ValidatorSet { #[derive(Clone, Debug, PartialEq, Eq)] pub struct Vote { - pub typ: VoteType, + pub vote_type: VoteType, pub height: Height, pub round: Round, pub value: NilOrVal, @@ -231,7 +231,7 @@ pub struct Vote { impl Encode for Vote { fn encode_to(&self, dest: &mut W) { - encode_vote_type_to(self.typ, dest); + encode_vote_type_to(self.vote_type, dest); self.height.as_u64().encode_to(dest); encode_round_to(self.round, dest); encode_nil_or_val_value_id_to(&self.value, dest); @@ -241,13 +241,13 @@ impl Encode for Vote { impl Decode for Vote { fn decode(input: &mut I) -> Result { - let typ = decode_vote_type(input)?; + let vote_type = decode_vote_type(input)?; let height = Height::new(u64::decode(input)?); let round = decode_round(input)?; let value = decode_nil_or_val_value_id(input)?; let validator_address = decode_address(input)?; Ok(Self { - typ, + vote_type, height, round, value, @@ -265,7 +265,7 @@ impl Vote { validator_address: Address, ) -> Self { Self { - typ: VoteType::Prevote, + vote_type: VoteType::Prevote, height, round, value, @@ -281,7 +281,7 @@ impl Vote { validator_address: Address, ) -> Self { Self { - typ: VoteType::Precommit, + vote_type: VoteType::Precommit, height, round, value, @@ -317,7 +317,7 @@ impl malachitebft_core_types::Vote for Vote { } fn vote_type(&self) -> VoteType { - self.typ + self.vote_type } fn validator_address(&self) -> &Address { diff --git a/ethexe/processor/Cargo.toml b/ethexe/processor/Cargo.toml index fb2b8515c2e..a297ce8b2e2 100644 --- a/ethexe/processor/Cargo.toml +++ b/ethexe/processor/Cargo.toml @@ -25,7 +25,7 @@ core-processor.workspace = true futures.workspace = true thiserror.workspace = true -wasmtime.workspace = true +wasmtime = { workspace = true, features = ["cache", "cranelift", "parallel-compilation", "runtime"] } log.workspace = true parity-scale-codec = { workspace = true, features = ["std", "derive"] } sp-allocator = { workspace = true, features = ["std"] } diff --git a/protocol/sandbox/Cargo.toml b/protocol/sandbox/Cargo.toml index 88c7cfb152a..23cb3c51ff8 100644 --- a/protocol/sandbox/Cargo.toml +++ b/protocol/sandbox/Cargo.toml @@ -24,7 +24,7 @@ gear-sandbox-interface.workspace = true gear-sandbox-env.workspace = true # embedded executor only -wasmtime = { workspace = true, optional = true } +wasmtime = { features = ["cache", "runtime", "winch"], workspace = true, optional = true } gear-wasmtime-cache = { workspace = true, optional = true } gear-workspace-hack.workspace = true diff --git a/protocol/sandbox/host/Cargo.toml b/protocol/sandbox/host/Cargo.toml index 225e407dd71..7cf703adf93 100644 --- a/protocol/sandbox/host/Cargo.toml +++ b/protocol/sandbox/host/Cargo.toml @@ -21,7 +21,7 @@ defer.workspace = true environmental.workspace = true thiserror.workspace = true log = { workspace = true, features = ["std"] } -wasmtime.workspace = true +wasmtime = { features = ["cache", "runtime", "winch"], workspace = true } wasmi.workspace = true sp-allocator = { workspace = true, features = ["std"] } sp-wasm-interface-common = { workspace = true, features = ["std"] } diff --git a/protocol/sandbox/src/embedded_executor.rs b/protocol/sandbox/src/embedded_executor.rs index 33ebe5c233a..b99406d94ec 100644 --- a/protocol/sandbox/src/embedded_executor.rs +++ b/protocol/sandbox/src/embedded_executor.rs @@ -60,7 +60,6 @@ impl SandboxStore for Store { let mut config = Config::new(); config .max_wasm_stack(16 * 1024 * 1024) // make stack size bigger for fuzzer - .async_stack_size(16 * 1024 * 1024) .strategy(wasmtime::Strategy::Winch) .cache(Some(cache)) // Keep sandbox traps on Unix signals on macOS: Gear lazy-pages diff --git a/protocol/wasmtime-cache/Cargo.toml b/protocol/wasmtime-cache/Cargo.toml index dc45c079d46..5b4e32cdb7e 100644 --- a/protocol/wasmtime-cache/Cargo.toml +++ b/protocol/wasmtime-cache/Cargo.toml @@ -16,7 +16,7 @@ workspace = true [dependencies] tracing.workspace = true lru.workspace = true -wasmtime.workspace = true +wasmtime = { features = ["cache", "runtime"], workspace = true } gear-core.workspace = true gear-workspace-hack.workspace = true diff --git a/scripts/check-license-headers.sh b/scripts/check-license-headers.sh index 243d33c3d85..1499959a0f3 100755 --- a/scripts/check-license-headers.sh +++ b/scripts/check-license-headers.sh @@ -13,7 +13,50 @@ set -euo pipefail ROOT="${1:-.}" -SPDX="// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0" +GEAR_SPDX="// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0" +APACHE_SPDX="// SPDX-License-Identifier: Apache-2.0" + +expected_spdx_for() { + case "$1" in + substrate/sp-wasm-interface-common/src/util.rs) + printf '%s\n' "$GEAR_SPDX" + ;; + substrate/sp-allocator/* | \ + substrate/sp-runtime-interface-proc-macro/* | \ + substrate/sp-wasm-interface/* | \ + substrate/sp-wasm-interface-common/* | \ + substrate/substrate-wasm-builder/*) + printf '%s\n' "$APACHE_SPDX" + ;; + *) + printf '%s\n' "$GEAR_SPDX" + ;; + esac +} + +copyright_pattern_for() { + case "$1" in + substrate/sp-wasm-interface-common/src/util.rs) + printf '%s\n' '^// Copyright' + ;; + substrate/runtime-executor/wasmtime/src/host_state.rs | \ + substrate/runtime-executor/wasmtime/src/memory_wrapper.rs | \ + substrate/runtime-executor/wasmtime/src/store_data.rs) + printf '%s\n' '^// Copyright' + ;; + substrate/runtime-executor/* | \ + substrate/sp-allocator/* | \ + substrate/sp-runtime-interface-proc-macro/* | \ + substrate/sp-wasm-interface/* | \ + substrate/sp-wasm-interface-common/* | \ + substrate/substrate-wasm-builder/*) + printf '%s\n' '^// Copyright [(]C[)]( [0-9]{4}(-[0-9]{4})?)? Parity Technologies' + ;; + *) + printf '%s\n' '^// Copyright' + ;; + esac +} ISSUES=$(mktemp) trap "rm -f '$ISSUES'" EXIT @@ -27,14 +70,17 @@ git -C "$ROOT" ls-files -z '*.rs' \ # ── 2-4. Per-file SPDX checks (awk reads each file once) ───────────────────── while IFS= read -r -d '' file; do - awk -v spdx="$SPDX" -v f="$ROOT/$file" ' + spdx=$(expected_spdx_for "$file") + copyright=$(copyright_pattern_for "$file") + + awk -v spdx="$spdx" -v copyright="$copyright" -v f="$ROOT/$file" ' { prev = cur; cur = $0 } cur ~ /SPDX-License-Identifier/ { if (cur != spdx) { - print "wrong SPDX value: " f + print "wrong SPDX value: " f " (expected: " spdx ")" } else { - if (prev !~ /^\/\/ Copyright/) + if (prev !~ copyright) print "no Copyright line above SPDX: " f getline nxt if (nxt !~ /^[[:space:]]*$/ && nxt != "") diff --git a/scripts/src/clippy.sh b/scripts/src/clippy.sh index 5b09a6b16c5..be803fc0b50 100755 --- a/scripts/src/clippy.sh +++ b/scripts/src/clippy.sh @@ -30,7 +30,7 @@ examples_clippy() { # find crates that use "gear-wasm-builder" mapfile -t examples < <( cargo metadata --no-deps --format-version=1 | - jq -r '.packages.[] | select(.manifest_path | contains("gear/sdk/examples")) | select(.dependencies.[].name == "gear-wasm-builder") | "-p=" + .name' + jq -r '.workspace_root as $root | .packages.[] | select(.manifest_path | startswith($root + "/sdk/examples/")) | select(any(.dependencies.[]; .name == "gear-wasm-builder")) | "-p=" + .name' ) # clippy will try to link "test" crate which is not available for "wasm32v1-none" target mapfile -t filtered_args < <(printf "%s\n" "${@}" | grep -v "all-targets") @@ -42,10 +42,10 @@ examples_clippy() { no_std_clippy() { mapfile -t no_std < <( cargo metadata --no-deps --format-version=1 | - jq -r '.packages.[] | select(.features | index("std")) | "-p=" + .name' + jq -r '.workspace_members as $members | .packages.[] | . as $pkg | select($members | index($pkg.id)) | select(.features | has("std")) | select(.name != "sc-executor") | "-p=" + .name' ) RUSTFLAGS="--cfg=substrate_runtime" \ __GEAR_WASM_BUILDER_NO_BUILD=1 \ SKIP_WASM_BUILD=1 \ - cargo clippy "${no_std[@]}" "$@" --no-default-features --target=wasm32v1-none -- -D warnings + cargo clippy "${no_std[@]}" "$@" --no-default-features --target=wasm32v1-none -- --no-deps -D warnings } diff --git a/scripts/src/common.sh b/scripts/src/common.sh index 6038f81558f..a8082bb6a8a 100644 --- a/scripts/src/common.sh +++ b/scripts/src/common.sh @@ -1,13 +1,19 @@ #!/usr/bin/env sh bold() { - tput bold + if [ -t 1 ] && [ -n "${TERM:-}" ]; then + tput bold || true + fi } normal() { - tput sgr0 + if [ -t 1 ] && [ -n "${TERM:-}" ]; then + tput sgr0 || true + fi } header() { - bold && printf "\n >> $1\n" && normal + bold + printf "\n >> %s\n" "$1" + normal } diff --git a/sdk/cargo-gbuild/test-program/Cargo.toml b/sdk/cargo-gbuild/test-program/Cargo.toml index dd103e4376f..b29954b8b10 100644 --- a/sdk/cargo-gbuild/test-program/Cargo.toml +++ b/sdk/cargo-gbuild/test-program/Cargo.toml @@ -22,3 +22,7 @@ members = ["foo", "bar"] [workspace.metadata.gbuild] programs = ["foo", "bar"] + +[patch."https://github.com/paritytech/polkadot-sdk.git"] +sp-runtime-interface-proc-macro = { path = "../../../substrate/sp-runtime-interface-proc-macro" } +sp-wasm-interface = { path = "../../../substrate/sp-wasm-interface" } diff --git a/sdk/examples/async-critical/Cargo.toml b/sdk/examples/async-critical/Cargo.toml index 8f28aa08ac4..729f3a8c1ac 100644 --- a/sdk/examples/async-critical/Cargo.toml +++ b/sdk/examples/async-critical/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async-custom-entry/Cargo.toml b/sdk/examples/async-custom-entry/Cargo.toml index 8c39a51c75f..63390e433a1 100644 --- a/sdk/examples/async-custom-entry/Cargo.toml +++ b/sdk/examples/async-custom-entry/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async-init/Cargo.toml b/sdk/examples/async-init/Cargo.toml index 1b8cb712ef1..d9452d70704 100644 --- a/sdk/examples/async-init/Cargo.toml +++ b/sdk/examples/async-init/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true futures.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -21,3 +20,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async-recursion/Cargo.toml b/sdk/examples/async-recursion/Cargo.toml index 222f2bc2062..39c6f9d46a1 100644 --- a/sdk/examples/async-recursion/Cargo.toml +++ b/sdk/examples/async-recursion/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true async-recursion.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async-reply-hook/Cargo.toml b/sdk/examples/async-reply-hook/Cargo.toml index 61782a657c6..80587593fe7 100644 --- a/sdk/examples/async-reply-hook/Cargo.toml +++ b/sdk/examples/async-reply-hook/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async-signal-entry/Cargo.toml b/sdk/examples/async-signal-entry/Cargo.toml index 98fdcd2fb38..4538d508e73 100644 --- a/sdk/examples/async-signal-entry/Cargo.toml +++ b/sdk/examples/async-signal-entry/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async-tester/Cargo.toml b/sdk/examples/async-tester/Cargo.toml index c97a07d09a2..da30c4b19ca 100644 --- a/sdk/examples/async-tester/Cargo.toml +++ b/sdk/examples/async-tester/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/async/Cargo.toml b/sdk/examples/async/Cargo.toml index 9e023cfe791..0630621f2cb 100644 --- a/sdk/examples/async/Cargo.toml +++ b/sdk/examples/async/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/autoreply/Cargo.toml b/sdk/examples/autoreply/Cargo.toml index 5c50b95d45a..d007870e97e 100644 --- a/sdk/examples/autoreply/Cargo.toml +++ b/sdk/examples/autoreply/Cargo.toml @@ -7,7 +7,6 @@ license.workspace = true [dependencies] gstd = { workspace = true, features = ["debug"] } -gear-workspace-hack.workspace = true [dev-dependencies] gtest.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/big-data-section/Cargo.toml b/sdk/examples/big-data-section/Cargo.toml index 3da8776194d..479c4b86224 100644 --- a/sdk/examples/big-data-section/Cargo.toml +++ b/sdk/examples/big-data-section/Cargo.toml @@ -14,7 +14,6 @@ workspace = true [dependencies] gstd = { workspace = true, features = ["debug"] } parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [dev-dependencies] gtest.workspace = true @@ -27,3 +26,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/bls381/Cargo.toml b/sdk/examples/bls381/Cargo.toml index 5940cbd1d37..c08d0bada60 100644 --- a/sdk/examples/bls381/Cargo.toml +++ b/sdk/examples/bls381/Cargo.toml @@ -12,7 +12,6 @@ parity-scale-codec = { workspace = true, features = ["derive"] } gstd = { workspace = true, features = ["debug"] } gbuiltin-bls381.workspace = true hex-literal.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true [features] default = ["std"] std = ["parity-scale-codec/std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/calc-hash/Cargo.toml b/sdk/examples/calc-hash/Cargo.toml index 78f523a65f0..3a16dc30a18 100644 --- a/sdk/examples/calc-hash/Cargo.toml +++ b/sdk/examples/calc-hash/Cargo.toml @@ -10,6 +10,8 @@ repository.workspace = true [dependencies] parity-scale-codec.workspace = true sha2.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/calc-hash/in-one-block/Cargo.toml b/sdk/examples/calc-hash/in-one-block/Cargo.toml index 508c829461d..49ca72129db 100644 --- a/sdk/examples/calc-hash/in-one-block/Cargo.toml +++ b/sdk/examples/calc-hash/in-one-block/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true shared = { path = "..", package = "demo-calc-hash" } -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = [ "std" ] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/calc-hash/over-blocks/Cargo.toml b/sdk/examples/calc-hash/over-blocks/Cargo.toml index 9016b9e674d..525ae53ccbe 100644 --- a/sdk/examples/calc-hash/over-blocks/Cargo.toml +++ b/sdk/examples/calc-hash/over-blocks/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true shared = { path = "../", package = "demo-calc-hash" } -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/compose/Cargo.toml b/sdk/examples/compose/Cargo.toml index e7d967bc5e4..213b4ad44e2 100644 --- a/sdk/examples/compose/Cargo.toml +++ b/sdk/examples/compose/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true hex.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/constructor/Cargo.toml b/sdk/examples/constructor/Cargo.toml index 2673c4bea91..6f4437e0885 100644 --- a/sdk/examples/constructor/Cargo.toml +++ b/sdk/examples/constructor/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gcore.workspace = true gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -21,3 +20,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/create-program-reentrance/Cargo.toml b/sdk/examples/create-program-reentrance/Cargo.toml index b0a22b639b7..9dcc6b988a2 100644 --- a/sdk/examples/create-program-reentrance/Cargo.toml +++ b/sdk/examples/create-program-reentrance/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true hex.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/ctor/Cargo.toml b/sdk/examples/ctor/Cargo.toml index 004deaf1410..ef36a48c6c4 100644 --- a/sdk/examples/ctor/Cargo.toml +++ b/sdk/examples/ctor/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [dev-dependencies] gtest.workspace = true @@ -22,3 +21,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/custom/Cargo.toml b/sdk/examples/custom/Cargo.toml index d5493388c51..cc2b38267bd 100644 --- a/sdk/examples/custom/Cargo.toml +++ b/sdk/examples/custom/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true gsys.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [dev-dependencies] gtest.workspace = true @@ -23,3 +22,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/delayed-reservation-sender/Cargo.toml b/sdk/examples/delayed-reservation-sender/Cargo.toml index 6a02d59a243..70c084f0ca0 100644 --- a/sdk/examples/delayed-reservation-sender/Cargo.toml +++ b/sdk/examples/delayed-reservation-sender/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/delayed-sender-ethexe/Cargo.toml b/sdk/examples/delayed-sender-ethexe/Cargo.toml index 79d89e00141..e893573e6d3 100644 --- a/sdk/examples/delayed-sender-ethexe/Cargo.toml +++ b/sdk/examples/delayed-sender-ethexe/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ wasm-wrapper = [] std = ["wasm-wrapper"] default = ["std"] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/delayed-sender/Cargo.toml b/sdk/examples/delayed-sender/Cargo.toml index 0662cb99565..dbbafa22afc 100644 --- a/sdk/examples/delayed-sender/Cargo.toml +++ b/sdk/examples/delayed-sender/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/distributor/Cargo.toml b/sdk/examples/distributor/Cargo.toml index 40b17181234..b92c561dc05 100644 --- a/sdk/examples/distributor/Cargo.toml +++ b/sdk/examples/distributor/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -23,3 +22,6 @@ gtest.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/fungible-token/Cargo.toml b/sdk/examples/fungible-token/Cargo.toml index e6cbbd13e95..78b31720275 100644 --- a/sdk/examples/fungible-token/Cargo.toml +++ b/sdk/examples/fungible-token/Cargo.toml @@ -12,7 +12,6 @@ gstd.workspace = true hashbrown.workspace = true parity-scale-codec.workspace = true scale-info.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -21,3 +20,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/futures-unordered/Cargo.toml b/sdk/examples/futures-unordered/Cargo.toml index 0218e81d008..f1b118bd750 100644 --- a/sdk/examples/futures-unordered/Cargo.toml +++ b/sdk/examples/futures-unordered/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true futures = { workspace = true, features = ["async-await"] } -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/gas-burned/Cargo.toml b/sdk/examples/gas-burned/Cargo.toml index 498f7a43d9b..8aa1af85fe9 100644 --- a/sdk/examples/gas-burned/Cargo.toml +++ b/sdk/examples/gas-burned/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -21,3 +20,6 @@ log.workspace = true [features] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/incomplete-async-payloads/Cargo.toml b/sdk/examples/incomplete-async-payloads/Cargo.toml index 13112a508dc..1f45edca031 100644 --- a/sdk/examples/incomplete-async-payloads/Cargo.toml +++ b/sdk/examples/incomplete-async-payloads/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/inheritor-in-error-reply/Cargo.toml b/sdk/examples/inheritor-in-error-reply/Cargo.toml index 435c8412b92..024abffd88c 100644 --- a/sdk/examples/inheritor-in-error-reply/Cargo.toml +++ b/sdk/examples/inheritor-in-error-reply/Cargo.toml @@ -8,7 +8,6 @@ license.workspace = true [dependencies] gstd = { workspace = true, features = ["debug"] } parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [dev-dependencies] gear-core.workspace = true @@ -21,3 +20,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/init-fail-sender/Cargo.toml b/sdk/examples/init-fail-sender/Cargo.toml index 17dc018dc87..b72b9f404d9 100644 --- a/sdk/examples/init-fail-sender/Cargo.toml +++ b/sdk/examples/init-fail-sender/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/init-wait-reply-exit/Cargo.toml b/sdk/examples/init-wait-reply-exit/Cargo.toml index aa2bb264c4a..fe9aa46ab85 100644 --- a/sdk/examples/init-wait-reply-exit/Cargo.toml +++ b/sdk/examples/init-wait-reply-exit/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/init-wait/Cargo.toml b/sdk/examples/init-wait/Cargo.toml index 7d874f21c99..d339b18ad5a 100644 --- a/sdk/examples/init-wait/Cargo.toml +++ b/sdk/examples/init-wait/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/messenger/Cargo.toml b/sdk/examples/messenger/Cargo.toml index d2823d78ced..594512a86fa 100644 --- a/sdk/examples/messenger/Cargo.toml +++ b/sdk/examples/messenger/Cargo.toml @@ -7,7 +7,6 @@ edition.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -15,3 +14,6 @@ gear-wasm-builder.workspace = true [features] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/mul-by-const/Cargo.toml b/sdk/examples/mul-by-const/Cargo.toml index fce4c01a3ba..dedbd9c5eb8 100644 --- a/sdk/examples/mul-by-const/Cargo.toml +++ b/sdk/examples/mul-by-const/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true hex.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/ncompose/Cargo.toml b/sdk/examples/ncompose/Cargo.toml index 3cf760abab4..cc332c0550f 100644 --- a/sdk/examples/ncompose/Cargo.toml +++ b/sdk/examples/ncompose/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true hex.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/node/Cargo.toml b/sdk/examples/node/Cargo.toml index 5d4fa5a9173..548556440b0 100644 --- a/sdk/examples/node/Cargo.toml +++ b/sdk/examples/node/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -23,3 +22,6 @@ gtest.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/out-of-memory/Cargo.toml b/sdk/examples/out-of-memory/Cargo.toml index bfc4c932038..e5b77da7de0 100644 --- a/sdk/examples/out-of-memory/Cargo.toml +++ b/sdk/examples/out-of-memory/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd = { workspace = true, features = ["oom-handler"] } -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/panic-payload/Cargo.toml b/sdk/examples/panic-payload/Cargo.toml index 9373b6cb214..6197adebe09 100644 --- a/sdk/examples/panic-payload/Cargo.toml +++ b/sdk/examples/panic-payload/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [dev-dependencies] gear-core.workspace = true @@ -23,3 +22,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/piggy-bank/Cargo.toml b/sdk/examples/piggy-bank/Cargo.toml index ae04bf2c482..9f707f33e0b 100644 --- a/sdk/examples/piggy-bank/Cargo.toml +++ b/sdk/examples/piggy-bank/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/ping/Cargo.toml b/sdk/examples/ping/Cargo.toml index 4350063695a..a1d1a7ef5c9 100644 --- a/sdk/examples/ping/Cargo.toml +++ b/sdk/examples/ping/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/program-factory/Cargo.toml b/sdk/examples/program-factory/Cargo.toml index c23a486ee40..51fa9d29e43 100644 --- a/sdk/examples/program-factory/Cargo.toml +++ b/sdk/examples/program-factory/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true hex-literal.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -23,3 +22,6 @@ gtest.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/program-generator/Cargo.toml b/sdk/examples/program-generator/Cargo.toml index eb3b34ceefd..79eb27184f5 100644 --- a/sdk/examples/program-generator/Cargo.toml +++ b/sdk/examples/program-generator/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true hex-literal.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/proxy-broker/Cargo.toml b/sdk/examples/proxy-broker/Cargo.toml index a3f24f8a2a9..9b892d00a26 100644 --- a/sdk/examples/proxy-broker/Cargo.toml +++ b/sdk/examples/proxy-broker/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gbuiltin-proxy.workspace = true gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/proxy-relay/Cargo.toml b/sdk/examples/proxy-relay/Cargo.toml index ac63b34072a..1cec1f81eaa 100644 --- a/sdk/examples/proxy-relay/Cargo.toml +++ b/sdk/examples/proxy-relay/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true scale-info.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std", "scale-info/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/proxy-reservation-with-gas/Cargo.toml b/sdk/examples/proxy-reservation-with-gas/Cargo.toml index 50523737f64..3a6e8d09cc0 100644 --- a/sdk/examples/proxy-reservation-with-gas/Cargo.toml +++ b/sdk/examples/proxy-reservation-with-gas/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true scale-info.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std", "scale-info/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/proxy/Cargo.toml b/sdk/examples/proxy/Cargo.toml index 571b7858a51..91768777ff6 100644 --- a/sdk/examples/proxy/Cargo.toml +++ b/sdk/examples/proxy/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true parity-scale-codec.workspace = true scale-info.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -21,3 +20,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper", "parity-scale-codec/std", "scale-info/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/read-big-state/Cargo.toml b/sdk/examples/read-big-state/Cargo.toml index 5b04ed9b02f..48b408571bc 100644 --- a/sdk/examples/read-big-state/Cargo.toml +++ b/sdk/examples/read-big-state/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper", "parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/reply-callback/Cargo.toml b/sdk/examples/reply-callback/Cargo.toml index fd52c91ff86..6834136f22e 100644 --- a/sdk/examples/reply-callback/Cargo.toml +++ b/sdk/examples/reply-callback/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ debug = ["gstd/debug"] default = ["std"] std = [] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/reservation-manager/Cargo.toml b/sdk/examples/reservation-manager/Cargo.toml index c1e96f112a3..983fabf30a1 100644 --- a/sdk/examples/reservation-manager/Cargo.toml +++ b/sdk/examples/reservation-manager/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true [features] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/reserve-gas/Cargo.toml b/sdk/examples/reserve-gas/Cargo.toml index 9f21f74f536..6174b228ac6 100644 --- a/sdk/examples/reserve-gas/Cargo.toml +++ b/sdk/examples/reserve-gas/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -23,3 +22,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper", "parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/rwlock/Cargo.toml b/sdk/examples/rwlock/Cargo.toml index d9d48b44794..b0dde070f14 100644 --- a/sdk/examples/rwlock/Cargo.toml +++ b/sdk/examples/rwlock/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd = { workspace = true, features = ["debug"] } parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true [features] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/send-from-reservation/Cargo.toml b/sdk/examples/send-from-reservation/Cargo.toml index c8eb2c156d0..a53c87c63b5 100644 --- a/sdk/examples/send-from-reservation/Cargo.toml +++ b/sdk/examples/send-from-reservation/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/signal-entry/Cargo.toml b/sdk/examples/signal-entry/Cargo.toml index d3233256b19..9f3b6ece98a 100644 --- a/sdk/examples/signal-entry/Cargo.toml +++ b/sdk/examples/signal-entry/Cargo.toml @@ -12,7 +12,6 @@ gcore.workspace = true gstd.workspace = true parity-scale-codec.workspace = true gear-core.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -25,3 +24,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper", "parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/stack-allocations/Cargo.toml b/sdk/examples/stack-allocations/Cargo.toml index b54bffec9b8..edeb403cd6e 100644 --- a/sdk/examples/stack-allocations/Cargo.toml +++ b/sdk/examples/stack-allocations/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [dev-dependencies] gtest.workspace = true @@ -24,3 +23,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/staking-broker/Cargo.toml b/sdk/examples/staking-broker/Cargo.toml index 16dbf9a72e5..bca48cede3d 100644 --- a/sdk/examples/staking-broker/Cargo.toml +++ b/sdk/examples/staking-broker/Cargo.toml @@ -13,7 +13,6 @@ gstd.workspace = true hashbrown.workspace = true hex-literal.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -22,3 +21,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/state-rollback/Cargo.toml b/sdk/examples/state-rollback/Cargo.toml index 5d288f38d0f..927c3b1cc67 100644 --- a/sdk/examples/state-rollback/Cargo.toml +++ b/sdk/examples/state-rollback/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/sync-duplicate/Cargo.toml b/sdk/examples/sync-duplicate/Cargo.toml index b0068e2eed9..33525b69f9e 100644 --- a/sdk/examples/sync-duplicate/Cargo.toml +++ b/sdk/examples/sync-duplicate/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/syscall-error/Cargo.toml b/sdk/examples/syscall-error/Cargo.toml index 4a06f3352c7..dc16dd06aa9 100644 --- a/sdk/examples/syscall-error/Cargo.toml +++ b/sdk/examples/syscall-error/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -21,3 +20,6 @@ gtest.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/syscalls-ethexe/Cargo.toml b/sdk/examples/syscalls-ethexe/Cargo.toml index 9b755530366..11d4b0b5d39 100644 --- a/sdk/examples/syscalls-ethexe/Cargo.toml +++ b/sdk/examples/syscalls-ethexe/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec = { workspace = true, features = ["derive"] } -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/syscalls/Cargo.toml b/sdk/examples/syscalls/Cargo.toml index 9f36914e3d7..0a6441febeb 100644 --- a/sdk/examples/syscalls/Cargo.toml +++ b/sdk/examples/syscalls/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["wasm-wrapper", "parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/value-sender-ethexe/Cargo.toml b/sdk/examples/value-sender-ethexe/Cargo.toml index b3de8ae37a2..6ee9341a8da 100644 --- a/sdk/examples/value-sender-ethexe/Cargo.toml +++ b/sdk/examples/value-sender-ethexe/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -19,3 +18,6 @@ debug = ["gstd/debug"] std = [] default = ["std"] ethexe = ["gstd/ethexe"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/value-sender/Cargo.toml b/sdk/examples/value-sender/Cargo.toml index 52ad016fccf..7a30c352ff1 100644 --- a/sdk/examples/value-sender/Cargo.toml +++ b/sdk/examples/value-sender/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/vec/Cargo.toml b/sdk/examples/vec/Cargo.toml index 440d2890464..1c5688cdda1 100644 --- a/sdk/examples/vec/Cargo.toml +++ b/sdk/examples/vec/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd = { workspace = true, features = ["debug"] } -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -17,3 +16,6 @@ gear-wasm-builder.workspace = true [features] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/wait-timeout/Cargo.toml b/sdk/examples/wait-timeout/Cargo.toml index b7baad4ae75..47c77b55985 100644 --- a/sdk/examples/wait-timeout/Cargo.toml +++ b/sdk/examples/wait-timeout/Cargo.toml @@ -11,7 +11,6 @@ repository.workspace = true gstd.workspace = true futures.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -20,3 +19,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = ["parity-scale-codec/std"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/wait/Cargo.toml b/sdk/examples/wait/Cargo.toml index 7ed0c41a47f..391914cb5d1 100644 --- a/sdk/examples/wait/Cargo.toml +++ b/sdk/examples/wait/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] default = ["std"] std = [] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/wait_wake/Cargo.toml b/sdk/examples/wait_wake/Cargo.toml index 1f5fc4e1d24..9554e5b0c9f 100644 --- a/sdk/examples/wait_wake/Cargo.toml +++ b/sdk/examples/wait_wake/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true [dependencies] gstd.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -22,3 +21,6 @@ gtest.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/waiter/Cargo.toml b/sdk/examples/waiter/Cargo.toml index a6bcccf1001..5a40d20117a 100644 --- a/sdk/examples/waiter/Cargo.toml +++ b/sdk/examples/waiter/Cargo.toml @@ -12,7 +12,6 @@ futures.workspace = true gstd.workspace = true gcore.workspace = true parity-scale-codec.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -27,3 +26,6 @@ debug = ["gstd/debug"] wasm-wrapper = [] std = ["parity-scale-codec/std", "wasm-wrapper"] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/waiting-proxy/Cargo.toml b/sdk/examples/waiting-proxy/Cargo.toml index 553a7d94e73..b9fd9a21297 100644 --- a/sdk/examples/waiting-proxy/Cargo.toml +++ b/sdk/examples/waiting-proxy/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true [dependencies] gstd.workspace = true -gear-workspace-hack.workspace = true [build-dependencies] gear-wasm-builder.workspace = true @@ -18,3 +17,6 @@ gear-wasm-builder.workspace = true debug = ["gstd/debug"] std = [] default = ["std"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gear-workspace-hack.workspace = true diff --git a/sdk/examples/wat/Cargo.toml b/sdk/examples/wat/Cargo.toml index 2d054989b56..80eb1ed8eae 100644 --- a/sdk/examples/wat/Cargo.toml +++ b/sdk/examples/wat/Cargo.toml @@ -12,4 +12,6 @@ hex.workspace = true wasmparser.workspace = true wat.workspace = true wasmprinter.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] gear-workspace-hack.workspace = true diff --git a/sdk/wasm-builder/src/crate_info.rs b/sdk/wasm-builder/src/crate_info.rs index d56d613ca9d..980dca0a049 100644 --- a/sdk/wasm-builder/src/crate_info.rs +++ b/sdk/wasm-builder/src/crate_info.rs @@ -5,6 +5,7 @@ use crate::{builder_error::BuilderError, multiple_crate_versions}; use anyhow::{Context, Result, ensure}; use cargo_metadata::{CrateType, Dependency, Metadata, MetadataCommand, Package}; use std::{collections::BTreeMap, path::Path}; +use toml::value::Table; /// Helper to get a crate info extracted from the `Cargo.toml`. #[derive(Debug, Default)] @@ -22,7 +23,7 @@ pub struct CrateInfo { /// Crate custom profiles pub profiles: BTreeMap, /// Workspace patches - pub patch: BTreeMap, + pub patch: Table, } impl CrateInfo { diff --git a/sdk/wasm-builder/src/wasm_project.rs b/sdk/wasm-builder/src/wasm_project.rs index 09f0df91f40..b54bc55b967 100644 --- a/sdk/wasm-builder/src/wasm_project.rs +++ b/sdk/wasm-builder/src/wasm_project.rs @@ -16,6 +16,26 @@ use toml::value::Table; const OPT_LEVEL: &str = "z"; +/// Strip path-based patches from the generated WASM sub-project manifest. +/// +/// The sub-project is written outside the workspace root, so workspace-relative +/// patch paths like local `substrate/` overrides cannot be resolved there. +fn remove_local_path_patches(patch: &mut Table) { + patch.retain(|_, section| { + let Some(entries) = section.as_table_mut() else { + return true; + }; + + entries.retain(|_, dependency| { + dependency + .as_table() + .is_none_or(|dependency| !dependency.contains_key("path")) + }); + + !entries.is_empty() + }); +} + /// Temporary project generated to build a WASM output. /// /// This project is required due to the cargo locking during build. @@ -203,6 +223,7 @@ impl WasmProject { if let Some(crates_io) = patch.get_mut("crates-io").and_then(|v| v.as_table_mut()) { crates_io.remove("gear-workspace-hack"); } + remove_local_path_patches(&mut patch); let mut cargo_toml = Table::new(); cargo_toml.insert("package".into(), package.into()); diff --git a/sdk/wasm-optimizer/src/cargo_command.rs b/sdk/wasm-optimizer/src/cargo_command.rs index e49c239704a..1ec844ab6b8 100644 --- a/sdk/wasm-optimizer/src/cargo_command.rs +++ b/sdk/wasm-optimizer/src/cargo_command.rs @@ -25,9 +25,8 @@ impl CargoCommand { let toolchain = Toolchain::try_from_rustup().expect("Failed to resolve toolchain version"); let rustc_version = rustc_version::version().expect("Failed to get rustc version"); let linker_plugin_lto = rustc_version.major == 1 && rustc_version.minor >= 91; - let allow_undefined = rustc_version.major == 1 && rustc_version.minor >= 96; - let mut rustc_flags = vec!["-Clink-arg=--import-memory"]; + let mut rustc_flags = vec!["-Clink-arg=--import-memory", "-Clink-arg=--allow-undefined"]; if linker_plugin_lto { rustc_flags.extend_from_slice(&[ @@ -42,14 +41,6 @@ impl CargoCommand { ]); } - if allow_undefined { - rustc_flags.extend_from_slice(&[ - // -C link-arg fixes this: https://github.com/rust-lang/rust/pull/149868 - "-C", - "link-arg=--allow-undefined", - ]); - } - CargoCommand { path: "rustup".to_string(), manifest_path: "Cargo.toml".into(), diff --git a/sdk/wasm-proc/Cargo.toml b/sdk/wasm-proc/Cargo.toml index 8f668d94395..e6738d2815b 100644 --- a/sdk/wasm-proc/Cargo.toml +++ b/sdk/wasm-proc/Cargo.toml @@ -19,3 +19,4 @@ tracing-subscriber.workspace = true gear-wasm-builder.workspace = true gear-wasm-instrument = { workspace = true, features = ["std"] } gear-workspace-hack.workspace = true +wasmparser.workspace = true diff --git a/sdk/wasm-proc/src/main.rs b/sdk/wasm-proc/src/main.rs index eacb3cdeb32..1eb50a58118 100644 --- a/sdk/wasm-proc/src/main.rs +++ b/sdk/wasm-proc/src/main.rs @@ -6,9 +6,10 @@ use gear_wasm_builder::{ code_validator::validate_program, optimize::{self, Optimizer}, }; -use gear_wasm_instrument::{Module, SyscallKind, TypeRef}; +use gear_wasm_instrument::SyscallKind; use std::{collections::HashSet, fs, path::PathBuf}; use tracing_subscriber::EnvFilter; +use wasmparser::{Parser as WasmParser, Payload, TypeRef}; const RT_ALLOWED_IMPORTS: [&str; 78] = [ // From `Allocator` (substrate/primitives/io/src/lib.rs) @@ -136,15 +137,7 @@ struct Args { fn check_rt_is_dev(path_to_wasm: &str, expected_to_be_dev: bool) -> Result<(), String> { let wasm = fs::read(path_to_wasm).map_err(|e| format!("Read error: {e}"))?; - let module = Module::new(&wasm).map_err(|e| format!("Deserialization error: {e}"))?; - - let is_dev = module - .custom_sections - .as_ref() - .iter() - .copied() - .flatten() - .any(|v| v.0 == "dev_runtime"); + let is_dev = has_custom_section(&wasm, "dev_runtime")?; match (expected_to_be_dev, is_dev) { (true, false) => Err(String::from("Runtime expected to be DEV, but it's NOT DEV")), @@ -155,20 +148,28 @@ fn check_rt_is_dev(path_to_wasm: &str, expected_to_be_dev: bool) -> Result<(), S fn check_rt_imports(path_to_wasm: &str, allowed_imports: &HashSet<&str>) -> Result<(), String> { let wasm = fs::read(path_to_wasm).map_err(|e| format!("Read error: {e}"))?; - let module = Module::new(&wasm).map_err(|e| format!("Deserialization error: {e}"))?; - let imports = module - .import_section - .as_ref() - .ok_or("Import section not found")?; - + let mut has_import_section = false; let mut unexpected_imports = vec![]; - for import in imports { - if matches!(import.ty, TypeRef::Func(_) if !allowed_imports.contains(&*import.name)) { - unexpected_imports.push(import.name.clone()); + for payload in WasmParser::new(0).parse_all(&wasm) { + if let Payload::ImportSection(section) = + payload.map_err(|e| format!("Deserialization error: {e}"))? + { + has_import_section = true; + + for import in section { + let import = import.map_err(|e| format!("Deserialization error: {e}"))?; + if matches!(import.ty, TypeRef::Func(_) if !allowed_imports.contains(import.name)) { + unexpected_imports.push(import.name.to_string()); + } + } } } + if !has_import_section { + return Err(String::from("Import section not found")); + } + if !unexpected_imports.is_empty() { return Err(format!( "Unexpected imports found: {}", @@ -180,6 +181,19 @@ fn check_rt_imports(path_to_wasm: &str, allowed_imports: &HashSet<&str>) -> Resu Ok(()) } +fn has_custom_section(wasm: &[u8], expected_section: &str) -> Result { + for payload in WasmParser::new(0).parse_all(wasm) { + if let Payload::CustomSection(section) = + payload.map_err(|e| format!("Deserialization error: {e}"))? + && section.name() == expected_section + { + return Ok(true); + } + } + + Ok(false) +} + fn main() -> Result<(), Box> { let Args { path: wasm_files, diff --git a/substrate/README.md b/substrate/README.md new file mode 100644 index 00000000000..907448d0cc5 --- /dev/null +++ b/substrate/README.md @@ -0,0 +1,29 @@ +# Gear-maintained Polkadot SDK crates + +This directory contains selected Polkadot SDK crates copied into the Gear workspace from Polkadot SDK `stable2409`, source reference [`298f676c91d64f15f38ea7fd78f125c5889ab09c`](https://github.com/paritytech/polkadot-sdk/tree/298f676c91d64f15f38ea7fd78f125c5889ab09c), plus Gear-local compatibility crates needed to isolate the remaining fork delta. + +Copied crates are modified under the terms of their upstream open-source licenses. Original SPDX headers and upstream copyright notices remain in the copied source files; original copyright ownership remains with the upstream rightsholders as indicated there, including Parity Technologies where present. Gear maintains local changes to isolate the remaining fork delta while the rest of the workspace depends on upstream Polkadot SDK. + +Local Cargo package names intentionally stay compatible with upstream package names so `[patch]` can replace Polkadot SDK git dependencies. When these crates are prepared for crates.io, Gear publishes them under `g*` aliases for Gear ecosystem packages. + +## Copied Polkadot SDK Crates + +| Local path | Upstream package | Gear publish name | License | +| --- | --- | --- | --- | +| `substrate/sp-allocator` | `sp-allocator`; derived from upstream `sc-allocator` | `gsp-allocator` | Apache-2.0 | +| `substrate/sp-wasm-interface` | `sp-wasm-interface` | `gsp-wasm-interface` | Apache-2.0 | +| `substrate/runtime-executor/common` | `sc-executor-common` | `gsc-executor-common` | GPL-3.0-or-later WITH Classpath-exception-2.0 | +| `substrate/runtime-executor/polkavm` | `sc-executor-polkavm` | `gsc-executor-polkavm` | GPL-3.0-or-later WITH Classpath-exception-2.0 | +| `substrate/runtime-executor/wasmtime` | `sc-executor-wasmtime` | `gsc-executor-wasmtime` | GPL-3.0-or-later WITH Classpath-exception-2.0 | +| `substrate/runtime-executor` | `sc-executor` | not published by Gear | GPL-3.0-or-later WITH Classpath-exception-2.0 | +| `substrate/substrate-wasm-builder` | `substrate-wasm-builder` | `gsubstrate-wasm-builder` | Apache-2.0 | + +## Gear Compatibility Crates + +| Local path | Upstream-compatible package name | Gear publish name | License | +| --- | --- | --- | --- | +| `substrate/sp-wasm-interface-common` | `sp-wasm-interface-common` | `gsp-wasm-interface-common` | Apache-2.0 | + +`substrate/sp-wasm-interface-common` is Gear-authored compatibility code, not copied upstream source. It keeps the upstream-compatible local package name so Gear can patch dependencies that previously resolved through the custom Polkadot SDK fork. + +Publishing is handled by Gear maintainers through `utils/crates-io`; this README only documents the fork and naming policy. diff --git a/substrate/runtime-executor/Cargo.toml b/substrate/runtime-executor/Cargo.toml new file mode 100644 index 00000000000..d1c5ee11e08 --- /dev/null +++ b/substrate/runtime-executor/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "sc-executor" +version = "0.40.1" +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true +description = "A crate that provides means of executing/dispatching calls into the runtime." +documentation = "https://docs.rs/sc-executor" +readme = "README.md" + +[lib] +name = "sc_executor" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +parking_lot = { workspace = true, default-features = true } +schnellru = { workspace = true } +tracing = { workspace = true, default-features = true } + +codec = { workspace = true, default-features = true } +sc-executor-common.workspace = true +sc-executor-common.default-features = true +sc-executor-polkavm.workspace = true +sc-executor-polkavm.default-features = true +sc-executor-wasmtime.workspace = true +sc-executor-wasmtime.default-features = true +sp-api.workspace = true +sp-api.default-features = true +sp-core.workspace = true +sp-core.default-features = true +sp-externalities.workspace = true +sp-externalities.default-features = true +sp-io.workspace = true +sp-io.default-features = true +sp-panic-handler.workspace = true +sp-panic-handler.default-features = true +sp-runtime-interface.workspace = true +sp-runtime-interface.default-features = true +sp-trie.workspace = true +sp-trie.default-features = true +sp-version.workspace = true +sp-version.default-features = true +sp-wasm-interface.workspace = true +sp-wasm-interface.default-features = true + +[features] +default = ["std"] +# This crate does not have `no_std` support, we just require this for tests +std = [ + "sp-api/std", + "sp-core/std", + "sp-externalities/std", + "sp-io/std", + "sp-runtime-interface/std", + "sp-trie/std", + "sp-version/std", + "sp-wasm-interface/std", +] +wasm-extern-trace = [] diff --git a/substrate/runtime-executor/README.md b/substrate/runtime-executor/README.md new file mode 100644 index 00000000000..e82b5bd8cfe --- /dev/null +++ b/substrate/runtime-executor/README.md @@ -0,0 +1,15 @@ +# sc-executor + +A crate that provides means of executing and dispatching calls into the runtime. + +Local Cargo package name: `sc-executor`. +Gear publish name: `gsc-executor`. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0. + +Source: Parity Polkadot SDK `stable2409` at `298f676c91d64f15f38ea7fd78f125c5889ab09c`. + +Copied source files retain the upstream SPDX headers and Parity Technologies copyright notices. Gear maintains local changes to isolate the remaining Polkadot SDK fork delta and publishes this crate under the `gsc-executor` package name for Gear ecosystem crates. + +GPL-3.0-or-later license text: . +Classpath exception 2.0 text: . diff --git a/substrate/runtime-executor/common/Cargo.toml b/substrate/runtime-executor/common/Cargo.toml new file mode 100644 index 00000000000..71817cc65d2 --- /dev/null +++ b/substrate/runtime-executor/common/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "sc-executor-common" +version = "0.35.0" +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true +description = "A set of common definitions that are needed for defining execution engines." +documentation = "https://docs.rs/sc-executor-common/" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +thiserror = { workspace = true } +wasm-instrument = { workspace = true, default-features = true } +sp-allocator.workspace = true +sp-allocator.default-features = true +sp-maybe-compressed-blob.workspace = true +sp-maybe-compressed-blob.default-features = true +sp-wasm-interface.workspace = true +sp-wasm-interface.default-features = true +polkavm = { workspace = true } + +[features] +default = [] diff --git a/substrate/runtime-executor/common/README.md b/substrate/runtime-executor/common/README.md new file mode 100644 index 00000000000..e9450e980b0 --- /dev/null +++ b/substrate/runtime-executor/common/README.md @@ -0,0 +1,15 @@ +# sc-executor-common + +A set of common definitions needed for execution engines. + +Local Cargo package name: `sc-executor-common`. +Gear publish name: `gsc-executor-common`. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0. + +Source: Parity Polkadot SDK `stable2409` at `298f676c91d64f15f38ea7fd78f125c5889ab09c`. + +Copied source files retain the upstream SPDX headers and Parity Technologies copyright notices. Gear maintains local changes to isolate the remaining Polkadot SDK fork delta and publishes this crate under the `gsc-executor-common` package name for Gear ecosystem crates. + +GPL-3.0-or-later license text: . +Classpath exception 2.0 text: . diff --git a/substrate/runtime-executor/common/src/error.rs b/substrate/runtime-executor/common/src/error.rs new file mode 100644 index 00000000000..2d675bd5a55 --- /dev/null +++ b/substrate/runtime-executor/common/src/error.rs @@ -0,0 +1,189 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Rust executor possible errors. + +/// Result type alias. +pub type Result = std::result::Result; + +/// Error type. +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error("Error calling api function: {0}")] + ApiError(Box), + + #[error("Method not found: '{0}'")] + MethodNotFound(String), + + #[error("On-chain runtime does not specify version")] + VersionInvalid, + + #[error("Externalities error")] + Externalities, + + #[error("Invalid index provided")] + InvalidIndex, + + #[error("Invalid type returned (should be u64)")] + InvalidReturn, + + #[error("Runtime panicked: {0}")] + RuntimePanicked(String), + + #[error("Invalid memory reference")] + InvalidMemoryReference, + + #[error("The runtime doesn't provide a global named `__heap_base` of type `i32`")] + HeapBaseNotFoundOrInvalid, + + #[error("The runtime must not have the `start` function defined")] + RuntimeHasStartFn, + + #[error("Other: {0}")] + Other(String), + + #[error(transparent)] + Allocator(#[from] sp_allocator::Error), + + #[error("Host function {0} execution failed with: {1}")] + FunctionExecution(String, String), + + #[error("No table exported by wasm blob")] + NoTable, + + #[error("No table entry with index {0} in wasm blob exported table")] + NoTableEntryWithIndex(u32), + + #[error("Table element with index {0} is not a function in wasm blob exported table")] + TableElementIsNotAFunction(u32), + + #[error("Table entry with index {0} in wasm blob is null")] + FunctionRefIsNull(u32), + + #[error(transparent)] + RuntimeConstruction(#[from] WasmError), + + #[error("Shared memory is not supported")] + SharedMemUnsupported, + + #[error("Imported globals are not supported yet")] + ImportedGlobalsUnsupported, + + #[error("initializer expression can have only up to 2 expressions in wasm 1.0")] + InitializerHasTooManyExpressions, + + #[error("Invalid initializer expression provided {0}")] + InvalidInitializerExpression(String), + + #[error("Execution aborted due to panic: {0}")] + AbortedDueToPanic(MessageWithBacktrace), + + #[error("Execution aborted due to trap: {0}")] + AbortedDueToTrap(MessageWithBacktrace), + + #[error("Output exceeds bounds of wasm memory")] + OutputExceedsBounds, +} + +impl From<&'static str> for Error { + fn from(err: &'static str) -> Error { + Error::Other(err.into()) + } +} + +impl From for Error { + fn from(err: String) -> Error { + Error::Other(err) + } +} + +/// Type for errors occurring during Wasm runtime construction. +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum WasmError { + #[error("Code could not be read from the state.")] + CodeNotFound, + + #[error("Failure to reinitialize runtime instance from snapshot.")] + ApplySnapshotFailed, + + /// Failure to erase the wasm memory. + /// + /// Depending on the implementation might mean failure of allocating memory. + #[error("Failure to erase the wasm memory: {0}")] + ErasingFailed(String), + + #[error("Wasm code failed validation.")] + InvalidModule, + + #[error("Wasm code could not be deserialized.")] + CantDeserializeWasm, + + #[error("The module does not export a linear memory named `memory`.")] + InvalidMemory, + + #[error("The number of heap pages requested is disallowed by the module.")] + InvalidHeapPages, + + /// Instantiation error. + #[error("{0}")] + Instantiation(String), + + /// Other error happened. + #[error("Other error happened while constructing the runtime: {0}")] + Other(String), +} + +impl From for WasmError { + fn from(error: polkavm::ProgramParseError) -> Self { + WasmError::Other(error.to_string()) + } +} + +impl From for WasmError { + fn from(error: polkavm::Error) -> Self { + WasmError::Other(error.to_string()) + } +} + +impl From for Error { + fn from(error: polkavm::Error) -> Self { + Error::Other(error.to_string()) + } +} + +/// An error message with an attached backtrace. +#[derive(Debug)] +pub struct MessageWithBacktrace { + /// The error message. + pub message: String, + + /// The backtrace associated with the error message. + pub backtrace: Option, +} + +impl std::fmt::Display for MessageWithBacktrace { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.write_str(&self.message)?; + if let Some(ref backtrace) = self.backtrace { + fmt.write_str("\nWASM backtrace:\n")?; + backtrace.backtrace_string.fmt(fmt)?; + } + + Ok(()) + } +} + +/// A WASM backtrace. +#[derive(Debug)] +pub struct Backtrace { + /// The string containing the backtrace. + pub backtrace_string: String, +} + +impl std::fmt::Display for Backtrace { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.write_str(&self.backtrace_string) + } +} diff --git a/substrate/runtime-executor/common/src/lib.rs b/substrate/runtime-executor/common/src/lib.rs new file mode 100644 index 00000000000..04944e9393d --- /dev/null +++ b/substrate/runtime-executor/common/src/lib.rs @@ -0,0 +1,16 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! A set of common definitions that are needed for defining execution engines. + +#![warn(missing_docs)] +#![deny(unused_crate_dependencies)] + +pub mod error; +pub mod runtime_blob; +pub mod util; +pub mod wasm_runtime; + +pub(crate) fn is_polkavm_enabled() -> bool { + std::env::var_os("SUBSTRATE_ENABLE_POLKAVM").is_some_and(|value| value == "1") +} diff --git a/substrate/runtime-executor/common/src/runtime_blob/mod.rs b/substrate/runtime-executor/common/src/runtime_blob/mod.rs new file mode 100644 index 00000000000..576a3aa963b --- /dev/null +++ b/substrate/runtime-executor/common/src/runtime_blob/mod.rs @@ -0,0 +1,37 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! This module allows for inspection and instrumentation, i.e. modifying the module to alter it's +//! structure or behavior, of a wasm module. +//! +//! ## Instrumentation +//! +//! In ideal world, there would be no instrumentation. However, in the real world the execution +//! engines we use are somewhat limited in their APIs or abilities. +//! +//! To give you some examples: +//! +//! We need to reset the globals because when we +//! execute the Substrate Runtime, we do not drop and create the instance anew, instead +//! we restore some selected parts of the state. +//! +//! - stack depth metering can be performed via instrumentation or deferred to the engine and say be +//! added directly in machine code. Implementing this in machine code is rather cumbersome so +//! instrumentation looks like a good solution. +//! +//! Stack depth metering is needed to make a wasm blob +//! execution deterministic, which in turn is needed by the Parachain Validation Function in +//! Polkadot. +//! +//! ## Inspection +//! +//! Inspection of a wasm module may be needed to extract some useful information, such as to extract +//! data segment snapshot, which is helpful for quickly restoring the initial state of instances. +//! Inspection can be also useful to prove that a wasm module possesses some properties, such as, +//! is free of any floating point operations, which is a useful step towards making instances +//! produced from such a module deterministic. + +#[allow(clippy::module_inception)] +mod runtime_blob; + +pub use runtime_blob::RuntimeBlob; diff --git a/substrate/runtime-executor/common/src/runtime_blob/runtime_blob.rs b/substrate/runtime-executor/common/src/runtime_blob/runtime_blob.rs new file mode 100644 index 00000000000..cae4cd22322 --- /dev/null +++ b/substrate/runtime-executor/common/src/runtime_blob/runtime_blob.rs @@ -0,0 +1,222 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use crate::{error::WasmError, wasm_runtime::HeapAllocStrategy}; +use wasm_instrument::parity_wasm::elements::{ + ExportEntry, External, Internal, MemorySection, MemoryType, Module, Section, + deserialize_buffer, serialize, +}; + +/// A program blob containing a Substrate runtime. +#[derive(Clone)] +pub struct RuntimeBlob(BlobKind); + +#[derive(Clone)] +enum BlobKind { + WebAssembly(Module), + PolkaVM(polkavm::ProgramBlob<'static>), +} + +impl RuntimeBlob { + /// Create `RuntimeBlob` from the given WASM or PolkaVM compressed program blob. + /// + /// See [`sp_maybe_compressed_blob`] for details about decompression. + pub fn uncompress_if_needed(wasm_code: &[u8]) -> Result { + use sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT; + let wasm_code = sp_maybe_compressed_blob::decompress(wasm_code, CODE_BLOB_BOMB_LIMIT) + .map_err(|e| WasmError::Other(format!("Decompression error: {:?}", e)))?; + Self::new(&wasm_code) + } + + /// Create `RuntimeBlob` from the given WASM or PolkaVM program blob. + /// + /// Returns `Err` if the blob cannot be deserialized. + /// + /// Will only accept a PolkaVM program if the `SUBSTRATE_ENABLE_POLKAVM` environment + /// variable is set to `1`. + pub fn new(raw_blob: &[u8]) -> Result { + if raw_blob.starts_with(b"PVM\0") { + if crate::is_polkavm_enabled() { + return Ok(Self(BlobKind::PolkaVM( + polkavm::ProgramBlob::parse(raw_blob)?.into_owned(), + ))); + } else { + return Err(WasmError::Other("expected a WASM runtime blob, found a PolkaVM runtime blob; set the 'SUBSTRATE_ENABLE_POLKAVM' environment variable to enable the experimental PolkaVM-based executor".to_string())); + } + } + + let raw_module: Module = deserialize_buffer(raw_blob) + .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:?}", e)))?; + Ok(Self(BlobKind::WebAssembly(raw_module))) + } + + /// Run a pass that instrument this module so as to introduce a deterministic stack height + /// limit. + /// + /// It will introduce a global mutable counter. The instrumentation will increase the counter + /// according to the "cost" of the callee. If the cost exceeds the `stack_depth_limit` constant, + /// the instrumentation will trap. The counter will be decreased as soon as the the callee + /// returns. + /// + /// The stack cost of a function is computed based on how much locals there are and the maximum + /// depth of the wasm operand stack. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. + pub fn inject_stack_depth_metering(self, stack_depth_limit: u32) -> Result { + let injected_module = + wasm_instrument::inject_stack_limiter(self.into_webassembly_blob()?, stack_depth_limit) + .map_err(|e| { + WasmError::Other(format!("cannot inject the stack limiter: {:?}", e)) + })?; + + Ok(Self(BlobKind::WebAssembly(injected_module))) + } + + /// Converts a WASM memory import into a memory section and exports it. + /// + /// Does nothing if there's no memory import. + /// + /// May return an error in case the WASM module is invalid. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. + pub fn convert_memory_import_into_export(&mut self) -> Result<(), WasmError> { + let raw_module = self.as_webassembly_blob_mut()?; + let import_section = match raw_module.import_section_mut() { + Some(import_section) => import_section, + None => return Ok(()), + }; + + let import_entries = import_section.entries_mut(); + for index in 0..import_entries.len() { + let entry = &import_entries[index]; + let memory_ty = match entry.external() { + External::Memory(memory_ty) => *memory_ty, + _ => continue, + }; + + let memory_name = entry.field().to_owned(); + import_entries.remove(index); + + raw_module + .insert_section(Section::Memory(MemorySection::with_entries(vec![memory_ty]))) + .map_err(|error| { + WasmError::Other(format!( + "can't convert a memory import into an export: failed to insert a new memory section: {}", + error + )) + })?; + + if raw_module.export_section_mut().is_none() { + // A module without an export section is somewhat unrealistic, but let's do this + // just in case to cover all of our bases. + raw_module + .insert_section(Section::Export(Default::default())) + .expect("an export section can be always inserted if it doesn't exist; qed"); + } + raw_module + .export_section_mut() + .expect("export section already existed or we just added it above, so it always exists; qed") + .entries_mut() + .push(ExportEntry::new(memory_name, Internal::Memory(0))); + + break; + } + + Ok(()) + } + + /// Modifies the blob's memory section according to the given `heap_alloc_strategy`. + /// + /// Will return an error in case there is no memory section present, + /// or if the memory section is empty. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. + pub fn setup_memory_according_to_heap_alloc_strategy( + &mut self, + heap_alloc_strategy: HeapAllocStrategy, + ) -> Result<(), WasmError> { + let raw_module = self.as_webassembly_blob_mut()?; + let memory_section = raw_module + .memory_section_mut() + .ok_or_else(|| WasmError::Other("no memory section found".into()))?; + + if memory_section.entries().is_empty() { + return Err(WasmError::Other("memory section is empty".into())); + } + for memory_ty in memory_section.entries_mut() { + let initial = memory_ty.limits().initial(); + let (min, max) = match heap_alloc_strategy { + HeapAllocStrategy::Dynamic { maximum_pages } => { + // Ensure `initial <= maximum_pages` + ( + maximum_pages.map(|m| m.min(initial)).unwrap_or(initial), + maximum_pages, + ) + } + HeapAllocStrategy::Static { extra_pages } => { + let pages = initial.saturating_add(extra_pages); + (pages, Some(pages)) + } + }; + *memory_ty = MemoryType::new(min, max); + } + Ok(()) + } + + /// Scans the wasm blob for the first section with the name that matches the given. Returns the + /// contents of the custom section if found or `None` otherwise. + /// + /// Only valid for WASM programs; will return an error if the blob is a PolkaVM program. + pub fn custom_section_contents(&self, section_name: &str) -> Option<&[u8]> { + self.as_webassembly_blob() + .ok()? + .custom_sections() + .find(|cs| cs.name() == section_name) + .map(|cs| cs.payload()) + } + + /// Consumes this runtime blob and serializes it. + pub fn serialize(self) -> Vec { + match self.0 { + BlobKind::WebAssembly(raw_module) => { + serialize(raw_module).expect("serializing into a vec should succeed; qed") + } + BlobKind::PolkaVM(ref blob) => blob.as_bytes().to_vec(), + } + } + + fn as_webassembly_blob(&self) -> Result<&Module, WasmError> { + match self.0 { + BlobKind::WebAssembly(ref raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + fn as_webassembly_blob_mut(&mut self) -> Result<&mut Module, WasmError> { + match self.0 { + BlobKind::WebAssembly(ref mut raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + fn into_webassembly_blob(self) -> Result { + match self.0 { + BlobKind::WebAssembly(raw_module) => Ok(raw_module), + BlobKind::PolkaVM(..) => Err(WasmError::Other( + "expected a WebAssembly program; found a PolkaVM program blob".into(), + )), + } + } + + /// Gets a reference to the inner PolkaVM program blob, if this is a PolkaVM program. + pub fn as_polkavm_blob(&self) -> Option<&polkavm::ProgramBlob<'_>> { + match self.0 { + BlobKind::WebAssembly(..) => None, + BlobKind::PolkaVM(ref blob) => Some(blob), + } + } +} diff --git a/substrate/runtime-executor/common/src/util.rs b/substrate/runtime-executor/common/src/util.rs new file mode 100644 index 00000000000..638a6a0c881 --- /dev/null +++ b/substrate/runtime-executor/common/src/util.rs @@ -0,0 +1,25 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Utilities used by all backends + +use crate::error::Result; +use sp_wasm_interface::Pointer; + +/// Provides safe memory access interface using an external buffer +pub trait MemoryTransfer { + /// Read data from a slice of memory into a newly allocated buffer. + /// + /// Returns an error if the read would go out of the memory bounds. + fn read(&self, source_addr: Pointer, size: usize) -> Result>; + + /// Read data from a slice of memory into a destination buffer. + /// + /// Returns an error if the read would go out of the memory bounds. + fn read_into(&self, source_addr: Pointer, destination: &mut [u8]) -> Result<()>; + + /// Write data to a slice of memory. + /// + /// Returns an error if the write would go out of the memory bounds. + fn write_from(&self, dest_addr: Pointer, source: &[u8]) -> Result<()>; +} diff --git a/substrate/runtime-executor/common/src/wasm_runtime.rs b/substrate/runtime-executor/common/src/wasm_runtime.rs new file mode 100644 index 00000000000..53836f9e666 --- /dev/null +++ b/substrate/runtime-executor/common/src/wasm_runtime.rs @@ -0,0 +1,89 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Definitions for a wasm runtime. + +use crate::error::Error; + +pub use sp_allocator::AllocationStats; + +/// Default heap allocation strategy. +pub const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy = HeapAllocStrategy::Static { + extra_pages: DEFAULT_HEAP_ALLOC_PAGES, +}; + +/// Default heap allocation pages. +pub const DEFAULT_HEAP_ALLOC_PAGES: u32 = 2048; + +/// A trait that defines an abstract WASM runtime module. +/// +/// This can be implemented by an execution engine. +pub trait WasmModule: Sync + Send { + /// Create a new instance. + fn new_instance(&self) -> Result, Error>; +} + +/// A trait that defines an abstract wasm module instance. +/// +/// This can be implemented by an execution engine. +pub trait WasmInstance: Send { + /// Call a method on this WASM instance. + /// + /// Before execution, instance is reset. + /// + /// Returns the encoded result on success. + fn call(&mut self, method: &str, data: &[u8]) -> Result, Error> { + self.call_with_allocation_stats(method, data).0 + } + + /// Call a method on this WASM instance. + /// + /// Before execution, instance is reset. + /// + /// Returns the encoded result on success. + fn call_with_allocation_stats( + &mut self, + method: &str, + data: &[u8], + ) -> (Result, Error>, Option); + + /// Call an exported method on this WASM instance. + /// + /// Before execution, instance is reset. + /// + /// Returns the encoded result on success. + fn call_export(&mut self, method: &str, data: &[u8]) -> Result, Error> { + self.call(method, data) + } + + /// Get the value from a global with the given `name`. + /// + /// This method is only suitable for getting immutable globals. + fn get_global_const(&mut self, name: &str) -> Result, Error>; +} + +/// Defines the heap pages allocation strategy the wasm runtime should use. +/// +/// A heap page is defined as 64KiB of memory. +#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)] +pub enum HeapAllocStrategy { + /// Allocate a static number of heap pages. + /// + /// The total number of allocated heap pages is the initial number of heap pages requested by + /// the wasm file plus the `extra_pages`. + Static { + /// The number of pages that will be added on top of the initial heap pages requested by + /// the wasm file. + extra_pages: u32, + }, + /// Allocate the initial heap pages as requested by the wasm file and then allow it to grow + /// dynamically. + Dynamic { + /// The absolute maximum size of the linear memory (in pages). + /// + /// When `Some(_)` the linear memory will be allowed to grow up to this limit. + /// When `None` the linear memory will be allowed to grow up to the maximum limit supported + /// by WASM (4GB). + maximum_pages: Option, + }, +} diff --git a/substrate/runtime-executor/polkavm/Cargo.toml b/substrate/runtime-executor/polkavm/Cargo.toml new file mode 100644 index 00000000000..685a2256d6b --- /dev/null +++ b/substrate/runtime-executor/polkavm/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "sc-executor-polkavm" +version = "0.32.0" +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true +description = "PolkaVM executor for Substrate" +documentation = "https://docs.rs/sc-executor-polkavm" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +log = { workspace = true } +polkavm = { workspace = true } +sc-executor-common.workspace = true +sc-executor-common.default-features = true +sp-wasm-interface.workspace = true +sp-wasm-interface.default-features = true diff --git a/substrate/runtime-executor/polkavm/README.md b/substrate/runtime-executor/polkavm/README.md new file mode 100644 index 00000000000..e8aa37432ef --- /dev/null +++ b/substrate/runtime-executor/polkavm/README.md @@ -0,0 +1,15 @@ +# sc-executor-polkavm + +PolkaVM executor for Substrate. + +Local Cargo package name: `sc-executor-polkavm`. +Gear publish name: `gsc-executor-polkavm`. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0. + +Source: Parity Polkadot SDK `stable2409` at `298f676c91d64f15f38ea7fd78f125c5889ab09c`. + +Copied source files retain the upstream SPDX headers and Parity Technologies copyright notices. Gear maintains local changes to isolate the remaining Polkadot SDK fork delta and publishes this crate under the `gsc-executor-polkavm` package name for Gear ecosystem crates. + +GPL-3.0-or-later license text: . +Classpath exception 2.0 text: . diff --git a/substrate/runtime-executor/polkavm/src/lib.rs b/substrate/runtime-executor/polkavm/src/lib.rs new file mode 100644 index 00000000000..069f1450aa8 --- /dev/null +++ b/substrate/runtime-executor/polkavm/src/lib.rs @@ -0,0 +1,265 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use polkavm::{Caller, Reg}; +use sc_executor_common::{ + error::{Error, WasmError}, + wasm_runtime::{AllocationStats, WasmInstance, WasmModule}, +}; +use sp_wasm_interface::{ + Function, FunctionContext, HostFunctions, Pointer, Value, ValueType, WordSize, +}; + +#[repr(transparent)] +pub struct InstancePre(polkavm::InstancePre<()>); + +#[repr(transparent)] +pub struct Instance(polkavm::Instance<()>); + +impl WasmModule for InstancePre { + fn new_instance(&self) -> Result, Error> { + Ok(Box::new(Instance(self.0.instantiate()?))) + } +} + +impl WasmInstance for Instance { + fn call_with_allocation_stats( + &mut self, + name: &str, + raw_data: &[u8], + ) -> (Result, Error>, Option) { + let Some(method_index) = self.0.module().lookup_export(name) else { + return ( + Err(format!("cannot call into the runtime: export not found: '{name}'").into()), + None, + ); + }; + + let Ok(raw_data_length) = u32::try_from(raw_data.len()) else { + return ( + Err( + format!("cannot call runtime method '{name}': input payload is too big").into(), + ), + None, + ); + }; + + // TODO: This will leak guest memory; find a better solution. + let mut state_args = polkavm::StateArgs::new(); + + // Make sure the memory is cleared... + state_args.reset_memory(true); + // ...and allocate space for the input payload. + state_args.sbrk(raw_data_length); + + match self.0.update_state(state_args) { + Ok(()) => {} + Err(polkavm::ExecutionError::Trap(trap)) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {trap}").into()), None); + } + Err(polkavm::ExecutionError::Error(error)) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to prepare the guest's memory: {error}").into()), None); + } + Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + } + + // Grab the address of where the guest's heap starts; that's where we've just allocated + // the memory for the input payload. + let data_pointer = self.0.module().memory_map().heap_base(); + + if let Err(error) = self.0.write_memory(data_pointer, raw_data) { + return (Err(format!("call into the runtime method '{name}': failed to write the input payload into guest memory: {error}").into()), None); + } + + let mut state = (); + let mut call_args = polkavm::CallArgs::new(&mut state, method_index); + call_args.args_untyped(&[data_pointer, raw_data_length]); + + match self.0.call(Default::default(), call_args) { + Ok(()) => {} + Err(polkavm::ExecutionError::Trap(trap)) => { + return ( + Err(format!("call into the runtime method '{name}' failed: {trap}").into()), + None, + ); + } + Err(polkavm::ExecutionError::Error(error)) => { + return ( + Err(format!("call into the runtime method '{name}' failed: {error}").into()), + None, + ); + } + Err(polkavm::ExecutionError::OutOfGas) => unreachable!("gas metering is never enabled"), + } + + let result_pointer = self.0.get_reg(Reg::A0); + let result_length = self.0.get_reg(Reg::A1); + let output = match self.0.read_memory_into_vec(result_pointer, result_length) { + Ok(output) => output, + Err(error) => { + return (Err(format!("call into the runtime method '{name}' failed: failed to read the return payload: {error}").into()), None) + }, + }; + + (Ok(output), None) + } + + fn get_global_const(&mut self, _name: &str) -> Result, Error> { + unimplemented!() + } +} + +struct Context<'r, 'a>(&'r mut polkavm::Caller<'a, ()>); + +impl<'r, 'a> FunctionContext for Context<'r, 'a> { + fn read_memory_into( + &self, + address: Pointer, + dest: &mut [u8], + ) -> sp_wasm_interface::Result<()> { + self.0 + .read_memory_into_slice(u32::from(address), dest) + .map_err(|error| error.to_string()) + .map(|_| ()) + } + + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { + self.0 + .write_memory(u32::from(address), data) + .map_err(|error| error.to_string()) + } + + fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { + let pointer = self + .0 + .sbrk(0) + .expect("fetching the current heap pointer never fails"); + + // TODO: This will leak guest memory; find a better solution. + self.0 + .sbrk(size) + .ok_or_else(|| String::from("allocation failed"))?; + + Ok(Pointer::new(pointer)) + } + + fn deallocate_memory(&mut self, _ptr: Pointer) -> sp_wasm_interface::Result<()> { + // This is only used by the allocator host function, which is unused under PolkaVM. + unimplemented!("'deallocate_memory' is never used when running under PolkaVM"); + } + + fn register_panic_error_message(&mut self, _message: &str) { + unimplemented!("'register_panic_error_message' is never used when running under PolkaVM"); + } +} + +fn call_host_function( + caller: &mut Caller<()>, + function: &dyn Function, +) -> Result<(), polkavm::Trap> { + let mut args = [Value::I64(0); Reg::ARG_REGS.len()]; + let mut nth_reg = 0; + for (nth_arg, kind) in function.signature().args.iter().enumerate() { + match kind { + ValueType::I32 => { + args[nth_arg] = Value::I32(caller.get_reg(Reg::ARG_REGS[nth_reg]) as i32); + nth_reg += 1; + } + ValueType::F32 => { + args[nth_arg] = Value::F32(caller.get_reg(Reg::ARG_REGS[nth_reg])); + nth_reg += 1; + } + ValueType::I64 => { + let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = + Value::I64((u64::from(value_lo) | (u64::from(value_hi) << 32)) as i64); + } + ValueType::F64 => { + let value_lo = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + let value_hi = caller.get_reg(Reg::ARG_REGS[nth_reg]); + nth_reg += 1; + + args[nth_arg] = Value::F64(u64::from(value_lo) | (u64::from(value_hi) << 32)); + } + } + } + + log::trace!( + "Calling host function: '{}', args = {:?}", + function.name(), + &args[..function.signature().args.len()] + ); + + let value = match function.execute( + &mut Context(caller), + &mut args.into_iter().take(function.signature().args.len()), + ) { + Ok(value) => value, + Err(error) => { + log::warn!( + "Call into the host function '{}' failed: {error}", + function.name() + ); + return Err(polkavm::Trap::default()); + } + }; + + if let Some(value) = value { + match value { + Value::I32(value) => { + caller.set_reg(Reg::A0, value as u32); + } + Value::F32(value) => { + caller.set_reg(Reg::A0, value); + } + Value::I64(value) => { + caller.set_reg(Reg::A0, value as u32); + caller.set_reg(Reg::A1, (value >> 32) as u32); + } + Value::F64(value) => { + caller.set_reg(Reg::A0, value as u32); + caller.set_reg(Reg::A1, (value >> 32) as u32); + } + } + } + + Ok(()) +} + +pub fn create_runtime(blob: &polkavm::ProgramBlob) -> Result, WasmError> +where + H: HostFunctions, +{ + static ENGINE: std::sync::OnceLock> = + std::sync::OnceLock::new(); + + let engine = ENGINE.get_or_init(|| { + let config = polkavm::Config::from_env()?; + polkavm::Engine::new(&config) + }); + + let engine = match engine { + Ok(engine) => engine, + Err(error) => { + return Err(WasmError::Other(error.to_string())); + } + }; + + let module = polkavm::Module::from_blob(engine, &polkavm::ModuleConfig::default(), blob)?; + let mut linker = polkavm::Linker::new(engine); + for function in H::host_functions() { + linker.func_new(function.name(), |mut caller| { + call_host_function(&mut caller, function) + })?; + } + + let instance_pre = linker.instantiate_pre(&module)?; + Ok(Box::new(InstancePre(instance_pre))) +} diff --git a/substrate/runtime-executor/src/executor.rs b/substrate/runtime-executor/src/executor.rs new file mode 100644 index 00000000000..d81fe97c7cd --- /dev/null +++ b/substrate/runtime-executor/src/executor.rs @@ -0,0 +1,765 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use crate::{ + RuntimeVersionOf, + error::{Error, Result}, + wasm_runtime::{RuntimeCache, WasmExecutionMethod}, +}; + +use std::{ + marker::PhantomData, + panic::{AssertUnwindSafe, UnwindSafe}, + path::PathBuf, + sync::Arc, +}; + +use codec::Encode; +use sc_executor_common::{ + runtime_blob::RuntimeBlob, + wasm_runtime::{ + AllocationStats, DEFAULT_HEAP_ALLOC_STRATEGY, HeapAllocStrategy, WasmInstance, WasmModule, + }, +}; +use sp_core::traits::{CallContext, CodeExecutor, Externalities, RuntimeCode}; +use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; +use sp_wasm_interface::{ExtendedHostFunctions, HostFunctions}; + +/// Set up the externalities and safe calling environment to execute runtime calls. +/// +/// If the inner closure panics, it will be caught and return an error. +pub fn with_externalities_safe(ext: &mut dyn Externalities, f: F) -> Result +where + F: UnwindSafe + FnOnce() -> U, +{ + sp_externalities::set_and_run_with_externalities(ext, move || { + // Substrate uses custom panic hook that terminates process on panic. Disable + // termination for the native call. + let _guard = sp_panic_handler::AbortGuard::force_unwind(); + std::panic::catch_unwind(f).map_err(|e| { + if let Some(err) = e.downcast_ref::() { + Error::RuntimePanicked(err.clone()) + } else if let Some(err) = e.downcast_ref::<&'static str>() { + Error::RuntimePanicked(err.to_string()) + } else { + Error::RuntimePanicked("Unknown panic".into()) + } + }) + }) +} + +/// Delegate for dispatching a CodeExecutor call. +/// +/// By dispatching we mean that we execute a runtime function specified by it's name. +pub trait NativeExecutionDispatch: Send + Sync { + /// Host functions for custom runtime interfaces that should be callable from within the runtime + /// besides the default Substrate runtime interfaces. + type ExtendHostFunctions: HostFunctions; + + /// Dispatch a method in the runtime. + fn dispatch(method: &str, data: &[u8]) -> Option>; + + /// Provide native runtime version. + fn native_version() -> NativeVersion; +} + +fn unwrap_heap_pages(pages: Option) -> HeapAllocStrategy { + pages.unwrap_or(DEFAULT_HEAP_ALLOC_STRATEGY) +} + +/// Builder for creating a [`WasmExecutor`] instance. +pub struct WasmExecutorBuilder { + _phantom: PhantomData, + method: WasmExecutionMethod, + onchain_heap_alloc_strategy: Option, + offchain_heap_alloc_strategy: Option, + ignore_onchain_heap_pages: bool, + max_runtime_instances: usize, + cache_path: Option, + allow_missing_host_functions: bool, + runtime_cache_size: u8, +} + +impl WasmExecutorBuilder { + /// Create a new instance of `Self` + /// + /// - `method`: The wasm execution method that should be used by the executor. + pub fn new() -> Self { + Self { + _phantom: PhantomData, + method: WasmExecutionMethod::default(), + onchain_heap_alloc_strategy: None, + offchain_heap_alloc_strategy: None, + ignore_onchain_heap_pages: false, + max_runtime_instances: 2, + runtime_cache_size: 4, + allow_missing_host_functions: false, + cache_path: None, + } + } + + /// Create the wasm executor with execution method that should be used by the executor. + pub fn with_execution_method(mut self, method: WasmExecutionMethod) -> Self { + self.method = method; + self + } + + /// Create the wasm executor with the given number of `heap_alloc_strategy` for onchain runtime + /// calls. + pub fn with_onchain_heap_alloc_strategy( + mut self, + heap_alloc_strategy: HeapAllocStrategy, + ) -> Self { + self.onchain_heap_alloc_strategy = Some(heap_alloc_strategy); + self + } + + /// Create the wasm executor with the given number of `heap_alloc_strategy` for offchain runtime + /// calls. + pub fn with_offchain_heap_alloc_strategy( + mut self, + heap_alloc_strategy: HeapAllocStrategy, + ) -> Self { + self.offchain_heap_alloc_strategy = Some(heap_alloc_strategy); + self + } + + /// Create the wasm executor and follow/ignore onchain heap pages value. + /// + /// By default this the onchain heap pages value is followed. + pub fn with_ignore_onchain_heap_pages(mut self, ignore_onchain_heap_pages: bool) -> Self { + self.ignore_onchain_heap_pages = ignore_onchain_heap_pages; + self + } + + /// Create the wasm executor with the given maximum number of `instances`. + /// + /// The number of `instances` defines how many different instances of a runtime the cache is + /// storing. + /// + /// By default the maximum number of `instances` is `2`. + pub fn with_max_runtime_instances(mut self, instances: usize) -> Self { + self.max_runtime_instances = instances; + self + } + + /// Create the wasm executor with the given `cache_path`. + /// + /// The `cache_path` is A path to a directory where the executor can place its files for + /// purposes of caching. This may be important in cases when there are many different modules + /// with the compiled execution method is used. + /// + /// By default there is no `cache_path` given. + pub fn with_cache_path(mut self, cache_path: impl Into) -> Self { + self.cache_path = Some(cache_path.into()); + self + } + + /// Create the wasm executor and allow/forbid missing host functions. + /// + /// If missing host functions are forbidden, the instantiation of a wasm blob will fail + /// for imported host functions that the executor is not aware of. If they are allowed, + /// a stub is generated that will return an error when being called while executing the wasm. + /// + /// By default missing host functions are forbidden. + pub fn with_allow_missing_host_functions(mut self, allow: bool) -> Self { + self.allow_missing_host_functions = allow; + self + } + + /// Create the wasm executor with the given `runtime_cache_size`. + /// + /// Defines the number of different runtimes/instantiated wasm blobs the cache stores. + /// Runtimes/wasm blobs are differentiated based on the hash and the number of heap pages. + /// + /// By default this value is set to `4`. + pub fn with_runtime_cache_size(mut self, runtime_cache_size: u8) -> Self { + self.runtime_cache_size = runtime_cache_size; + self + } + + /// Build the configured [`WasmExecutor`]. + pub fn build(self) -> WasmExecutor { + WasmExecutor { + method: self.method, + default_offchain_heap_alloc_strategy: unwrap_heap_pages( + self.offchain_heap_alloc_strategy, + ), + default_onchain_heap_alloc_strategy: unwrap_heap_pages( + self.onchain_heap_alloc_strategy, + ), + ignore_onchain_heap_pages: self.ignore_onchain_heap_pages, + cache: Arc::new(RuntimeCache::new( + self.max_runtime_instances, + self.cache_path.clone(), + self.runtime_cache_size, + )), + cache_path: self.cache_path, + allow_missing_host_functions: self.allow_missing_host_functions, + phantom: PhantomData, + } + } +} + +/// An abstraction over Wasm code executor. Supports selecting execution backend and +/// manages runtime cache. +pub struct WasmExecutor { + /// Method used to execute fallback Wasm code. + method: WasmExecutionMethod, + /// The heap allocation strategy for onchain Wasm calls. + default_onchain_heap_alloc_strategy: HeapAllocStrategy, + /// The heap allocation strategy for offchain Wasm calls. + default_offchain_heap_alloc_strategy: HeapAllocStrategy, + /// Ignore onchain heap pages value. + ignore_onchain_heap_pages: bool, + /// WASM runtime cache. + cache: Arc, + /// The path to a directory which the executor can leverage for a file cache, e.g. put there + /// compiled artifacts. + cache_path: Option, + /// Ignore missing function imports. + allow_missing_host_functions: bool, + phantom: PhantomData, +} + +impl Clone for WasmExecutor { + fn clone(&self) -> Self { + Self { + method: self.method, + default_onchain_heap_alloc_strategy: self.default_onchain_heap_alloc_strategy, + default_offchain_heap_alloc_strategy: self.default_offchain_heap_alloc_strategy, + ignore_onchain_heap_pages: self.ignore_onchain_heap_pages, + cache: self.cache.clone(), + cache_path: self.cache_path.clone(), + allow_missing_host_functions: self.allow_missing_host_functions, + phantom: self.phantom, + } + } +} + +impl Default for WasmExecutor { + fn default() -> Self { + WasmExecutorBuilder::new().build() + } +} + +impl WasmExecutor { + /// Create new instance. + /// + /// # Parameters + /// + /// `method` - Method used to execute Wasm code. + /// + /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. Internally this + /// will be mapped as [`HeapAllocStrategy::Static`] where `default_heap_pages` represent the + /// static number of heap pages to allocate. Defaults to `DEFAULT_HEAP_ALLOC_STRATEGY` if `None` + /// is provided. + /// + /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. + /// + /// `cache_path` - A path to a directory where the executor can place its files for purposes of + /// caching. This may be important in cases when there are many different modules with the + /// compiled execution method is used. + /// + /// `runtime_cache_size` - The capacity of runtime cache. + #[deprecated(note = "use `Self::builder` method instead of it")] + pub fn new( + method: WasmExecutionMethod, + default_heap_pages: Option, + max_runtime_instances: usize, + cache_path: Option, + runtime_cache_size: u8, + ) -> Self { + WasmExecutor { + method, + default_onchain_heap_alloc_strategy: unwrap_heap_pages(default_heap_pages.map(|h| { + HeapAllocStrategy::Static { + extra_pages: h as _, + } + })), + default_offchain_heap_alloc_strategy: unwrap_heap_pages(default_heap_pages.map(|h| { + HeapAllocStrategy::Static { + extra_pages: h as _, + } + })), + ignore_onchain_heap_pages: false, + cache: Arc::new(RuntimeCache::new( + max_runtime_instances, + cache_path.clone(), + runtime_cache_size, + )), + cache_path, + allow_missing_host_functions: false, + phantom: PhantomData, + } + } + + /// Instantiate a builder for creating an instance of `Self`. + pub fn builder() -> WasmExecutorBuilder { + WasmExecutorBuilder::new() + } + + /// Ignore missing function imports if set true. + #[deprecated(note = "use `Self::builder` method instead of it")] + pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { + self.allow_missing_host_functions = allow_missing_host_functions + } +} + +impl WasmExecutor +where + H: HostFunctions, +{ + /// Execute the given closure `f` with the latest runtime (based on `runtime_code`). + /// + /// The closure `f` is expected to return `Err(_)` when there happened a `panic!` in native code + /// while executing the runtime in Wasm. If a `panic!` occurred, the runtime is invalidated to + /// prevent any poisoned state. Native runtime execution does not need to report back + /// any `panic!`. + /// + /// # Safety + /// + /// `runtime` and `ext` are given as `AssertUnwindSafe` to the closure. As described above, the + /// runtime is invalidated on any `panic!` to prevent a poisoned state. `ext` is already + /// implicitly handled as unwind safe, as we store it in a global variable while executing the + /// native runtime. + pub fn with_instance( + &self, + runtime_code: &RuntimeCode, + ext: &mut dyn Externalities, + heap_alloc_strategy: HeapAllocStrategy, + f: F, + ) -> Result + where + F: FnOnce( + AssertUnwindSafe<&dyn WasmModule>, + AssertUnwindSafe<&mut dyn WasmInstance>, + Option<&RuntimeVersion>, + AssertUnwindSafe<&mut dyn Externalities>, + ) -> Result>, + { + match self.cache.with_instance::( + runtime_code, + ext, + self.method, + heap_alloc_strategy, + self.allow_missing_host_functions, + |module, instance, version, ext| { + let module = AssertUnwindSafe(module); + let instance = AssertUnwindSafe(instance); + let ext = AssertUnwindSafe(ext); + f(module, instance, version, ext) + }, + )? { + Ok(r) => r, + Err(e) => Err(e), + } + } + + /// Perform a call into the given runtime. + /// + /// The runtime is passed as a [`RuntimeBlob`]. The runtime will be instantiated with the + /// parameters this `WasmExecutor` was initialized with. + /// + /// In case of problems with during creation of the runtime or instantiation, a `Err` is + /// returned. that describes the message. + #[doc(hidden)] // We use this function for tests across multiple crates. + pub fn uncached_call( + &self, + runtime_blob: RuntimeBlob, + ext: &mut dyn Externalities, + allow_missing_host_functions: bool, + export_name: &str, + call_data: &[u8], + ) -> std::result::Result, Error> { + self.uncached_call_impl( + runtime_blob, + ext, + allow_missing_host_functions, + export_name, + call_data, + &mut None, + ) + } + + /// Same as `uncached_call`, except it also returns allocation statistics. + #[doc(hidden)] // We use this function in tests. + pub fn uncached_call_with_allocation_stats( + &self, + runtime_blob: RuntimeBlob, + ext: &mut dyn Externalities, + allow_missing_host_functions: bool, + export_name: &str, + call_data: &[u8], + ) -> (std::result::Result, Error>, Option) { + let mut allocation_stats = None; + let result = self.uncached_call_impl( + runtime_blob, + ext, + allow_missing_host_functions, + export_name, + call_data, + &mut allocation_stats, + ); + (result, allocation_stats) + } + + fn uncached_call_impl( + &self, + runtime_blob: RuntimeBlob, + ext: &mut dyn Externalities, + allow_missing_host_functions: bool, + export_name: &str, + call_data: &[u8], + allocation_stats_out: &mut Option, + ) -> std::result::Result, Error> { + let module = crate::wasm_runtime::create_wasm_runtime_with_code::( + self.method, + self.default_onchain_heap_alloc_strategy, + runtime_blob, + allow_missing_host_functions, + self.cache_path.as_deref(), + ) + .map_err(|e| format!("Failed to create module: {}", e))?; + + let instance = module + .new_instance() + .map_err(|e| format!("Failed to create instance: {}", e))?; + + let mut instance = AssertUnwindSafe(instance); + let mut ext = AssertUnwindSafe(ext); + let mut allocation_stats_out = AssertUnwindSafe(allocation_stats_out); + + with_externalities_safe(&mut **ext, move || { + let (result, allocation_stats) = + instance.call_with_allocation_stats(export_name, call_data); + **allocation_stats_out = allocation_stats; + result + }) + .and_then(|r| r) + } +} + +impl sp_core::traits::ReadRuntimeVersion for WasmExecutor +where + H: HostFunctions, +{ + fn read_runtime_version( + &self, + wasm_code: &[u8], + ext: &mut dyn Externalities, + ) -> std::result::Result, String> { + let runtime_blob = RuntimeBlob::uncompress_if_needed(wasm_code) + .map_err(|e| format!("Failed to create runtime blob: {:?}", e))?; + + if let Some(version) = crate::wasm_runtime::read_embedded_version(&runtime_blob) + .map_err(|e| format!("Failed to read the static section: {:?}", e)) + .map(|v| v.map(|v| v.encode()))? + { + return Ok(version); + } + + // If the blob didn't have embedded runtime version section, we fallback to the legacy + // way of fetching the version: i.e. instantiating the given instance and calling + // `Core_version` on it. + + self.uncached_call( + runtime_blob, + ext, + // If a runtime upgrade introduces new host functions that are not provided by + // the node, we should not fail at instantiation. Otherwise nodes that are + // updated could run this successfully and it could lead to a storage root + // mismatch when importing this block. + true, + "Core_version", + &[], + ) + .map_err(|e| e.to_string()) + } +} + +impl CodeExecutor for WasmExecutor +where + H: HostFunctions, +{ + type Error = Error; + + fn call( + &self, + ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, + method: &str, + data: &[u8], + context: CallContext, + ) -> (Result>, bool) { + tracing::trace!( + target: "executor", + %method, + "Executing function", + ); + + let on_chain_heap_alloc_strategy = if self.ignore_onchain_heap_pages { + self.default_onchain_heap_alloc_strategy + } else { + runtime_code + .heap_pages + .map(|h| HeapAllocStrategy::Static { + extra_pages: h as _, + }) + .unwrap_or_else(|| self.default_onchain_heap_alloc_strategy) + }; + + let heap_alloc_strategy = match context { + CallContext::Offchain => self.default_offchain_heap_alloc_strategy, + CallContext::Onchain => on_chain_heap_alloc_strategy, + }; + + let result = self.with_instance( + runtime_code, + ext, + heap_alloc_strategy, + |_, mut instance, _on_chain_version, mut ext| { + with_externalities_safe(&mut **ext, move || instance.call_export(method, data)) + }, + ); + + (result, false) + } +} + +impl RuntimeVersionOf for WasmExecutor +where + H: HostFunctions, +{ + fn runtime_version( + &self, + ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, + ) -> Result { + let on_chain_heap_pages = if self.ignore_onchain_heap_pages { + self.default_onchain_heap_alloc_strategy + } else { + runtime_code + .heap_pages + .map(|h| HeapAllocStrategy::Static { + extra_pages: h as _, + }) + .unwrap_or_else(|| self.default_onchain_heap_alloc_strategy) + }; + + self.with_instance( + runtime_code, + ext, + on_chain_heap_pages, + |_module, _instance, version, _ext| { + Ok(version + .cloned() + .ok_or_else(|| Error::ApiError("Unknown version".into()))) + }, + ) + } +} + +/// A generic `CodeExecutor` implementation that uses a delegate to determine wasm code equivalence +/// and dispatch to native code when possible, falling back on `WasmExecutor` when not. +#[deprecated( + note = "Native execution will be deprecated, please replace with `WasmExecutor`. Will be removed at end of 2024." +)] +pub struct NativeElseWasmExecutor { + /// Native runtime version info. + native_version: NativeVersion, + /// Fallback wasm executor. + wasm: + WasmExecutor>, + + use_native: bool, +} + +#[allow(deprecated)] +impl NativeElseWasmExecutor { + /// + /// Create new instance. + /// + /// # Parameters + /// + /// `fallback_method` - Method used to execute fallback Wasm code. + /// + /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. Internally this + /// will be mapped as [`HeapAllocStrategy::Static`] where `default_heap_pages` represent the + /// static number of heap pages to allocate. Defaults to `DEFAULT_HEAP_ALLOC_STRATEGY` if `None` + /// is provided. + /// + /// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse. + /// + /// `runtime_cache_size` - The capacity of runtime cache. + #[deprecated(note = "use `Self::new_with_wasm_executor` method instead of it")] + pub fn new( + fallback_method: WasmExecutionMethod, + default_heap_pages: Option, + max_runtime_instances: usize, + runtime_cache_size: u8, + ) -> Self { + let heap_pages = + default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { + extra_pages: h as _, + }); + let wasm = WasmExecutor::builder() + .with_execution_method(fallback_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(max_runtime_instances) + .with_runtime_cache_size(runtime_cache_size) + .build(); + + NativeElseWasmExecutor { + native_version: D::native_version(), + wasm, + use_native: true, + } + } + + /// Create a new instance using the given [`WasmExecutor`]. + pub fn new_with_wasm_executor( + executor: WasmExecutor< + ExtendedHostFunctions, + >, + ) -> Self { + Self { + native_version: D::native_version(), + wasm: executor, + use_native: true, + } + } + + /// Disable to use native runtime when possible just behave like `WasmExecutor`. + /// + /// Default to enabled. + pub fn disable_use_native(&mut self) { + self.use_native = false; + } + + /// Ignore missing function imports if set true. + #[deprecated(note = "use `Self::new_with_wasm_executor` method instead of it")] + pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { + self.wasm.allow_missing_host_functions = allow_missing_host_functions + } +} + +#[allow(deprecated)] +impl RuntimeVersionOf for NativeElseWasmExecutor { + fn runtime_version( + &self, + ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, + ) -> Result { + self.wasm.runtime_version(ext, runtime_code) + } +} + +#[allow(deprecated)] +impl GetNativeVersion for NativeElseWasmExecutor { + fn native_version(&self) -> &NativeVersion { + &self.native_version + } +} + +#[allow(deprecated)] +impl CodeExecutor for NativeElseWasmExecutor { + type Error = Error; + + fn call( + &self, + ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, + method: &str, + data: &[u8], + context: CallContext, + ) -> (Result>, bool) { + let use_native = self.use_native; + + tracing::trace!( + target: "executor", + function = %method, + "Executing function", + ); + + let on_chain_heap_alloc_strategy = if self.wasm.ignore_onchain_heap_pages { + self.wasm.default_onchain_heap_alloc_strategy + } else { + runtime_code + .heap_pages + .map(|h| HeapAllocStrategy::Static { + extra_pages: h as _, + }) + .unwrap_or_else(|| self.wasm.default_onchain_heap_alloc_strategy) + }; + + let heap_alloc_strategy = match context { + CallContext::Offchain => self.wasm.default_offchain_heap_alloc_strategy, + CallContext::Onchain => on_chain_heap_alloc_strategy, + }; + + let mut used_native = false; + let result = self.wasm.with_instance( + runtime_code, + ext, + heap_alloc_strategy, + |_, mut instance, on_chain_version, mut ext| { + let on_chain_version = + on_chain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?; + + let can_call_with = + on_chain_version.can_call_with(&self.native_version.runtime_version); + + if use_native && can_call_with { + tracing::trace!( + target: "executor", + native = %self.native_version.runtime_version, + chain = %on_chain_version, + "Request for native execution succeeded", + ); + + used_native = true; + Ok( + with_externalities_safe(&mut **ext, move || D::dispatch(method, data))? + .ok_or_else(|| Error::MethodNotFound(method.to_owned())), + ) + } else { + if !can_call_with { + tracing::trace!( + target: "executor", + native = %self.native_version.runtime_version, + chain = %on_chain_version, + "Request for native execution failed", + ); + } + + with_externalities_safe(&mut **ext, move || instance.call_export(method, data)) + } + }, + ); + (result, used_native) + } +} + +#[allow(deprecated)] +impl Clone for NativeElseWasmExecutor { + fn clone(&self) -> Self { + NativeElseWasmExecutor { + native_version: D::native_version(), + wasm: self.wasm.clone(), + use_native: self.use_native, + } + } +} + +#[allow(deprecated)] +impl sp_core::traits::ReadRuntimeVersion for NativeElseWasmExecutor { + fn read_runtime_version( + &self, + wasm_code: &[u8], + ext: &mut dyn Externalities, + ) -> std::result::Result, String> { + self.wasm.read_runtime_version(wasm_code, ext) + } +} diff --git a/substrate/runtime-executor/src/lib.rs b/substrate/runtime-executor/src/lib.rs new file mode 100644 index 00000000000..2e66ae7fb77 --- /dev/null +++ b/substrate/runtime-executor/src/lib.rs @@ -0,0 +1,54 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! A crate that provides means of executing/dispatching calls into the runtime. +//! +//! There are a few responsibilities of this crate at the moment: +//! +//! - It provides an implementation of a common entrypoint for calling into the runtime, both +//! wasm and compiled. +//! - It defines the environment for the wasm execution, namely the host functions that are to be +//! provided into the wasm runtime module. +//! - It also provides the required infrastructure for executing the current wasm runtime (specified +//! by the current value of `:code` in the provided externalities), i.e. interfacing with +//! wasm engine used, instance cache. + +#![warn(missing_docs)] + +#[macro_use] +mod executor; +mod wasm_runtime; + +pub use codec::Codec; +#[allow(deprecated)] +pub use executor::NativeElseWasmExecutor; +pub use executor::{NativeExecutionDispatch, WasmExecutor, with_externalities_safe}; +#[doc(hidden)] +pub use sp_core::traits::Externalities; +pub use sp_version::{NativeVersion, RuntimeVersion}; +#[doc(hidden)] +pub use sp_wasm_interface; +pub use sp_wasm_interface::HostFunctions; +pub use wasm_runtime::{WasmExecutionMethod, read_embedded_version}; + +pub use sc_executor_common::{ + error, + wasm_runtime::{DEFAULT_HEAP_ALLOC_PAGES, DEFAULT_HEAP_ALLOC_STRATEGY, HeapAllocStrategy}, +}; +pub use sc_executor_wasmtime::{ + Caller as WasmtimeCaller, InstantiationStrategy as WasmtimeInstantiationStrategy, StoreData, + util as wasmtime_util, with_caller_mut, +}; + +/// Wasmtime caller type used by Gear's sandbox runtime interface. +pub type Caller<'a> = WasmtimeCaller<'a, StoreData>; + +/// Extracts the runtime version of a given runtime code. +pub trait RuntimeVersionOf { + /// Extract [`RuntimeVersion`] of the given `runtime_code`. + fn runtime_version( + &self, + ext: &mut dyn Externalities, + runtime_code: &sp_core::traits::RuntimeCode, + ) -> error::Result; +} diff --git a/substrate/runtime-executor/src/wasm_runtime.rs b/substrate/runtime-executor/src/wasm_runtime.rs new file mode 100644 index 00000000000..87a74c2e1f4 --- /dev/null +++ b/substrate/runtime-executor/src/wasm_runtime.rs @@ -0,0 +1,439 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Traits and accessor functions for calling into the Substrate Wasm runtime. +//! +//! The primary means of accessing the runtimes is through a cache which saves the reusable +//! components of the runtime that are expensive to initialize. + +use crate::error::{Error, WasmError}; + +use codec::Decode; +use parking_lot::Mutex; +use sc_executor_common::{ + runtime_blob::RuntimeBlob, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, +}; +use schnellru::{ByLength, LruMap}; +use sp_core::traits::{Externalities, FetchRuntimeCode, RuntimeCode}; +use sp_version::RuntimeVersion; +use sp_wasm_interface::HostFunctions; + +use std::{ + panic::AssertUnwindSafe, + path::{Path, PathBuf}, + sync::Arc, +}; + +/// Specification of different methods of executing the runtime Wasm code. +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +pub enum WasmExecutionMethod { + /// Uses the Wasmtime compiled runtime. + Compiled { + /// The instantiation strategy to use. + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy, + }, +} + +impl Default for WasmExecutionMethod { + fn default() -> Self { + Self::Compiled { + instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite, + } + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +struct VersionedRuntimeId { + /// Runtime code hash. + code_hash: Vec, + /// Wasm runtime type. + wasm_method: WasmExecutionMethod, + /// The heap allocation strategy this runtime was created with. + heap_alloc_strategy: HeapAllocStrategy, +} + +/// A Wasm runtime object along with its cached runtime version. +struct VersionedRuntime { + /// Shared runtime that can spawn instances. + module: Box, + /// Runtime version according to `Core_version` if any. + version: Option, + + // TODO: Remove this once the legacy instance reuse instantiation strategy + // for `wasmtime` is gone, as this only makes sense with that particular strategy. + /// Cached instance pool. + instances: Vec>>>, +} + +impl VersionedRuntime { + /// Run the given closure `f` with an instance of this runtime. + fn with_instance(&self, ext: &mut dyn Externalities, f: F) -> Result + where + F: FnOnce( + &dyn WasmModule, + &mut dyn WasmInstance, + Option<&RuntimeVersion>, + &mut dyn Externalities, + ) -> Result, + { + // Find a free instance + let instance = self + .instances + .iter() + .enumerate() + .find_map(|(index, i)| i.try_lock().map(|i| (index, i))); + + match instance { + Some((index, mut locked)) => { + let (mut instance, new_inst) = locked + .take() + .map(|r| Ok((r, false))) + .unwrap_or_else(|| self.module.new_instance().map(|i| (i, true)))?; + + let result = f(&*self.module, &mut *instance, self.version.as_ref(), ext); + if let Err(e) = &result { + if new_inst { + tracing::warn!( + target: "wasm-runtime", + error = %e, + "Fresh runtime instance failed", + ) + } else { + tracing::warn!( + target: "wasm-runtime", + error = %e, + "Evicting failed runtime instance", + ); + } + } else { + *locked = Some(instance); + + if new_inst { + tracing::debug!( + target: "wasm-runtime", + "Allocated WASM instance {}/{}", + index + 1, + self.instances.len(), + ); + } + } + + result + } + None => { + tracing::warn!(target: "wasm-runtime", "Ran out of free WASM instances"); + + // Allocate a new instance + let mut instance = self.module.new_instance()?; + + f(&*self.module, &mut *instance, self.version.as_ref(), ext) + } + } + } +} + +/// Cache for the runtimes. +/// +/// When an instance is requested for the first time it is added to this cache. Metadata is kept +/// with the instance so that it can be efficiently reinitialized. +/// +/// When using the Wasmi interpreter execution method, the metadata includes the initial memory and +/// values of mutable globals. Follow-up requests to fetch a runtime return this one instance with +/// the memory reset to the initial memory. So, one runtime instance is reused for every fetch +/// request. +/// +/// The size of cache is configurable via the cli option `--runtime-cache-size`. +pub struct RuntimeCache { + /// A cache of runtimes along with metadata. + /// + /// Runtimes sorted by recent usage. The most recently used is at the front. + runtimes: Mutex>>, + /// The size of the instances cache for each runtime. + max_runtime_instances: usize, + cache_path: Option, +} + +impl RuntimeCache { + /// Creates a new instance of a runtimes cache. + /// + /// `max_runtime_instances` specifies the number of instances per runtime preserved in an + /// in-memory cache. + /// + /// `cache_path` allows to specify an optional directory where the executor can store files + /// for caching. + /// + /// `runtime_cache_size` specifies the number of different runtimes versions preserved in an + /// in-memory cache, must always be at least 1. + pub fn new( + max_runtime_instances: usize, + cache_path: Option, + runtime_cache_size: u8, + ) -> RuntimeCache { + let cap = ByLength::new(runtime_cache_size.max(1) as u32); + RuntimeCache { + runtimes: Mutex::new(LruMap::new(cap)), + max_runtime_instances, + cache_path, + } + } + + /// Prepares a WASM module instance and executes given function for it. + /// + /// This uses internal cache to find available instance or create a new one. + /// # Parameters + /// + /// `runtime_code` - The runtime wasm code used setup the runtime. + /// + /// `ext` - The externalities to access the state. + /// + /// `wasm_method` - Type of WASM backend to use. + /// + /// `heap_alloc_strategy` - The heap allocation strategy to use. + /// + /// `allow_missing_func_imports` - Ignore missing function imports. + /// + /// `f` - Function to execute. + /// + /// `H` - A compile-time list of host functions to expose to the runtime. + /// + /// # Returns result of `f` wrapped in an additional result. + /// In case of failure one of two errors can be returned: + /// + /// `Err::RuntimeConstruction` is returned for runtime construction issues. + /// + /// `Error::InvalidMemoryReference` is returned if no memory export with the + /// identifier `memory` can be found in the runtime. + pub fn with_instance<'c, H, R, F>( + &self, + runtime_code: &'c RuntimeCode<'c>, + ext: &mut dyn Externalities, + wasm_method: WasmExecutionMethod, + heap_alloc_strategy: HeapAllocStrategy, + allow_missing_func_imports: bool, + f: F, + ) -> Result, Error> + where + H: HostFunctions, + F: FnOnce( + &dyn WasmModule, + &mut dyn WasmInstance, + Option<&RuntimeVersion>, + &mut dyn Externalities, + ) -> Result, + { + let code_hash = &runtime_code.hash; + + let versioned_runtime_id = VersionedRuntimeId { + code_hash: code_hash.clone(), + heap_alloc_strategy, + wasm_method, + }; + + let mut runtimes = self.runtimes.lock(); // this must be released prior to calling f + let versioned_runtime = if let Some(versioned_runtime) = runtimes.get(&versioned_runtime_id) + { + versioned_runtime.clone() + } else { + let code = runtime_code + .fetch_runtime_code() + .ok_or(WasmError::CodeNotFound)?; + + let time = std::time::Instant::now(); + + let result = create_versioned_wasm_runtime::( + &code, + ext, + wasm_method, + heap_alloc_strategy, + allow_missing_func_imports, + self.max_runtime_instances, + self.cache_path.as_deref(), + ); + + match result { + Ok(ref result) => { + tracing::debug!( + target: "wasm-runtime", + "Prepared new runtime version {:?} in {} ms.", + result.version, + time.elapsed().as_millis(), + ); + } + Err(ref err) => { + tracing::warn!(target: "wasm-runtime", error = ?err, "Cannot create a runtime"); + } + } + + let versioned_runtime = Arc::new(result?); + + // Save new versioned wasm runtime in cache + runtimes.insert(versioned_runtime_id, versioned_runtime.clone()); + + versioned_runtime + }; + + // Lock must be released prior to calling f + drop(runtimes); + + Ok(versioned_runtime.with_instance(ext, f)) + } +} + +/// Create a wasm runtime with the given `code`. +pub fn create_wasm_runtime_with_code( + wasm_method: WasmExecutionMethod, + heap_alloc_strategy: HeapAllocStrategy, + blob: RuntimeBlob, + allow_missing_func_imports: bool, + cache_path: Option<&Path>, +) -> Result, WasmError> +where + H: HostFunctions, +{ + if let Some(blob) = blob.as_polkavm_blob() { + return sc_executor_polkavm::create_runtime::(blob); + } + + match wasm_method { + WasmExecutionMethod::Compiled { + instantiation_strategy, + } => sc_executor_wasmtime::create_runtime::( + blob, + sc_executor_wasmtime::Config { + allow_missing_func_imports, + cache_path: cache_path.map(ToOwned::to_owned), + semantics: sc_executor_wasmtime::Semantics { + heap_alloc_strategy, + instantiation_strategy, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, + }, + }, + ) + .map(|runtime| -> Box { Box::new(runtime) }), + } +} + +fn decode_version(mut version: &[u8]) -> Result { + Decode::decode(&mut version).map_err(|_| { + WasmError::Instantiation( + "failed to decode \"Core_version\" result using old runtime version".into(), + ) + }) +} + +fn decode_runtime_apis(apis: &[u8]) -> Result, WasmError> { + use sp_api::RUNTIME_API_INFO_SIZE; + + apis.chunks(RUNTIME_API_INFO_SIZE) + .map(|chunk| { + // `chunk` can be less than `RUNTIME_API_INFO_SIZE` if the total length of `apis` + // doesn't completely divide by `RUNTIME_API_INFO_SIZE`. + <[u8; RUNTIME_API_INFO_SIZE]>::try_from(chunk) + .map(sp_api::deserialize_runtime_api_info) + .map_err(|_| WasmError::Other("a clipped runtime api info declaration".to_owned())) + }) + .collect::, WasmError>>() +} + +/// Take the runtime blob and scan it for the custom wasm sections containing the version +/// information and construct the `RuntimeVersion` from them. +/// +/// If there are no such sections, it returns `None`. If there is an error during decoding those +/// sections, `Err` will be returned. +pub fn read_embedded_version(blob: &RuntimeBlob) -> Result, WasmError> { + if let Some(mut version_section) = blob.custom_section_contents("runtime_version") { + let apis = blob + .custom_section_contents("runtime_apis") + .map(decode_runtime_apis) + .transpose()? + .map(Into::into); + + let core_version = apis.as_ref().and_then(sp_version::core_version_from_apis); + // We do not use `RuntimeVersion::decode` here because that `decode_version` relies on + // presence of a special API in the `apis` field to treat the input as a non-legacy version. + // However the structure found in the `runtime_version` always contain an empty `apis` + // field. Therefore the version read will be mistakenly treated as an legacy one. + let mut decoded_version = sp_version::RuntimeVersion::decode_with_version_hint( + &mut version_section, + core_version, + ) + .map_err(|_| WasmError::Instantiation("failed to decode version section".into()))?; + + if let Some(apis) = apis { + decoded_version.apis = apis; + } + + Ok(Some(decoded_version)) + } else { + Ok(None) + } +} + +fn create_versioned_wasm_runtime( + code: &[u8], + ext: &mut dyn Externalities, + wasm_method: WasmExecutionMethod, + heap_alloc_strategy: HeapAllocStrategy, + allow_missing_func_imports: bool, + max_instances: usize, + cache_path: Option<&Path>, +) -> Result +where + H: HostFunctions, +{ + // The incoming code may be actually compressed. We decompress it here and then work with + // the uncompressed code from now on. + let blob = sc_executor_common::runtime_blob::RuntimeBlob::uncompress_if_needed(code)?; + + // Use the runtime blob to scan if there is any metadata embedded into the wasm binary + // pertaining to runtime version. We do it before consuming the runtime blob for creating the + // runtime. + let mut version = read_embedded_version(&blob)?; + + let runtime = create_wasm_runtime_with_code::( + wasm_method, + heap_alloc_strategy, + blob, + allow_missing_func_imports, + cache_path, + )?; + + // If the runtime blob doesn't embed the runtime version then use the legacy version query + // mechanism: call the runtime. + if version.is_none() { + // Call to determine runtime version. + let version_result = { + // `ext` is already implicitly handled as unwind safe, as we store it in a global + // variable. + let mut ext = AssertUnwindSafe(ext); + + // The following unwind safety assertion is OK because if the method call panics, the + // runtime will be dropped. + let runtime = AssertUnwindSafe(runtime.as_ref()); + crate::executor::with_externalities_safe(&mut **ext, move || { + runtime.new_instance()?.call("Core_version", &[]) + }) + .map_err(|_| WasmError::Instantiation("panic in call to get runtime version".into()))? + }; + + if let Ok(version_buf) = version_result { + version = Some(decode_version(&version_buf)?) + } + } + + let mut instances = Vec::with_capacity(max_instances); + instances.resize_with(max_instances, || Mutex::new(None)); + + Ok(VersionedRuntime { + module: runtime, + version, + instances, + }) +} diff --git a/substrate/runtime-executor/wasmtime/Cargo.toml b/substrate/runtime-executor/wasmtime/Cargo.toml new file mode 100644 index 00000000000..f271fe3d4b0 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "sc-executor-wasmtime" +version = "0.35.0" +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage.workspace = true +repository.workspace = true +description = "Defines a `WasmRuntime` that uses the Wasmtime JIT to execute." +documentation = "https://docs.rs/sc-executor-wasmtime" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +log = { workspace = true, default-features = true } +parking_lot = { workspace = true, default-features = true } + +# When bumping wasmtime do not forget to also bump rustix +# to exactly the same version as used by wasmtime! +wasmtime = { features = [ + "cache", + "cranelift", + "parallel-compilation", + "pooling-allocator", +], workspace = true } +sp-allocator.workspace = true +sp-allocator.default-features = true +sc-executor-common.workspace = true +sc-executor-common.default-features = true +sp-runtime-interface.workspace = true +sp-runtime-interface.default-features = true +sp-wasm-interface = { features = ["wasmtime"], workspace = true, default-features = true } + +# Here we include the rustix crate in the exactly same semver-compatible version as used by +# wasmtime and enable its 'use-libc' flag. +# +# By default rustix directly calls the appropriate syscalls completely bypassing libc; +# this doesn't have any actual benefits for us besides making it harder to debug memory +# problems (since then `mmap` etc. cannot be easily hooked into). +rustix = { features = ["fs", "mm", "param", "std", "use-libc"], workspace = true } + +[dev-dependencies] +cargo_metadata = { workspace = true } +codec = { workspace = true, default-features = true } +paste = { workspace = true, default-features = true } +sc-runtime-test = { workspace = true } +sp-io = { workspace = true, default-features = true } +tempfile = { workspace = true } +wat = { workspace = true } diff --git a/substrate/runtime-executor/wasmtime/README.md b/substrate/runtime-executor/wasmtime/README.md new file mode 100644 index 00000000000..6b4e28ea8d6 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/README.md @@ -0,0 +1,17 @@ +# sc-executor-wasmtime + +Defines a `WasmRuntime` that uses the Wasmtime JIT to execute. + +Local Cargo package name: `sc-executor-wasmtime`. +Gear publish name: `gsc-executor-wasmtime`. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0. + +Source: Parity Polkadot SDK `stable2409` at `298f676c91d64f15f38ea7fd78f125c5889ab09c`. + +Copied source files retain the upstream SPDX headers and Parity Technologies copyright notices. Gear-authored files are marked in their file headers. Gear maintains local changes to isolate the remaining Polkadot SDK fork delta and publishes this crate under the `gsc-executor-wasmtime` package name for Gear ecosystem crates. + +`src/test-guard-page-skip.wat` is a modified WebAssembly testsuite fixture from , licensed under Apache-2.0: . + +GPL-3.0-or-later license text: . +Classpath exception 2.0 text: . diff --git a/substrate/runtime-executor/wasmtime/build.rs b/substrate/runtime-executor/wasmtime/build.rs new file mode 100644 index 00000000000..1f3e89af074 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/build.rs @@ -0,0 +1,10 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use std::env; + +fn main() { + if let Ok(profile) = env::var("PROFILE") { + println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + } +} diff --git a/substrate/runtime-executor/wasmtime/src/host.rs b/substrate/runtime-executor/wasmtime/src/host.rs new file mode 100644 index 00000000000..7dfbc50977c --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/host.rs @@ -0,0 +1,95 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! This module defines `HostContext`, which provides logic required for host execution. + +use std::cell::Cell; +pub use wasmtime::Caller; + +use sp_wasm_interface::{FunctionContext, Pointer, WordSize}; + +use crate::{store_data::StoreData, util}; + +thread_local! { + static CURRENT_CALLER: Cell<*mut ()> = const { Cell::new(std::ptr::null_mut()) }; +} + +struct CurrentCallerGuard<'a> { + cell: &'a Cell<*mut ()>, + previous: *mut (), +} + +impl Drop for CurrentCallerGuard<'_> { + fn drop(&mut self) { + self.cell.set(self.previous); + } +} + +/// A `HostContext` implements `FunctionContext` for making host calls from a Wasmtime +/// runtime. The `HostContext` exists only for the lifetime of the call and borrows state from +/// a longer-living `HostState`. +pub(crate) struct HostContext<'a> { + pub(crate) caller: Caller<'a, StoreData>, +} + +pub(crate) fn with_host_context( + host_context: &mut HostContext<'_>, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, +) -> R { + CURRENT_CALLER.with(|cell| { + let _guard = CurrentCallerGuard { + cell, + previous: cell.replace(&mut host_context.caller as *mut _ as *mut ()), + }; + callback(host_context) + }) +} + +/// Runs `callback` with the active Wasmtime caller for the current host call. +/// +/// This is the Gear-local replacement for the caller accessor that used to live in the custom +/// Polkadot SDK fork. It is intentionally scoped to the Wasmtime executor. +pub fn with_caller_mut( + _context: &mut dyn FunctionContext, + callback: impl FnOnce(&mut Caller<'_, StoreData>) -> R, +) -> R { + CURRENT_CALLER.with(|cell| { + let ptr = cell.get(); + assert!( + !ptr.is_null(), + "Wasmtime caller is only available during a host call" + ); + let caller = unsafe { &mut *(ptr as *mut Caller<'_, StoreData>) }; + callback(caller) + }) +} + +impl<'a> FunctionContext for HostContext<'a> { + fn read_memory_into( + &self, + address: Pointer, + dest: &mut [u8], + ) -> sp_wasm_interface::Result<()> { + util::read_memory_into(&self.caller, address, dest).map_err(|e| e.to_string()) + } + + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> sp_wasm_interface::Result<()> { + util::write_memory_from(&mut self.caller, address, data).map_err(|e| e.to_string()) + } + + fn allocate_memory(&mut self, size: WordSize) -> sp_wasm_interface::Result> { + util::allocate_memory(&mut self.caller, size).map_err(|e| e.to_string()) + } + + fn deallocate_memory(&mut self, ptr: Pointer) -> sp_wasm_interface::Result<()> { + util::deallocate_memory(&mut self.caller, ptr).map_err(|e| e.to_string()) + } + + fn register_panic_error_message(&mut self, message: &str) { + self.caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .panic_message = Some(message.to_owned()); + } +} diff --git a/substrate/runtime-executor/wasmtime/src/host_state.rs b/substrate/runtime-executor/wasmtime/src/host_state.rs new file mode 100644 index 00000000000..feb70c7e92a --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/host_state.rs @@ -0,0 +1,30 @@ +// Copyright (C) Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use sp_allocator::{AllocationStats, FreeingBumpHeapAllocator}; + +/// State shared by all host calls during one Wasmtime runtime invocation. +pub struct HostState { + pub(crate) allocator: Option, + pub(crate) panic_message: Option, +} + +impl HostState { + pub(crate) fn new(allocator: FreeingBumpHeapAllocator) -> Self { + Self { + allocator: Some(allocator), + panic_message: None, + } + } + + pub(crate) fn take_panic_message(&mut self) -> Option { + self.panic_message.take() + } + + pub(crate) fn allocation_stats(&self) -> AllocationStats { + self.allocator + .as_ref() + .expect("allocator is set outside active allocation/deallocation; qed") + .stats() + } +} diff --git a/substrate/runtime-executor/wasmtime/src/imports.rs b/substrate/runtime-executor/wasmtime/src/imports.rs new file mode 100644 index 00000000000..dd8d5919511 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/imports.rs @@ -0,0 +1,117 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use crate::{ + host::{HostContext, with_host_context}, + store_data::StoreData, +}; +use sc_executor_common::error::WasmError; +use sp_wasm_interface::{FunctionContext, HostFunctions}; +use std::collections::HashMap; +use wasmtime::{ExternType, FuncType, ImportType, Linker, Module}; + +/// Goes over all imports of a module and prepares the given linker for instantiation of the module. +/// Returns an error if there are imports that cannot be satisfied. +pub(crate) fn prepare_imports( + linker: &mut Linker, + module: &Module, + allow_missing_func_imports: bool, +) -> Result<(), WasmError> +where + H: HostFunctions, +{ + let mut pending_func_imports = HashMap::new(); + for import_ty in module.imports() { + let name = import_ty.name(); + + if import_ty.module() != "env" { + return Err(WasmError::Other(format!( + "host doesn't provide any imports from non-env module: {}:{}", + import_ty.module(), + name, + ))); + } + + match import_ty.ty() { + ExternType::Func(func_ty) => { + pending_func_imports.insert(name.to_owned(), (import_ty, func_ty)); + } + _ => { + return Err(WasmError::Other(format!( + "host doesn't provide any non function imports: {}:{}", + import_ty.module(), + name, + ))); + } + }; + } + + let mut registry = Registry { + linker, + pending_func_imports, + }; + H::register_static(&mut registry)?; + + if !registry.pending_func_imports.is_empty() { + if allow_missing_func_imports { + for (name, (import_ty, func_ty)) in registry.pending_func_imports { + let error = format!("call to a missing function {}:{}", import_ty.module(), name); + log::debug!("Missing import: '{}' {:?}", name, func_ty); + linker + .func_new("env", &name, func_ty.clone(), move |_, _, _| { + Err(wasmtime::Error::msg(error.clone())) + }) + .expect("adding a missing import stub can only fail when the item already exists, and it is missing here; qed"); + } + } else { + let mut names = Vec::new(); + for (name, (import_ty, _)) in registry.pending_func_imports { + names.push(format!("'{}:{}'", import_ty.module(), name)); + } + let names = names.join(", "); + return Err(WasmError::Other(format!( + "runtime requires function imports which are not present on the host: {}", + names + ))); + } + } + + Ok(()) +} + +struct Registry<'a, 'b> { + linker: &'a mut Linker, + pending_func_imports: HashMap, FuncType)>, +} + +impl<'a, 'b> sp_wasm_interface::HostFunctionRegistry for Registry<'a, 'b> { + type State = StoreData; + type Error = WasmError; + type FunctionContext = HostContext<'a>; + + fn with_function_context( + caller: wasmtime::Caller, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, + ) -> R { + with_host_context(&mut HostContext { caller }, callback) + } + + fn register_static( + &mut self, + fn_name: &str, + func: impl wasmtime::IntoFunc, + ) -> Result<(), Self::Error> { + if self.pending_func_imports.remove(fn_name).is_some() { + self.linker + .func_wrap("env", fn_name, func) + .map_err(|error| { + WasmError::Other(format!( + "failed to register host function '{}' with the WASM linker: {:#}", + fn_name, error + )) + })?; + } + + Ok(()) + } +} diff --git a/substrate/runtime-executor/wasmtime/src/instance_wrapper.rs b/substrate/runtime-executor/wasmtime/src/instance_wrapper.rs new file mode 100644 index 00000000000..8646406b3dc --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/instance_wrapper.rs @@ -0,0 +1,206 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Defines data and logic needed for interaction with an WebAssembly instance of a substrate +//! runtime module. + +use std::sync::Arc; + +use crate::{ + runtime::{InstanceCounter, ReleaseInstanceHandle, Store}, + store_data::StoreData, +}; +use sc_executor_common::error::{Backtrace, Error, MessageWithBacktrace, Result, WasmError}; +use sp_wasm_interface::{Pointer, Value, WordSize}; +use wasmtime::{ + AsContext, AsContextMut, Engine, Extern, Instance, InstancePre, Memory, Table, Val, +}; + +/// Wasm blob entry point. +pub struct EntryPoint(wasmtime::TypedFunc<(u32, u32), u64>); + +impl EntryPoint { + /// Call this entry point. + pub(crate) fn call( + &self, + store: &mut Store, + data_ptr: Pointer, + data_len: WordSize, + ) -> Result { + let data_ptr = u32::from(data_ptr); + + self.0 + .call(&mut *store, (data_ptr, data_len)) + .map_err(|trap| { + let host_state = store + .data_mut() + .host_state + .as_mut() + .expect("host state cannot be empty while a function is being called; qed"); + + let backtrace = trap + .downcast_ref::() + .map(|backtrace| { + // The logic to print out a backtrace is somewhat complicated, + // so let's get wasmtime to print it out for us. + Backtrace { + backtrace_string: backtrace.to_string(), + } + }); + + if let Some(message) = host_state.take_panic_message() { + Error::AbortedDueToPanic(MessageWithBacktrace { message, backtrace }) + } else { + let message = trap.root_cause().to_string(); + Error::AbortedDueToTrap(MessageWithBacktrace { message, backtrace }) + } + }) + } + + pub fn direct( + func: wasmtime::Func, + ctx: impl AsContext, + ) -> std::result::Result { + let entrypoint = func + .typed::<(u32, u32), u64>(ctx) + .map_err(|_| "Invalid signature for direct entry point")?; + Ok(Self(entrypoint)) + } +} + +/// Wrap the given WebAssembly Instance of a wasm module with Substrate-runtime. +/// +/// This struct is a handy wrapper around a wasmtime `Instance` that provides substrate specific +/// routines. +pub struct InstanceWrapper { + instance: Instance, + store: Store, + // NOTE: We want to decrement the instance counter *after* the store has been dropped + // to avoid a potential race condition, so this field must always be kept + // as the last field in the struct! + _release_instance_handle: ReleaseInstanceHandle, +} + +impl InstanceWrapper { + pub(crate) fn new( + engine: &Engine, + instance_pre: &InstancePre, + instance_counter: Arc, + ) -> Result { + let _release_instance_handle = instance_counter.acquire_instance(); + let mut store = Store::new(engine, Default::default()); + let instance = instance_pre.instantiate(&mut store).map_err(|error| { + WasmError::Other(format!( + "failed to instantiate a new WASM module instance: {:#}", + error, + )) + })?; + + let memory = get_linear_memory(&instance, &mut store)?; + let table = get_table(&instance, &mut store); + + store.data_mut().memory = Some(memory); + store.data_mut().table = table; + + Ok(InstanceWrapper { + instance, + store, + _release_instance_handle, + }) + } + + /// Resolves a substrate entrypoint by the given name. + /// + /// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return + /// an error. + pub fn resolve_entrypoint(&mut self, method: &str) -> Result { + // Resolve the requested method and verify that it has a proper signature. + let export = self + .instance + .get_export(&mut self.store, method) + .ok_or_else(|| Error::from(format!("Exported method {} is not found", method)))?; + let func = export + .into_func() + .ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?; + EntryPoint::direct(func, &self.store).map_err(|_| { + Error::from(format!( + "Exported function '{}' has invalid signature.", + method + )) + }) + } + + /// Reads `__heap_base: i32` global variable and returns it. + /// + /// If it doesn't exist, not a global or of not i32 type returns an error. + pub fn extract_heap_base(&mut self) -> Result { + let heap_base_export = self + .instance + .get_export(&mut self.store, "__heap_base") + .ok_or_else(|| Error::from("__heap_base is not found"))?; + + let heap_base_global = heap_base_export + .into_global() + .ok_or_else(|| Error::from("__heap_base is not a global"))?; + + let heap_base = heap_base_global + .get(&mut self.store) + .i32() + .ok_or_else(|| Error::from("__heap_base is not a i32"))?; + + Ok(heap_base as u32) + } + + /// Get the value from a global with the given `name`. + pub fn get_global_val(&mut self, name: &str) -> Result> { + let global = match self.instance.get_export(&mut self.store, name) { + Some(global) => global, + None => return Ok(None), + }; + + let global = global + .into_global() + .ok_or_else(|| format!("`{}` is not a global", name))?; + + match global.get(&mut self.store) { + Val::I32(val) => Ok(Some(Value::I32(val))), + Val::I64(val) => Ok(Some(Value::I64(val))), + Val::F32(val) => Ok(Some(Value::F32(val))), + Val::F64(val) => Ok(Some(Value::F64(val))), + _ => Err("Unknown value type".into()), + } + } +} + +/// Extract linear memory instance from the given instance. +fn get_linear_memory(instance: &Instance, ctx: impl AsContextMut) -> Result { + let memory_export = instance + .get_export(ctx, "memory") + .ok_or_else(|| Error::from("memory is not exported under `memory` name"))?; + + let memory = memory_export + .into_memory() + .ok_or_else(|| Error::from("the `memory` export should have memory type"))?; + + Ok(memory) +} + +/// Extract the table from the given instance if any. +fn get_table(instance: &Instance, ctx: &mut Store) -> Option { + instance + .get_export(ctx, "__indirect_function_table") + .as_ref() + .cloned() + .and_then(Extern::into_table) +} + +/// Functions related to memory. +impl InstanceWrapper { + pub(crate) fn store(&self) -> &Store { + &self.store + } + + pub(crate) fn store_mut(&mut self) -> &mut Store { + &mut self.store + } +} diff --git a/substrate/runtime-executor/wasmtime/src/lib.rs b/substrate/runtime-executor/wasmtime/src/lib.rs new file mode 100644 index 00000000000..6c0df16d204 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/lib.rs @@ -0,0 +1,38 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Defines a `WasmRuntime` that uses the Wasmtime JIT to execute. +//! +//! You can choose a profiling strategy at runtime with +//! environment variable `WASMTIME_PROFILING_STRATEGY`: +//! +//! | `WASMTIME_PROFILING_STRATEGY` | Effect | +//! |-------------|-------------------------| +//! | undefined | No profiling | +//! | `"jitdump"` | jitdump profiling | +//! | other value | No profiling (warning) | + +mod host; +mod host_state; +mod imports; +mod instance_wrapper; +mod memory_wrapper; +mod runtime; +mod store_data; +pub mod util; + +#[cfg(test)] +mod tests; + +pub use host::{Caller, with_caller_mut}; +pub use host_state::HostState; +pub use runtime::{ + Config, DeterministicStackLimit, InstantiationStrategy, Semantics, WasmtimeRuntime, + create_runtime, create_runtime_from_artifact, create_runtime_from_artifact_bytes, + prepare_runtime_artifact, +}; +pub use sc_executor_common::{ + runtime_blob::RuntimeBlob, + wasm_runtime::{HeapAllocStrategy, WasmModule}, +}; +pub use store_data::StoreData; diff --git a/substrate/runtime-executor/wasmtime/src/memory_wrapper.rs b/substrate/runtime-executor/wasmtime/src/memory_wrapper.rs new file mode 100644 index 00000000000..845399e2727 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/memory_wrapper.rs @@ -0,0 +1,38 @@ +// Copyright (C) Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +/// Wrapper around [`wasmtime::Memory`] that implements [`sp_allocator::Memory`]. +pub(crate) struct MemoryWrapper<'a, C>(&'a wasmtime::Memory, &'a mut C); + +impl<'a, C> From<(&'a wasmtime::Memory, &'a mut C)> for MemoryWrapper<'a, C> { + fn from((memory, caller): (&'a wasmtime::Memory, &'a mut C)) -> Self { + Self(memory, caller) + } +} + +impl sp_allocator::Memory for MemoryWrapper<'_, C> { + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(self.0.data(&self.1)) + } + + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + run(self.0.data_mut(&mut self.1)) + } + + fn grow(&mut self, additional: u32) -> std::result::Result<(), ()> { + self.0 + .grow(&mut self.1, additional as u64) + .map_err(|error| { + log::error!("Failed to grow memory by {} pages: {}", additional, error) + }) + .map(drop) + } + + fn pages(&self) -> u32 { + self.0.size(&self.1) as u32 + } + + fn max_pages(&self) -> Option { + self.0.ty(&self.1).maximum().map(|pages| pages as _) + } +} diff --git a/substrate/runtime-executor/wasmtime/src/runtime.rs b/substrate/runtime-executor/wasmtime/src/runtime.rs new file mode 100644 index 00000000000..301bf1389cc --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/runtime.rs @@ -0,0 +1,782 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Defines the compiled Wasm runtime that uses Wasmtime internally. + +use crate::{ + host_state::HostState, + instance_wrapper::{EntryPoint, InstanceWrapper}, + memory_wrapper::MemoryWrapper, + store_data::StoreData, + util as memory_util, + util::replace_strategy_if_broken, +}; + +use parking_lot::Mutex; +use sc_executor_common::{ + error::{Result, WasmError}, + runtime_blob::RuntimeBlob, + wasm_runtime::{HeapAllocStrategy, WasmInstance, WasmModule}, +}; +use sp_allocator::{AllocationStats, FreeingBumpHeapAllocator}; +use sp_runtime_interface::unpack_ptr_and_len; +use sp_wasm_interface::{HostFunctions, Pointer, Value, WordSize}; +use std::{ + path::{Path, PathBuf}, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, +}; +use wasmtime::{AsContext, Cache, Engine}; + +const MAX_INSTANCE_COUNT: u32 = 64; + +pub(crate) type Store = wasmtime::Store; + +enum Strategy { + RecreateInstance(InstanceCreator), +} + +struct InstanceCreator { + engine: Engine, + instance_pre: Arc>, + instance_counter: Arc, +} + +impl InstanceCreator { + fn instantiate(&mut self) -> Result { + InstanceWrapper::new( + &self.engine, + &self.instance_pre, + self.instance_counter.clone(), + ) + } +} + +/// A handle for releasing an instance acquired by [`InstanceCounter::acquire_instance`]. +pub(crate) struct ReleaseInstanceHandle { + counter: Arc, +} + +impl Drop for ReleaseInstanceHandle { + fn drop(&mut self) { + { + let mut counter = self.counter.counter.lock(); + *counter = counter.saturating_sub(1); + } + + self.counter.wait_for_instance.notify_one(); + } +} + +/// Keeps track on the number of parallel instances. +/// +/// The runtime cache keeps track on the number of parallel instances. The maximum number in the +/// cache is less than what we have configured as [`MAX_INSTANCE_COUNT`] for wasmtime. However, the +/// cache will create on demand instances if required. This instance counter will ensure that we are +/// blocking when we are trying to create too many instances. +#[derive(Default)] +pub(crate) struct InstanceCounter { + counter: Mutex, + wait_for_instance: parking_lot::Condvar, +} + +impl InstanceCounter { + /// Acquire an instance. + /// + /// Blocks if there is no free instance available. + /// + /// The returned [`ReleaseInstanceHandle`] should be dropped when the instance isn't used + /// anymore. + pub fn acquire_instance(self: Arc) -> ReleaseInstanceHandle { + let mut counter = self.counter.lock(); + + while *counter >= MAX_INSTANCE_COUNT { + self.wait_for_instance.wait(&mut counter); + } + *counter += 1; + + ReleaseInstanceHandle { + counter: self.clone(), + } + } +} + +/// A `WasmModule` implementation using wasmtime to compile the runtime module to machine code +/// and execute the compiled code. +pub struct WasmtimeRuntime { + engine: Engine, + instance_pre: Arc>, + instantiation_strategy: InternalInstantiationStrategy, + instance_counter: Arc, +} + +impl WasmModule for WasmtimeRuntime { + fn new_instance(&self) -> Result> { + let strategy = match self.instantiation_strategy { + InternalInstantiationStrategy::Builtin => Strategy::RecreateInstance(InstanceCreator { + engine: self.engine.clone(), + instance_pre: self.instance_pre.clone(), + instance_counter: self.instance_counter.clone(), + }), + }; + + Ok(Box::new(WasmtimeInstance { strategy })) + } +} + +/// A `WasmInstance` implementation that reuses compiled module and spawns instances +/// to execute the compiled code. +pub struct WasmtimeInstance { + strategy: Strategy, +} + +impl WasmtimeInstance { + fn call_impl( + &mut self, + method: &str, + data: &[u8], + allocation_stats: &mut Option, + ) -> Result> { + match &mut self.strategy { + Strategy::RecreateInstance(instance_creator) => { + let mut instance_wrapper = instance_creator.instantiate()?; + let heap_base = instance_wrapper.extract_heap_base()?; + let entrypoint = instance_wrapper.resolve_entrypoint(method)?; + let allocator = FreeingBumpHeapAllocator::new(heap_base); + + perform_call( + data, + &mut instance_wrapper, + entrypoint, + allocator, + allocation_stats, + ) + } + } + } +} + +impl WasmInstance for WasmtimeInstance { + fn call_with_allocation_stats( + &mut self, + method: &str, + data: &[u8], + ) -> (Result>, Option) { + let mut allocation_stats = None; + let result = self.call_impl(method, data, &mut allocation_stats); + (result, allocation_stats) + } + + fn get_global_const(&mut self, name: &str) -> Result> { + match &mut self.strategy { + Strategy::RecreateInstance(instance_creator) => { + instance_creator.instantiate()?.get_global_val(name) + } + } + } +} + +/// Prepare a directory structure and a config file to enable wasmtime caching. +/// +/// In case of an error the caching will not be enabled. +fn setup_wasmtime_caching( + cache_path: &Path, + config: &mut wasmtime::Config, +) -> std::result::Result<(), String> { + use std::fs; + + let wasmtime_cache_root = cache_path.join("wasmtime"); + fs::create_dir_all(&wasmtime_cache_root) + .map_err(|err| format!("cannot create the dirs to cache: {}", err))?; + + // Canonicalize the path after creating the directories. + let wasmtime_cache_root = wasmtime_cache_root + .canonicalize() + .map_err(|err| format!("failed to canonicalize the path: {}", err))?; + + // Write the cache config file + let cache_config_path = wasmtime_cache_root.join("cache-config.toml"); + let config_content = format!( + "\ +[cache] +directory = {cache_dir} +", + cache_dir = toml_basic_string(&wasmtime_cache_root.to_string_lossy()) + ); + fs::write(&cache_config_path, config_content) + .map_err(|err| format!("cannot write the cache config: {}", err))?; + + let cache = Cache::from_file(Some(&cache_config_path)) + .map_err(|err| format!("failed to parse the config: {:#}", err))?; + config.cache(Some(cache)); + + Ok(()) +} + +fn toml_basic_string(value: &str) -> String { + use std::fmt::Write as _; + + let mut escaped = String::with_capacity(value.len() + 2); + escaped.push('"'); + for ch in value.chars() { + match ch { + '\\' => escaped.push_str("\\\\"), + '"' => escaped.push_str("\\\""), + '\n' => escaped.push_str("\\n"), + '\r' => escaped.push_str("\\r"), + '\t' => escaped.push_str("\\t"), + '\u{08}' => escaped.push_str("\\b"), + '\u{0c}' => escaped.push_str("\\f"), + ch if ch.is_control() => { + write!(escaped, "\\u{:04X}", ch as u32).expect("writing to a string cannot fail") + } + ch => escaped.push(ch), + } + } + escaped.push('"'); + escaped +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn toml_basic_string_escapes_cache_paths() { + assert_eq!( + toml_basic_string(r#"C:\Users\gear"cache"\wasmtime"#), + r#""C:\\Users\\gear\"cache\"\\wasmtime""# + ); + } +} + +fn common_config(semantics: &Semantics) -> std::result::Result { + let mut config = wasmtime::Config::new(); + config.macos_use_mach_ports(false); + config.cranelift_opt_level(wasmtime::OptLevel::SpeedAndSize); + config.cranelift_nan_canonicalization(semantics.canonicalize_nans); + + let profiler = match std::env::var_os("WASMTIME_PROFILING_STRATEGY") { + Some(os_string) if os_string == "jitdump" => wasmtime::ProfilingStrategy::JitDump, + None => wasmtime::ProfilingStrategy::None, + Some(_) => { + // Remember if we have already logged a warning due to an unknown profiling strategy. + static UNKNOWN_PROFILING_STRATEGY: AtomicBool = AtomicBool::new(false); + // Make sure that the warning will not be relogged regularly. + if !UNKNOWN_PROFILING_STRATEGY.swap(true, Ordering::Relaxed) { + log::warn!("WASMTIME_PROFILING_STRATEGY is set to unknown value, ignored."); + } + wasmtime::ProfilingStrategy::None + } + }; + config.profiler(profiler); + + let native_stack_max = match semantics.deterministic_stack_limit { + Some(DeterministicStackLimit { + native_stack_max, .. + }) => native_stack_max, + + // In `wasmtime` 0.35 the default stack size limit was changed from 1MB to 512KB. + // + // This broke at least one parachain which depended on the original 1MB limit, + // so here we restore it to what it was originally. + None => 1024 * 1024, + }; + + config.max_wasm_stack(native_stack_max as usize); + + config.parallel_compilation(semantics.parallel_compilation); + + // Be clear and specific about the extensions we support. If an update brings new features + // they should be introduced here as well. + config.wasm_simd(semantics.wasm_simd); + config.wasm_relaxed_simd(false); + config.wasm_bulk_memory(semantics.wasm_bulk_memory); + config.wasm_multi_value(semantics.wasm_multi_value); + config.wasm_multi_memory(false); + config.wasm_memory64(false); + + let (use_pooling, use_cow) = match semantics.instantiation_strategy { + InstantiationStrategy::PoolingCopyOnWrite => (true, true), + InstantiationStrategy::Pooling => (true, false), + InstantiationStrategy::RecreateInstanceCopyOnWrite => (false, true), + InstantiationStrategy::RecreateInstance => (false, false), + }; + + const WASM_PAGE_SIZE: u64 = 65536; + + config.memory_init_cow(use_cow); + config.memory_guaranteed_dense_image_size(match semantics.heap_alloc_strategy { + HeapAllocStrategy::Dynamic { maximum_pages } => maximum_pages + .map(|p| p as u64 * WASM_PAGE_SIZE) + .unwrap_or(u64::MAX), + HeapAllocStrategy::Static { .. } => u64::MAX, + }); + + if use_pooling { + const MAX_WASM_PAGES: u64 = 0x10000; + + let memory_pages = match semantics.heap_alloc_strategy { + HeapAllocStrategy::Dynamic { maximum_pages } => { + maximum_pages.map(|p| p as u64).unwrap_or(MAX_WASM_PAGES) + } + HeapAllocStrategy::Static { .. } => MAX_WASM_PAGES, + }; + + let mut pooling_config = wasmtime::PoolingAllocationConfig::default(); + pooling_config + .max_unused_warm_slots(4) + // Pooling needs a bunch of hard limits to be set; if we go over + // any of these then the instantiation will fail. + // + // Current minimum values for kusama (as of 2022-04-14): + // size: 32384 + // table_elements: 1249 + // memory_pages: 2070 + .max_core_instance_size(128 * 1024) + .table_elements(8192) + .max_memory_size((memory_pages * WASM_PAGE_SIZE) as usize) + // We can only have a single of those. + .max_tables_per_module(1) + .max_memories_per_module(1) + // This determines how many instances of the module can be + // instantiated in parallel from the same `Module`. + .total_core_instances(MAX_INSTANCE_COUNT); + + config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling( + pooling_config, + )); + } + + Ok(config) +} + +/// Knobs for deterministic stack height limiting. +/// +/// The WebAssembly standard defines a call/value stack but it doesn't say anything about its +/// size except that it has to be finite. The implementations are free to choose their own notion +/// of limit: some may count the number of calls or values, others would rely on the host machine +/// stack and trap on reaching a guard page. +/// +/// This obviously is a source of non-determinism during execution. This feature can be used +/// to instrument the code so that it will count the depth of execution in some deterministic +/// way (the machine stack limit should be so high that the deterministic limit always triggers +/// first). +/// +/// The deterministic stack height limiting feature allows to instrument the code so that it will +/// count the number of items that may be on the stack. This counting will only act as an rough +/// estimate of the actual stack limit in wasmtime. This is because wasmtime measures it's stack +/// usage in bytes. +/// +/// The actual number of bytes consumed by a function is not trivial to compute without going +/// through full compilation. Therefore, it's expected that `native_stack_max` is greatly +/// overestimated and thus never reached in practice. The stack overflow check introduced by the +/// instrumentation and that relies on the logical item count should be reached first. +/// +/// See [here][stack_height] for more details of the instrumentation +/// +/// [stack_height]: https://github.com/paritytech/wasm-instrument/blob/master/src/stack_limiter/mod.rs +#[derive(Clone)] +pub struct DeterministicStackLimit { + /// A number of logical "values" that can be pushed on the wasm stack. A trap will be triggered + /// if exceeded. + /// + /// A logical value is a local, an argument or a value pushed on operand stack. + pub logical_max: u32, + /// The maximum number of bytes for stack used by wasmtime JITed code. + /// + /// It's not specified how much bytes will be consumed by a stack frame for a given wasm + /// function after translation into machine code. It is also not quite trivial. + /// + /// Therefore, this number should be chosen conservatively. It must be so large so that it can + /// fit the [`logical_max`](Self::logical_max) logical values on the stack, according to the + /// current instrumentation algorithm. + /// + /// This value cannot be 0. + pub native_stack_max: u32, +} + +/// The instantiation strategy to use for the WASM executor. +/// +/// All of the CoW strategies (with `CopyOnWrite` suffix) are only supported when either: +/// a) we're running on Linux, +/// b) we're running on an Unix-like system and we're precompiling +/// our module beforehand and instantiating from a file. +/// +/// If the CoW variant of a strategy is unsupported the executor will +/// fall back to the non-CoW equivalent. +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum InstantiationStrategy { + /// Pool the instances to avoid initializing everything from scratch + /// on each instantiation. Use copy-on-write memory when possible. + /// + /// This is the fastest instantiation strategy. + PoolingCopyOnWrite, + + /// Recreate the instance from scratch on every instantiation. + /// Use copy-on-write memory when possible. + RecreateInstanceCopyOnWrite, + + /// Pool the instances to avoid initializing everything from scratch + /// on each instantiation. + Pooling, + + /// Recreate the instance from scratch on every instantiation. Very slow. + RecreateInstance, +} + +enum InternalInstantiationStrategy { + Builtin, +} + +#[derive(Clone)] +pub struct Semantics { + /// The instantiation strategy to use. + pub instantiation_strategy: InstantiationStrategy, + + /// Specifying `Some` will enable deterministic stack height. That is, all executor + /// invocations will reach stack overflow at the exactly same point across different wasmtime + /// versions and architectures. + /// + /// This is achieved by a combination of running an instrumentation pass on input code and + /// configuring wasmtime accordingly. + /// + /// Since this feature depends on instrumentation, it can be set only if runtime is + /// instantiated using the runtime blob, e.g. using [`create_runtime`]. + // I.e. if [`CodeSupplyMode::Verbatim`] is used. + pub deterministic_stack_limit: Option, + + /// Controls whether wasmtime should compile floating point in a way that doesn't allow for + /// non-determinism. + /// + /// By default, the wasm spec allows some local non-determinism wrt. certain floating point + /// operations. Specifically, those operations that are not defined to operate on bits (e.g. + /// fneg) can produce NaN values. The exact bit pattern for those is not specified and may + /// depend on the particular machine that executes wasmtime generated JITed machine code. That + /// is a source of non-deterministic values. + /// + /// The classical runtime environment for Substrate allowed it and punted this on the runtime + /// developers. For PVFs, we want to ensure that execution is deterministic though. Therefore, + /// for PVF execution this flag is meant to be turned on. + pub canonicalize_nans: bool, + + /// Configures wasmtime to use multiple threads for compiling. + pub parallel_compilation: bool, + + /// The heap allocation strategy to use. + pub heap_alloc_strategy: HeapAllocStrategy, + + /// Enables WASM Multi-Value proposal + pub wasm_multi_value: bool, + + /// Enables WASM Bulk Memory Operations proposal + pub wasm_bulk_memory: bool, + + /// Enables WASM Reference Types proposal + pub wasm_reference_types: bool, + + /// Enables WASM Fixed-Width SIMD proposal + pub wasm_simd: bool, +} + +#[derive(Clone)] +pub struct Config { + /// The WebAssembly standard requires all imports of an instantiated module to be resolved, + /// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is + /// overridden and imports that are requested by the module and not provided by the host + /// functions will be resolved using stubs. These stubs will trap upon a call. + pub allow_missing_func_imports: bool, + + /// A directory in which wasmtime can store its compiled artifacts cache. + pub cache_path: Option, + + /// Tuning of various semantics of the wasmtime executor. + pub semantics: Semantics, +} + +enum CodeSupplyMode<'a> { + /// The runtime is instantiated using the given runtime blob. + Fresh(RuntimeBlob), + + /// The runtime is instantiated using a precompiled module at the given path. + /// + /// This assumes that the code is already prepared for execution and the same `Config` was + /// used. + /// + /// We use a `Path` here instead of simply passing a byte slice to allow `wasmtime` to + /// map the runtime's linear memory on supported platforms in a copy-on-write fashion. + Precompiled(&'a Path), + + /// The runtime is instantiated using a precompiled module with the given bytes. + /// + /// This assumes that the code is already prepared for execution and the same `Config` was + /// used. + PrecompiledBytes(&'a [u8]), +} + +/// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to +/// machine code, which can be computationally heavy. +/// +/// The `H` generic parameter is used to statically pass a set of host functions which are exposed +/// to the runtime. +pub fn create_runtime( + blob: RuntimeBlob, + config: Config, +) -> std::result::Result +where + H: HostFunctions, +{ + // SAFETY: this is safe because it doesn't use `CodeSupplyMode::Precompiled`. + unsafe { do_create_runtime::(CodeSupplyMode::Fresh(blob), config) } +} + +/// The same as [`create_runtime`] but takes a path to a precompiled artifact, +/// which makes this function considerably faster than [`create_runtime`]. +/// +/// # Safety +/// +/// The caller must ensure that the compiled artifact passed here was: +/// 1) produced by [`prepare_runtime_artifact`], +/// 2) written to the disk as a file, +/// 3) was not modified, +/// 4) will not be modified while any runtime using this artifact is alive, or is being +/// instantiated. +/// +/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. +/// +/// It is ok though if the compiled artifact was created by code of another version or with +/// different configuration flags. In such case the caller will receive an `Err` deterministically. +pub unsafe fn create_runtime_from_artifact( + compiled_artifact_path: &Path, + config: Config, +) -> std::result::Result +where + H: HostFunctions, +{ + // SAFETY: This function carries the same caller contract as `do_create_runtime`. + unsafe { do_create_runtime::(CodeSupplyMode::Precompiled(compiled_artifact_path), config) } +} + +/// The same as [`create_runtime`] but takes the bytes of a precompiled artifact, +/// which makes this function considerably faster than [`create_runtime`], +/// but slower than the more optimized [`create_runtime_from_artifact`]. +/// This is especially slow on non-Linux Unix systems. Useful in very niche cases. +/// +/// # Safety +/// +/// The caller must ensure that the compiled artifact passed here was: +/// 1) produced by [`prepare_runtime_artifact`], +/// 2) was not modified, +/// +/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution. +/// +/// It is ok though if the compiled artifact was created by code of another version or with +/// different configuration flags. In such case the caller will receive an `Err` deterministically. +pub unsafe fn create_runtime_from_artifact_bytes( + compiled_artifact_bytes: &[u8], + config: Config, +) -> std::result::Result +where + H: HostFunctions, +{ + // SAFETY: This function carries the same caller contract as `do_create_runtime`. + unsafe { + do_create_runtime::( + CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes), + config, + ) + } +} + +/// # Safety +/// +/// This is only unsafe if called with [`CodeSupplyMode::Artifact`]. See +/// [`create_runtime_from_artifact`] to get more details. +unsafe fn do_create_runtime( + code_supply_mode: CodeSupplyMode<'_>, + mut config: Config, +) -> std::result::Result +where + H: HostFunctions, +{ + replace_strategy_if_broken(&mut config.semantics.instantiation_strategy); + + let mut wasmtime_config = common_config(&config.semantics)?; + if let Some(ref cache_path) = config.cache_path + && let Err(reason) = setup_wasmtime_caching(cache_path, &mut wasmtime_config) + { + log::warn!( + "failed to setup wasmtime cache. Performance may degrade significantly: {}.", + reason, + ); + } + + let engine = Engine::new(&wasmtime_config) + .map_err(|e| WasmError::Other(format!("cannot create the wasmtime engine: {:#}", e)))?; + + let (module, instantiation_strategy) = match code_supply_mode { + CodeSupplyMode::Fresh(blob) => { + let blob = prepare_blob_for_compilation(blob, &config.semantics)?; + let serialized_blob = blob.clone().serialize(); + + let module = wasmtime::Module::new(&engine, &serialized_blob) + .map_err(|e| WasmError::Other(format!("cannot create module: {:#}", e)))?; + + match config.semantics.instantiation_strategy { + InstantiationStrategy::Pooling + | InstantiationStrategy::PoolingCopyOnWrite + | InstantiationStrategy::RecreateInstance + | InstantiationStrategy::RecreateInstanceCopyOnWrite => { + (module, InternalInstantiationStrategy::Builtin) + } + } + } + CodeSupplyMode::Precompiled(compiled_artifact_path) => { + // SAFETY: The unsafety of `deserialize_file` is covered by this function. The + // responsibilities to maintain the invariants are passed to the caller. + // + // See [`create_runtime_from_artifact`] for more details. + let module = + unsafe { wasmtime::Module::deserialize_file(&engine, compiled_artifact_path) } + .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?; + + (module, InternalInstantiationStrategy::Builtin) + } + CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes) => { + // SAFETY: The unsafety of `deserialize` is covered by this function. The + // responsibilities to maintain the invariants are passed to the caller. + // + // See [`create_runtime_from_artifact_bytes`] for more details. + let module = unsafe { wasmtime::Module::deserialize(&engine, compiled_artifact_bytes) } + .map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?; + + (module, InternalInstantiationStrategy::Builtin) + } + }; + + let mut linker = wasmtime::Linker::new(&engine); + crate::imports::prepare_imports::(&mut linker, &module, config.allow_missing_func_imports)?; + + let instance_pre = linker + .instantiate_pre(&module) + .map_err(|e| WasmError::Other(format!("cannot preinstantiate module: {:#}", e)))?; + + Ok(WasmtimeRuntime { + engine, + instance_pre: Arc::new(instance_pre), + instantiation_strategy, + instance_counter: Default::default(), + }) +} + +fn prepare_blob_for_compilation( + mut blob: RuntimeBlob, + semantics: &Semantics, +) -> std::result::Result { + if let Some(DeterministicStackLimit { logical_max, .. }) = semantics.deterministic_stack_limit { + blob = blob.inject_stack_depth_metering(logical_max)?; + } + + // We don't actually need the memory to be imported so we can just convert any memory + // import into an export with impunity. This simplifies our code since `wasmtime` will + // now automatically take care of creating the memory for us, and it is also necessary + // to enable `wasmtime`'s instance pooling. (Imported memories are ineligible for pooling.) + blob.convert_memory_import_into_export()?; + blob.setup_memory_according_to_heap_alloc_strategy(semantics.heap_alloc_strategy)?; + + Ok(blob) +} + +/// Takes a [`RuntimeBlob`] and precompiles it returning the serialized result of compilation. It +/// can then be used for calling [`create_runtime`] avoiding long compilation times. +pub fn prepare_runtime_artifact( + blob: RuntimeBlob, + semantics: &Semantics, +) -> std::result::Result, WasmError> { + let mut semantics = semantics.clone(); + replace_strategy_if_broken(&mut semantics.instantiation_strategy); + + let blob = prepare_blob_for_compilation(blob, &semantics)?; + + let engine = Engine::new(&common_config(&semantics)?) + .map_err(|e| WasmError::Other(format!("cannot create the engine: {:#}", e)))?; + + engine + .precompile_module(&blob.serialize()) + .map_err(|e| WasmError::Other(format!("cannot precompile module: {:#}", e))) +} + +fn perform_call( + data: &[u8], + instance_wrapper: &mut InstanceWrapper, + entrypoint: EntryPoint, + mut allocator: FreeingBumpHeapAllocator, + allocation_stats: &mut Option, +) -> Result> { + let (data_ptr, data_len) = inject_input_data(instance_wrapper, &mut allocator, data)?; + + let host_state = HostState::new(allocator); + + // Set the host state before calling into wasm. + instance_wrapper.store_mut().data_mut().host_state = Some(host_state); + + let ret = entrypoint + .call(instance_wrapper.store_mut(), data_ptr, data_len) + .map(unpack_ptr_and_len); + + // Reset the host state + let host_state = instance_wrapper + .store_mut() + .data_mut() + .host_state + .take() + .expect( + "the host state is always set before calling into WASM so it can't be None here; qed", + ); + *allocation_stats = Some(host_state.allocation_stats()); + + let (output_ptr, output_len) = ret?; + let output = extract_output_data(instance_wrapper, output_ptr, output_len)?; + + Ok(output) +} + +fn inject_input_data( + instance: &mut InstanceWrapper, + allocator: &mut FreeingBumpHeapAllocator, + data: &[u8], +) -> Result<(Pointer, WordSize)> { + let mut ctx = instance.store_mut(); + let memory = ctx.data().memory(); + let data_len = data.len() as WordSize; + let data_ptr = allocator.allocate(&mut MemoryWrapper::from((&memory, &mut ctx)), data_len)?; + memory_util::write_memory_from(instance.store_mut(), data_ptr, data)?; + Ok((data_ptr, data_len)) +} + +fn extract_output_data( + instance: &InstanceWrapper, + output_ptr: u32, + output_len: u32, +) -> Result> { + let ctx = instance.store(); + + // Do a length check before allocating. The returned output should not be bigger than the + // available WASM memory. Otherwise, a malicious parachain can trigger a large allocation, + // potentially causing memory exhaustion. + // + // Get the size of the WASM memory in bytes. + let memory_size = ctx.as_context().data().memory().data_size(ctx); + if memory_util::checked_range(output_ptr as usize, output_len as usize, memory_size).is_none() { + Err(WasmError::Other( + "output exceeds bounds of wasm memory".into(), + ))? + } + let mut output = vec![0; output_len as usize]; + + memory_util::read_memory_into(ctx, Pointer::new(output_ptr), &mut output)?; + Ok(output) +} diff --git a/substrate/runtime-executor/wasmtime/src/store_data.rs b/substrate/runtime-executor/wasmtime/src/store_data.rs new file mode 100644 index 00000000000..9c558f5bb14 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/store_data.rs @@ -0,0 +1,24 @@ +// Copyright (C) Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use crate::host_state::HostState; +use wasmtime::{Memory, Table}; + +/// Data stored in each Wasmtime store used by the Gear runtime executor. +#[derive(Default)] +pub struct StoreData { + pub host_state: Option, + pub memory: Option, + pub table: Option
, +} + +impl StoreData { + pub fn host_state_mut(&mut self) -> Option<&mut HostState> { + self.host_state.as_mut() + } + + pub fn memory(&self) -> Memory { + self.memory + .expect("memory is initialized before runtime calls; qed") + } +} diff --git a/substrate/runtime-executor/wasmtime/src/test-guard-page-skip.wat b/substrate/runtime-executor/wasmtime/src/test-guard-page-skip.wat new file mode 100644 index 00000000000..2f7339d45c9 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/test-guard-page-skip.wat @@ -0,0 +1,2293 @@ +;; This file is a modified version of +;; https://github.com/WebAssembly/testsuite/blob/01efde81028c5b0d099eb836645a2dc5e7755449/skip-stack-guard-page.wast +;; Licensed Apache 2.0 https://github.com/WebAssembly/testsuite/blob/01efde81028c5b0d099eb836645a2dc5e7755449/LICENSE + +;; This wasm module implements a Substrate Runtime with one entrypoint: `test-many-locals`. This +;; entrypoint does not take any parameters nor returns a result. Each execution should end up with +;; a stack overflow trap. +;; +;; What it does is essentially a recursive call. The function that recurses into itself declares +;; lots of local variables. It reads into each local at the corresponding offset, recurses into itself +;; and then writes the contents of the locals back into the memory at the same offset. +;; +;; The original purpose of this file in the test suite is to test skipping the guard page (hence the +;; size 256 + 4096 + 4096). However, what's important here is to just an infinite recursion with +;; many locals. +;; +;; NOTE That memory accesses are put there in an attempt to prevent eliminating the dead locals. +;; At the moment of writing, wasmtime should be dumb enough to be tricked into thinking that the code +;; does something. + +(module + (import "env" "memory" (memory 1)) + (export "test-many-locals" (func $test-many-locals)) + + ;; The heap base is chosen so that the heap doesn't overlap with the data below. + (global (export "__heap_base") i32 (i32.const 8448)) + + (func $test-many-locals + (param i32 i32) (result i64) + (call $function-with-many-locals) + (i64.const 0) + ) + + (func $function-with-many-locals + + ;; 1056 i64 = 8448 bytes of locals + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x000-0x007 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x008-0x00f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x010-0x017 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x018-0x01f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x020-0x027 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x028-0x02f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x030-0x037 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x038-0x03f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x040-0x047 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x048-0x04f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x050-0x057 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x058-0x05f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x060-0x067 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x068-0x06f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x070-0x077 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x078-0x07f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x080-0x087 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x088-0x08f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x090-0x097 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x098-0x09f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0a0-0x0a7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0a8-0x0af + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0b0-0x0b7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0b8-0x0bf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0c0-0x0c7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0c8-0x0cf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0d0-0x0d7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0d8-0x0df + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0e0-0x0e7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0e8-0x0ef + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0f0-0x0f7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x0f8-0x0ff + + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x100-0x107 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x108-0x10f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x110-0x117 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x118-0x11f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x120-0x127 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x128-0x12f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x130-0x137 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x138-0x13f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x140-0x147 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x148-0x14f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x150-0x157 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x158-0x15f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x160-0x167 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x168-0x16f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x170-0x177 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x178-0x17f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x180-0x187 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x188-0x18f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x190-0x197 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x198-0x19f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1a0-0x1a7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1a8-0x1af + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1b0-0x1b7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1b8-0x1bf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1c0-0x1c7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1c8-0x1cf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1d0-0x1d7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1d8-0x1df + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1e0-0x1e7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1e8-0x1ef + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1f0-0x1f7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x1f8-0x1ff + + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x200-0x207 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x208-0x20f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x210-0x217 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x218-0x21f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x220-0x227 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x228-0x22f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x230-0x237 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x238-0x23f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x240-0x247 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x248-0x24f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x250-0x257 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x258-0x25f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x260-0x267 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x268-0x26f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x270-0x277 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x278-0x27f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x280-0x287 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x288-0x28f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x290-0x297 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x298-0x29f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2a0-0x2a7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2a8-0x2af + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2b0-0x2b7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2b8-0x2bf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2c0-0x2c7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2c8-0x2cf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2d0-0x2d7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2d8-0x2df + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2e0-0x2e7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2e8-0x2ef + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2f0-0x2f7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x2f8-0x2ff + + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x300-0x307 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x308-0x30f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x310-0x317 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x318-0x31f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x320-0x327 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x328-0x32f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x330-0x337 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x338-0x33f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x340-0x347 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x348-0x34f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x350-0x357 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x358-0x35f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x360-0x367 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x368-0x36f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x370-0x377 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x378-0x37f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x380-0x387 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x388-0x38f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x390-0x397 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x398-0x39f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3a0-0x3a7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3a8-0x3af + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3b0-0x3b7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3b8-0x3bf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3c0-0x3c7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3c8-0x3cf + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3d0-0x3d7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3d8-0x3df + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3e0-0x3e7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3e8-0x3ef + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3f0-0x3f7 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x3f8-0x3ff + + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x400-0x407 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x408-0x40f + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x410-0x417 + (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) (local i64) ;; 0x418-0x41f + + ;; recurse first to try to make the callee access the stack below the space allocated for the locals before the locals themselves have been initialized. + (call $function-with-many-locals) + + ;; load from memory into the locals. + (local.set 0x000 (i64.load offset=0x000 align=1 (i32.const 0))) + (local.set 0x001 (i64.load offset=0x001 align=1 (i32.const 0))) + (local.set 0x002 (i64.load offset=0x002 align=1 (i32.const 0))) + (local.set 0x003 (i64.load offset=0x003 align=1 (i32.const 0))) + (local.set 0x004 (i64.load offset=0x004 align=1 (i32.const 0))) + (local.set 0x005 (i64.load offset=0x005 align=1 (i32.const 0))) + (local.set 0x006 (i64.load offset=0x006 align=1 (i32.const 0))) + (local.set 0x007 (i64.load offset=0x007 align=1 (i32.const 0))) + (local.set 0x008 (i64.load offset=0x008 align=1 (i32.const 0))) + (local.set 0x009 (i64.load offset=0x009 align=1 (i32.const 0))) + (local.set 0x00a (i64.load offset=0x00a align=1 (i32.const 0))) + (local.set 0x00b (i64.load offset=0x00b align=1 (i32.const 0))) + (local.set 0x00c (i64.load offset=0x00c align=1 (i32.const 0))) + (local.set 0x00d (i64.load offset=0x00d align=1 (i32.const 0))) + (local.set 0x00e (i64.load offset=0x00e align=1 (i32.const 0))) + (local.set 0x00f (i64.load offset=0x00f align=1 (i32.const 0))) + (local.set 0x010 (i64.load offset=0x010 align=1 (i32.const 0))) + (local.set 0x011 (i64.load offset=0x011 align=1 (i32.const 0))) + (local.set 0x012 (i64.load offset=0x012 align=1 (i32.const 0))) + (local.set 0x013 (i64.load offset=0x013 align=1 (i32.const 0))) + (local.set 0x014 (i64.load offset=0x014 align=1 (i32.const 0))) + (local.set 0x015 (i64.load offset=0x015 align=1 (i32.const 0))) + (local.set 0x016 (i64.load offset=0x016 align=1 (i32.const 0))) + (local.set 0x017 (i64.load offset=0x017 align=1 (i32.const 0))) + (local.set 0x018 (i64.load offset=0x018 align=1 (i32.const 0))) + (local.set 0x019 (i64.load offset=0x019 align=1 (i32.const 0))) + (local.set 0x01a (i64.load offset=0x01a align=1 (i32.const 0))) + (local.set 0x01b (i64.load offset=0x01b align=1 (i32.const 0))) + (local.set 0x01c (i64.load offset=0x01c align=1 (i32.const 0))) + (local.set 0x01d (i64.load offset=0x01d align=1 (i32.const 0))) + (local.set 0x01e (i64.load offset=0x01e align=1 (i32.const 0))) + (local.set 0x01f (i64.load offset=0x01f align=1 (i32.const 0))) + (local.set 0x020 (i64.load offset=0x020 align=1 (i32.const 0))) + (local.set 0x021 (i64.load offset=0x021 align=1 (i32.const 0))) + (local.set 0x022 (i64.load offset=0x022 align=1 (i32.const 0))) + (local.set 0x023 (i64.load offset=0x023 align=1 (i32.const 0))) + (local.set 0x024 (i64.load offset=0x024 align=1 (i32.const 0))) + (local.set 0x025 (i64.load offset=0x025 align=1 (i32.const 0))) + (local.set 0x026 (i64.load offset=0x026 align=1 (i32.const 0))) + (local.set 0x027 (i64.load offset=0x027 align=1 (i32.const 0))) + (local.set 0x028 (i64.load offset=0x028 align=1 (i32.const 0))) + (local.set 0x029 (i64.load offset=0x029 align=1 (i32.const 0))) + (local.set 0x02a (i64.load offset=0x02a align=1 (i32.const 0))) + (local.set 0x02b (i64.load offset=0x02b align=1 (i32.const 0))) + (local.set 0x02c (i64.load offset=0x02c align=1 (i32.const 0))) + (local.set 0x02d (i64.load offset=0x02d align=1 (i32.const 0))) + (local.set 0x02e (i64.load offset=0x02e align=1 (i32.const 0))) + (local.set 0x02f (i64.load offset=0x02f align=1 (i32.const 0))) + (local.set 0x030 (i64.load offset=0x030 align=1 (i32.const 0))) + (local.set 0x031 (i64.load offset=0x031 align=1 (i32.const 0))) + (local.set 0x032 (i64.load offset=0x032 align=1 (i32.const 0))) + (local.set 0x033 (i64.load offset=0x033 align=1 (i32.const 0))) + (local.set 0x034 (i64.load offset=0x034 align=1 (i32.const 0))) + (local.set 0x035 (i64.load offset=0x035 align=1 (i32.const 0))) + (local.set 0x036 (i64.load offset=0x036 align=1 (i32.const 0))) + (local.set 0x037 (i64.load offset=0x037 align=1 (i32.const 0))) + (local.set 0x038 (i64.load offset=0x038 align=1 (i32.const 0))) + (local.set 0x039 (i64.load offset=0x039 align=1 (i32.const 0))) + (local.set 0x03a (i64.load offset=0x03a align=1 (i32.const 0))) + (local.set 0x03b (i64.load offset=0x03b align=1 (i32.const 0))) + (local.set 0x03c (i64.load offset=0x03c align=1 (i32.const 0))) + (local.set 0x03d (i64.load offset=0x03d align=1 (i32.const 0))) + (local.set 0x03e (i64.load offset=0x03e align=1 (i32.const 0))) + (local.set 0x03f (i64.load offset=0x03f align=1 (i32.const 0))) + (local.set 0x040 (i64.load offset=0x040 align=1 (i32.const 0))) + (local.set 0x041 (i64.load offset=0x041 align=1 (i32.const 0))) + (local.set 0x042 (i64.load offset=0x042 align=1 (i32.const 0))) + (local.set 0x043 (i64.load offset=0x043 align=1 (i32.const 0))) + (local.set 0x044 (i64.load offset=0x044 align=1 (i32.const 0))) + (local.set 0x045 (i64.load offset=0x045 align=1 (i32.const 0))) + (local.set 0x046 (i64.load offset=0x046 align=1 (i32.const 0))) + (local.set 0x047 (i64.load offset=0x047 align=1 (i32.const 0))) + (local.set 0x048 (i64.load offset=0x048 align=1 (i32.const 0))) + (local.set 0x049 (i64.load offset=0x049 align=1 (i32.const 0))) + (local.set 0x04a (i64.load offset=0x04a align=1 (i32.const 0))) + (local.set 0x04b (i64.load offset=0x04b align=1 (i32.const 0))) + (local.set 0x04c (i64.load offset=0x04c align=1 (i32.const 0))) + (local.set 0x04d (i64.load offset=0x04d align=1 (i32.const 0))) + (local.set 0x04e (i64.load offset=0x04e align=1 (i32.const 0))) + (local.set 0x04f (i64.load offset=0x04f align=1 (i32.const 0))) + (local.set 0x050 (i64.load offset=0x050 align=1 (i32.const 0))) + (local.set 0x051 (i64.load offset=0x051 align=1 (i32.const 0))) + (local.set 0x052 (i64.load offset=0x052 align=1 (i32.const 0))) + (local.set 0x053 (i64.load offset=0x053 align=1 (i32.const 0))) + (local.set 0x054 (i64.load offset=0x054 align=1 (i32.const 0))) + (local.set 0x055 (i64.load offset=0x055 align=1 (i32.const 0))) + (local.set 0x056 (i64.load offset=0x056 align=1 (i32.const 0))) + (local.set 0x057 (i64.load offset=0x057 align=1 (i32.const 0))) + (local.set 0x058 (i64.load offset=0x058 align=1 (i32.const 0))) + (local.set 0x059 (i64.load offset=0x059 align=1 (i32.const 0))) + (local.set 0x05a (i64.load offset=0x05a align=1 (i32.const 0))) + (local.set 0x05b (i64.load offset=0x05b align=1 (i32.const 0))) + (local.set 0x05c (i64.load offset=0x05c align=1 (i32.const 0))) + (local.set 0x05d (i64.load offset=0x05d align=1 (i32.const 0))) + (local.set 0x05e (i64.load offset=0x05e align=1 (i32.const 0))) + (local.set 0x05f (i64.load offset=0x05f align=1 (i32.const 0))) + (local.set 0x060 (i64.load offset=0x060 align=1 (i32.const 0))) + (local.set 0x061 (i64.load offset=0x061 align=1 (i32.const 0))) + (local.set 0x062 (i64.load offset=0x062 align=1 (i32.const 0))) + (local.set 0x063 (i64.load offset=0x063 align=1 (i32.const 0))) + (local.set 0x064 (i64.load offset=0x064 align=1 (i32.const 0))) + (local.set 0x065 (i64.load offset=0x065 align=1 (i32.const 0))) + (local.set 0x066 (i64.load offset=0x066 align=1 (i32.const 0))) + (local.set 0x067 (i64.load offset=0x067 align=1 (i32.const 0))) + (local.set 0x068 (i64.load offset=0x068 align=1 (i32.const 0))) + (local.set 0x069 (i64.load offset=0x069 align=1 (i32.const 0))) + (local.set 0x06a (i64.load offset=0x06a align=1 (i32.const 0))) + (local.set 0x06b (i64.load offset=0x06b align=1 (i32.const 0))) + (local.set 0x06c (i64.load offset=0x06c align=1 (i32.const 0))) + (local.set 0x06d (i64.load offset=0x06d align=1 (i32.const 0))) + (local.set 0x06e (i64.load offset=0x06e align=1 (i32.const 0))) + (local.set 0x06f (i64.load offset=0x06f align=1 (i32.const 0))) + (local.set 0x070 (i64.load offset=0x070 align=1 (i32.const 0))) + (local.set 0x071 (i64.load offset=0x071 align=1 (i32.const 0))) + (local.set 0x072 (i64.load offset=0x072 align=1 (i32.const 0))) + (local.set 0x073 (i64.load offset=0x073 align=1 (i32.const 0))) + (local.set 0x074 (i64.load offset=0x074 align=1 (i32.const 0))) + (local.set 0x075 (i64.load offset=0x075 align=1 (i32.const 0))) + (local.set 0x076 (i64.load offset=0x076 align=1 (i32.const 0))) + (local.set 0x077 (i64.load offset=0x077 align=1 (i32.const 0))) + (local.set 0x078 (i64.load offset=0x078 align=1 (i32.const 0))) + (local.set 0x079 (i64.load offset=0x079 align=1 (i32.const 0))) + (local.set 0x07a (i64.load offset=0x07a align=1 (i32.const 0))) + (local.set 0x07b (i64.load offset=0x07b align=1 (i32.const 0))) + (local.set 0x07c (i64.load offset=0x07c align=1 (i32.const 0))) + (local.set 0x07d (i64.load offset=0x07d align=1 (i32.const 0))) + (local.set 0x07e (i64.load offset=0x07e align=1 (i32.const 0))) + (local.set 0x07f (i64.load offset=0x07f align=1 (i32.const 0))) + (local.set 0x080 (i64.load offset=0x080 align=1 (i32.const 0))) + (local.set 0x081 (i64.load offset=0x081 align=1 (i32.const 0))) + (local.set 0x082 (i64.load offset=0x082 align=1 (i32.const 0))) + (local.set 0x083 (i64.load offset=0x083 align=1 (i32.const 0))) + (local.set 0x084 (i64.load offset=0x084 align=1 (i32.const 0))) + (local.set 0x085 (i64.load offset=0x085 align=1 (i32.const 0))) + (local.set 0x086 (i64.load offset=0x086 align=1 (i32.const 0))) + (local.set 0x087 (i64.load offset=0x087 align=1 (i32.const 0))) + (local.set 0x088 (i64.load offset=0x088 align=1 (i32.const 0))) + (local.set 0x089 (i64.load offset=0x089 align=1 (i32.const 0))) + (local.set 0x08a (i64.load offset=0x08a align=1 (i32.const 0))) + (local.set 0x08b (i64.load offset=0x08b align=1 (i32.const 0))) + (local.set 0x08c (i64.load offset=0x08c align=1 (i32.const 0))) + (local.set 0x08d (i64.load offset=0x08d align=1 (i32.const 0))) + (local.set 0x08e (i64.load offset=0x08e align=1 (i32.const 0))) + (local.set 0x08f (i64.load offset=0x08f align=1 (i32.const 0))) + (local.set 0x090 (i64.load offset=0x090 align=1 (i32.const 0))) + (local.set 0x091 (i64.load offset=0x091 align=1 (i32.const 0))) + (local.set 0x092 (i64.load offset=0x092 align=1 (i32.const 0))) + (local.set 0x093 (i64.load offset=0x093 align=1 (i32.const 0))) + (local.set 0x094 (i64.load offset=0x094 align=1 (i32.const 0))) + (local.set 0x095 (i64.load offset=0x095 align=1 (i32.const 0))) + (local.set 0x096 (i64.load offset=0x096 align=1 (i32.const 0))) + (local.set 0x097 (i64.load offset=0x097 align=1 (i32.const 0))) + (local.set 0x098 (i64.load offset=0x098 align=1 (i32.const 0))) + (local.set 0x099 (i64.load offset=0x099 align=1 (i32.const 0))) + (local.set 0x09a (i64.load offset=0x09a align=1 (i32.const 0))) + (local.set 0x09b (i64.load offset=0x09b align=1 (i32.const 0))) + (local.set 0x09c (i64.load offset=0x09c align=1 (i32.const 0))) + (local.set 0x09d (i64.load offset=0x09d align=1 (i32.const 0))) + (local.set 0x09e (i64.load offset=0x09e align=1 (i32.const 0))) + (local.set 0x09f (i64.load offset=0x09f align=1 (i32.const 0))) + (local.set 0x0a0 (i64.load offset=0x0a0 align=1 (i32.const 0))) + (local.set 0x0a1 (i64.load offset=0x0a1 align=1 (i32.const 0))) + (local.set 0x0a2 (i64.load offset=0x0a2 align=1 (i32.const 0))) + (local.set 0x0a3 (i64.load offset=0x0a3 align=1 (i32.const 0))) + (local.set 0x0a4 (i64.load offset=0x0a4 align=1 (i32.const 0))) + (local.set 0x0a5 (i64.load offset=0x0a5 align=1 (i32.const 0))) + (local.set 0x0a6 (i64.load offset=0x0a6 align=1 (i32.const 0))) + (local.set 0x0a7 (i64.load offset=0x0a7 align=1 (i32.const 0))) + (local.set 0x0a8 (i64.load offset=0x0a8 align=1 (i32.const 0))) + (local.set 0x0a9 (i64.load offset=0x0a9 align=1 (i32.const 0))) + (local.set 0x0aa (i64.load offset=0x0aa align=1 (i32.const 0))) + (local.set 0x0ab (i64.load offset=0x0ab align=1 (i32.const 0))) + (local.set 0x0ac (i64.load offset=0x0ac align=1 (i32.const 0))) + (local.set 0x0ad (i64.load offset=0x0ad align=1 (i32.const 0))) + (local.set 0x0ae (i64.load offset=0x0ae align=1 (i32.const 0))) + (local.set 0x0af (i64.load offset=0x0af align=1 (i32.const 0))) + (local.set 0x0b0 (i64.load offset=0x0b0 align=1 (i32.const 0))) + (local.set 0x0b1 (i64.load offset=0x0b1 align=1 (i32.const 0))) + (local.set 0x0b2 (i64.load offset=0x0b2 align=1 (i32.const 0))) + (local.set 0x0b3 (i64.load offset=0x0b3 align=1 (i32.const 0))) + (local.set 0x0b4 (i64.load offset=0x0b4 align=1 (i32.const 0))) + (local.set 0x0b5 (i64.load offset=0x0b5 align=1 (i32.const 0))) + (local.set 0x0b6 (i64.load offset=0x0b6 align=1 (i32.const 0))) + (local.set 0x0b7 (i64.load offset=0x0b7 align=1 (i32.const 0))) + (local.set 0x0b8 (i64.load offset=0x0b8 align=1 (i32.const 0))) + (local.set 0x0b9 (i64.load offset=0x0b9 align=1 (i32.const 0))) + (local.set 0x0ba (i64.load offset=0x0ba align=1 (i32.const 0))) + (local.set 0x0bb (i64.load offset=0x0bb align=1 (i32.const 0))) + (local.set 0x0bc (i64.load offset=0x0bc align=1 (i32.const 0))) + (local.set 0x0bd (i64.load offset=0x0bd align=1 (i32.const 0))) + (local.set 0x0be (i64.load offset=0x0be align=1 (i32.const 0))) + (local.set 0x0bf (i64.load offset=0x0bf align=1 (i32.const 0))) + (local.set 0x0c0 (i64.load offset=0x0c0 align=1 (i32.const 0))) + (local.set 0x0c1 (i64.load offset=0x0c1 align=1 (i32.const 0))) + (local.set 0x0c2 (i64.load offset=0x0c2 align=1 (i32.const 0))) + (local.set 0x0c3 (i64.load offset=0x0c3 align=1 (i32.const 0))) + (local.set 0x0c4 (i64.load offset=0x0c4 align=1 (i32.const 0))) + (local.set 0x0c5 (i64.load offset=0x0c5 align=1 (i32.const 0))) + (local.set 0x0c6 (i64.load offset=0x0c6 align=1 (i32.const 0))) + (local.set 0x0c7 (i64.load offset=0x0c7 align=1 (i32.const 0))) + (local.set 0x0c8 (i64.load offset=0x0c8 align=1 (i32.const 0))) + (local.set 0x0c9 (i64.load offset=0x0c9 align=1 (i32.const 0))) + (local.set 0x0ca (i64.load offset=0x0ca align=1 (i32.const 0))) + (local.set 0x0cb (i64.load offset=0x0cb align=1 (i32.const 0))) + (local.set 0x0cc (i64.load offset=0x0cc align=1 (i32.const 0))) + (local.set 0x0cd (i64.load offset=0x0cd align=1 (i32.const 0))) + (local.set 0x0ce (i64.load offset=0x0ce align=1 (i32.const 0))) + (local.set 0x0cf (i64.load offset=0x0cf align=1 (i32.const 0))) + (local.set 0x0d0 (i64.load offset=0x0d0 align=1 (i32.const 0))) + (local.set 0x0d1 (i64.load offset=0x0d1 align=1 (i32.const 0))) + (local.set 0x0d2 (i64.load offset=0x0d2 align=1 (i32.const 0))) + (local.set 0x0d3 (i64.load offset=0x0d3 align=1 (i32.const 0))) + (local.set 0x0d4 (i64.load offset=0x0d4 align=1 (i32.const 0))) + (local.set 0x0d5 (i64.load offset=0x0d5 align=1 (i32.const 0))) + (local.set 0x0d6 (i64.load offset=0x0d6 align=1 (i32.const 0))) + (local.set 0x0d7 (i64.load offset=0x0d7 align=1 (i32.const 0))) + (local.set 0x0d8 (i64.load offset=0x0d8 align=1 (i32.const 0))) + (local.set 0x0d9 (i64.load offset=0x0d9 align=1 (i32.const 0))) + (local.set 0x0da (i64.load offset=0x0da align=1 (i32.const 0))) + (local.set 0x0db (i64.load offset=0x0db align=1 (i32.const 0))) + (local.set 0x0dc (i64.load offset=0x0dc align=1 (i32.const 0))) + (local.set 0x0dd (i64.load offset=0x0dd align=1 (i32.const 0))) + (local.set 0x0de (i64.load offset=0x0de align=1 (i32.const 0))) + (local.set 0x0df (i64.load offset=0x0df align=1 (i32.const 0))) + (local.set 0x0e0 (i64.load offset=0x0e0 align=1 (i32.const 0))) + (local.set 0x0e1 (i64.load offset=0x0e1 align=1 (i32.const 0))) + (local.set 0x0e2 (i64.load offset=0x0e2 align=1 (i32.const 0))) + (local.set 0x0e3 (i64.load offset=0x0e3 align=1 (i32.const 0))) + (local.set 0x0e4 (i64.load offset=0x0e4 align=1 (i32.const 0))) + (local.set 0x0e5 (i64.load offset=0x0e5 align=1 (i32.const 0))) + (local.set 0x0e6 (i64.load offset=0x0e6 align=1 (i32.const 0))) + (local.set 0x0e7 (i64.load offset=0x0e7 align=1 (i32.const 0))) + (local.set 0x0e8 (i64.load offset=0x0e8 align=1 (i32.const 0))) + (local.set 0x0e9 (i64.load offset=0x0e9 align=1 (i32.const 0))) + (local.set 0x0ea (i64.load offset=0x0ea align=1 (i32.const 0))) + (local.set 0x0eb (i64.load offset=0x0eb align=1 (i32.const 0))) + (local.set 0x0ec (i64.load offset=0x0ec align=1 (i32.const 0))) + (local.set 0x0ed (i64.load offset=0x0ed align=1 (i32.const 0))) + (local.set 0x0ee (i64.load offset=0x0ee align=1 (i32.const 0))) + (local.set 0x0ef (i64.load offset=0x0ef align=1 (i32.const 0))) + (local.set 0x0f0 (i64.load offset=0x0f0 align=1 (i32.const 0))) + (local.set 0x0f1 (i64.load offset=0x0f1 align=1 (i32.const 0))) + (local.set 0x0f2 (i64.load offset=0x0f2 align=1 (i32.const 0))) + (local.set 0x0f3 (i64.load offset=0x0f3 align=1 (i32.const 0))) + (local.set 0x0f4 (i64.load offset=0x0f4 align=1 (i32.const 0))) + (local.set 0x0f5 (i64.load offset=0x0f5 align=1 (i32.const 0))) + (local.set 0x0f6 (i64.load offset=0x0f6 align=1 (i32.const 0))) + (local.set 0x0f7 (i64.load offset=0x0f7 align=1 (i32.const 0))) + (local.set 0x0f8 (i64.load offset=0x0f8 align=1 (i32.const 0))) + (local.set 0x0f9 (i64.load offset=0x0f9 align=1 (i32.const 0))) + (local.set 0x0fa (i64.load offset=0x0fa align=1 (i32.const 0))) + (local.set 0x0fb (i64.load offset=0x0fb align=1 (i32.const 0))) + (local.set 0x0fc (i64.load offset=0x0fc align=1 (i32.const 0))) + (local.set 0x0fd (i64.load offset=0x0fd align=1 (i32.const 0))) + (local.set 0x0fe (i64.load offset=0x0fe align=1 (i32.const 0))) + (local.set 0x0ff (i64.load offset=0x0ff align=1 (i32.const 0))) + (local.set 0x100 (i64.load offset=0x100 align=1 (i32.const 0))) + (local.set 0x101 (i64.load offset=0x101 align=1 (i32.const 0))) + (local.set 0x102 (i64.load offset=0x102 align=1 (i32.const 0))) + (local.set 0x103 (i64.load offset=0x103 align=1 (i32.const 0))) + (local.set 0x104 (i64.load offset=0x104 align=1 (i32.const 0))) + (local.set 0x105 (i64.load offset=0x105 align=1 (i32.const 0))) + (local.set 0x106 (i64.load offset=0x106 align=1 (i32.const 0))) + (local.set 0x107 (i64.load offset=0x107 align=1 (i32.const 0))) + (local.set 0x108 (i64.load offset=0x108 align=1 (i32.const 0))) + (local.set 0x109 (i64.load offset=0x109 align=1 (i32.const 0))) + (local.set 0x10a (i64.load offset=0x10a align=1 (i32.const 0))) + (local.set 0x10b (i64.load offset=0x10b align=1 (i32.const 0))) + (local.set 0x10c (i64.load offset=0x10c align=1 (i32.const 0))) + (local.set 0x10d (i64.load offset=0x10d align=1 (i32.const 0))) + (local.set 0x10e (i64.load offset=0x10e align=1 (i32.const 0))) + (local.set 0x10f (i64.load offset=0x10f align=1 (i32.const 0))) + (local.set 0x110 (i64.load offset=0x110 align=1 (i32.const 0))) + (local.set 0x111 (i64.load offset=0x111 align=1 (i32.const 0))) + (local.set 0x112 (i64.load offset=0x112 align=1 (i32.const 0))) + (local.set 0x113 (i64.load offset=0x113 align=1 (i32.const 0))) + (local.set 0x114 (i64.load offset=0x114 align=1 (i32.const 0))) + (local.set 0x115 (i64.load offset=0x115 align=1 (i32.const 0))) + (local.set 0x116 (i64.load offset=0x116 align=1 (i32.const 0))) + (local.set 0x117 (i64.load offset=0x117 align=1 (i32.const 0))) + (local.set 0x118 (i64.load offset=0x118 align=1 (i32.const 0))) + (local.set 0x119 (i64.load offset=0x119 align=1 (i32.const 0))) + (local.set 0x11a (i64.load offset=0x11a align=1 (i32.const 0))) + (local.set 0x11b (i64.load offset=0x11b align=1 (i32.const 0))) + (local.set 0x11c (i64.load offset=0x11c align=1 (i32.const 0))) + (local.set 0x11d (i64.load offset=0x11d align=1 (i32.const 0))) + (local.set 0x11e (i64.load offset=0x11e align=1 (i32.const 0))) + (local.set 0x11f (i64.load offset=0x11f align=1 (i32.const 0))) + (local.set 0x120 (i64.load offset=0x120 align=1 (i32.const 0))) + (local.set 0x121 (i64.load offset=0x121 align=1 (i32.const 0))) + (local.set 0x122 (i64.load offset=0x122 align=1 (i32.const 0))) + (local.set 0x123 (i64.load offset=0x123 align=1 (i32.const 0))) + (local.set 0x124 (i64.load offset=0x124 align=1 (i32.const 0))) + (local.set 0x125 (i64.load offset=0x125 align=1 (i32.const 0))) + (local.set 0x126 (i64.load offset=0x126 align=1 (i32.const 0))) + (local.set 0x127 (i64.load offset=0x127 align=1 (i32.const 0))) + (local.set 0x128 (i64.load offset=0x128 align=1 (i32.const 0))) + (local.set 0x129 (i64.load offset=0x129 align=1 (i32.const 0))) + (local.set 0x12a (i64.load offset=0x12a align=1 (i32.const 0))) + (local.set 0x12b (i64.load offset=0x12b align=1 (i32.const 0))) + (local.set 0x12c (i64.load offset=0x12c align=1 (i32.const 0))) + (local.set 0x12d (i64.load offset=0x12d align=1 (i32.const 0))) + (local.set 0x12e (i64.load offset=0x12e align=1 (i32.const 0))) + (local.set 0x12f (i64.load offset=0x12f align=1 (i32.const 0))) + (local.set 0x130 (i64.load offset=0x130 align=1 (i32.const 0))) + (local.set 0x131 (i64.load offset=0x131 align=1 (i32.const 0))) + (local.set 0x132 (i64.load offset=0x132 align=1 (i32.const 0))) + (local.set 0x133 (i64.load offset=0x133 align=1 (i32.const 0))) + (local.set 0x134 (i64.load offset=0x134 align=1 (i32.const 0))) + (local.set 0x135 (i64.load offset=0x135 align=1 (i32.const 0))) + (local.set 0x136 (i64.load offset=0x136 align=1 (i32.const 0))) + (local.set 0x137 (i64.load offset=0x137 align=1 (i32.const 0))) + (local.set 0x138 (i64.load offset=0x138 align=1 (i32.const 0))) + (local.set 0x139 (i64.load offset=0x139 align=1 (i32.const 0))) + (local.set 0x13a (i64.load offset=0x13a align=1 (i32.const 0))) + (local.set 0x13b (i64.load offset=0x13b align=1 (i32.const 0))) + (local.set 0x13c (i64.load offset=0x13c align=1 (i32.const 0))) + (local.set 0x13d (i64.load offset=0x13d align=1 (i32.const 0))) + (local.set 0x13e (i64.load offset=0x13e align=1 (i32.const 0))) + (local.set 0x13f (i64.load offset=0x13f align=1 (i32.const 0))) + (local.set 0x140 (i64.load offset=0x140 align=1 (i32.const 0))) + (local.set 0x141 (i64.load offset=0x141 align=1 (i32.const 0))) + (local.set 0x142 (i64.load offset=0x142 align=1 (i32.const 0))) + (local.set 0x143 (i64.load offset=0x143 align=1 (i32.const 0))) + (local.set 0x144 (i64.load offset=0x144 align=1 (i32.const 0))) + (local.set 0x145 (i64.load offset=0x145 align=1 (i32.const 0))) + (local.set 0x146 (i64.load offset=0x146 align=1 (i32.const 0))) + (local.set 0x147 (i64.load offset=0x147 align=1 (i32.const 0))) + (local.set 0x148 (i64.load offset=0x148 align=1 (i32.const 0))) + (local.set 0x149 (i64.load offset=0x149 align=1 (i32.const 0))) + (local.set 0x14a (i64.load offset=0x14a align=1 (i32.const 0))) + (local.set 0x14b (i64.load offset=0x14b align=1 (i32.const 0))) + (local.set 0x14c (i64.load offset=0x14c align=1 (i32.const 0))) + (local.set 0x14d (i64.load offset=0x14d align=1 (i32.const 0))) + (local.set 0x14e (i64.load offset=0x14e align=1 (i32.const 0))) + (local.set 0x14f (i64.load offset=0x14f align=1 (i32.const 0))) + (local.set 0x150 (i64.load offset=0x150 align=1 (i32.const 0))) + (local.set 0x151 (i64.load offset=0x151 align=1 (i32.const 0))) + (local.set 0x152 (i64.load offset=0x152 align=1 (i32.const 0))) + (local.set 0x153 (i64.load offset=0x153 align=1 (i32.const 0))) + (local.set 0x154 (i64.load offset=0x154 align=1 (i32.const 0))) + (local.set 0x155 (i64.load offset=0x155 align=1 (i32.const 0))) + (local.set 0x156 (i64.load offset=0x156 align=1 (i32.const 0))) + (local.set 0x157 (i64.load offset=0x157 align=1 (i32.const 0))) + (local.set 0x158 (i64.load offset=0x158 align=1 (i32.const 0))) + (local.set 0x159 (i64.load offset=0x159 align=1 (i32.const 0))) + (local.set 0x15a (i64.load offset=0x15a align=1 (i32.const 0))) + (local.set 0x15b (i64.load offset=0x15b align=1 (i32.const 0))) + (local.set 0x15c (i64.load offset=0x15c align=1 (i32.const 0))) + (local.set 0x15d (i64.load offset=0x15d align=1 (i32.const 0))) + (local.set 0x15e (i64.load offset=0x15e align=1 (i32.const 0))) + (local.set 0x15f (i64.load offset=0x15f align=1 (i32.const 0))) + (local.set 0x160 (i64.load offset=0x160 align=1 (i32.const 0))) + (local.set 0x161 (i64.load offset=0x161 align=1 (i32.const 0))) + (local.set 0x162 (i64.load offset=0x162 align=1 (i32.const 0))) + (local.set 0x163 (i64.load offset=0x163 align=1 (i32.const 0))) + (local.set 0x164 (i64.load offset=0x164 align=1 (i32.const 0))) + (local.set 0x165 (i64.load offset=0x165 align=1 (i32.const 0))) + (local.set 0x166 (i64.load offset=0x166 align=1 (i32.const 0))) + (local.set 0x167 (i64.load offset=0x167 align=1 (i32.const 0))) + (local.set 0x168 (i64.load offset=0x168 align=1 (i32.const 0))) + (local.set 0x169 (i64.load offset=0x169 align=1 (i32.const 0))) + (local.set 0x16a (i64.load offset=0x16a align=1 (i32.const 0))) + (local.set 0x16b (i64.load offset=0x16b align=1 (i32.const 0))) + (local.set 0x16c (i64.load offset=0x16c align=1 (i32.const 0))) + (local.set 0x16d (i64.load offset=0x16d align=1 (i32.const 0))) + (local.set 0x16e (i64.load offset=0x16e align=1 (i32.const 0))) + (local.set 0x16f (i64.load offset=0x16f align=1 (i32.const 0))) + (local.set 0x170 (i64.load offset=0x170 align=1 (i32.const 0))) + (local.set 0x171 (i64.load offset=0x171 align=1 (i32.const 0))) + (local.set 0x172 (i64.load offset=0x172 align=1 (i32.const 0))) + (local.set 0x173 (i64.load offset=0x173 align=1 (i32.const 0))) + (local.set 0x174 (i64.load offset=0x174 align=1 (i32.const 0))) + (local.set 0x175 (i64.load offset=0x175 align=1 (i32.const 0))) + (local.set 0x176 (i64.load offset=0x176 align=1 (i32.const 0))) + (local.set 0x177 (i64.load offset=0x177 align=1 (i32.const 0))) + (local.set 0x178 (i64.load offset=0x178 align=1 (i32.const 0))) + (local.set 0x179 (i64.load offset=0x179 align=1 (i32.const 0))) + (local.set 0x17a (i64.load offset=0x17a align=1 (i32.const 0))) + (local.set 0x17b (i64.load offset=0x17b align=1 (i32.const 0))) + (local.set 0x17c (i64.load offset=0x17c align=1 (i32.const 0))) + (local.set 0x17d (i64.load offset=0x17d align=1 (i32.const 0))) + (local.set 0x17e (i64.load offset=0x17e align=1 (i32.const 0))) + (local.set 0x17f (i64.load offset=0x17f align=1 (i32.const 0))) + (local.set 0x180 (i64.load offset=0x180 align=1 (i32.const 0))) + (local.set 0x181 (i64.load offset=0x181 align=1 (i32.const 0))) + (local.set 0x182 (i64.load offset=0x182 align=1 (i32.const 0))) + (local.set 0x183 (i64.load offset=0x183 align=1 (i32.const 0))) + (local.set 0x184 (i64.load offset=0x184 align=1 (i32.const 0))) + (local.set 0x185 (i64.load offset=0x185 align=1 (i32.const 0))) + (local.set 0x186 (i64.load offset=0x186 align=1 (i32.const 0))) + (local.set 0x187 (i64.load offset=0x187 align=1 (i32.const 0))) + (local.set 0x188 (i64.load offset=0x188 align=1 (i32.const 0))) + (local.set 0x189 (i64.load offset=0x189 align=1 (i32.const 0))) + (local.set 0x18a (i64.load offset=0x18a align=1 (i32.const 0))) + (local.set 0x18b (i64.load offset=0x18b align=1 (i32.const 0))) + (local.set 0x18c (i64.load offset=0x18c align=1 (i32.const 0))) + (local.set 0x18d (i64.load offset=0x18d align=1 (i32.const 0))) + (local.set 0x18e (i64.load offset=0x18e align=1 (i32.const 0))) + (local.set 0x18f (i64.load offset=0x18f align=1 (i32.const 0))) + (local.set 0x190 (i64.load offset=0x190 align=1 (i32.const 0))) + (local.set 0x191 (i64.load offset=0x191 align=1 (i32.const 0))) + (local.set 0x192 (i64.load offset=0x192 align=1 (i32.const 0))) + (local.set 0x193 (i64.load offset=0x193 align=1 (i32.const 0))) + (local.set 0x194 (i64.load offset=0x194 align=1 (i32.const 0))) + (local.set 0x195 (i64.load offset=0x195 align=1 (i32.const 0))) + (local.set 0x196 (i64.load offset=0x196 align=1 (i32.const 0))) + (local.set 0x197 (i64.load offset=0x197 align=1 (i32.const 0))) + (local.set 0x198 (i64.load offset=0x198 align=1 (i32.const 0))) + (local.set 0x199 (i64.load offset=0x199 align=1 (i32.const 0))) + (local.set 0x19a (i64.load offset=0x19a align=1 (i32.const 0))) + (local.set 0x19b (i64.load offset=0x19b align=1 (i32.const 0))) + (local.set 0x19c (i64.load offset=0x19c align=1 (i32.const 0))) + (local.set 0x19d (i64.load offset=0x19d align=1 (i32.const 0))) + (local.set 0x19e (i64.load offset=0x19e align=1 (i32.const 0))) + (local.set 0x19f (i64.load offset=0x19f align=1 (i32.const 0))) + (local.set 0x1a0 (i64.load offset=0x1a0 align=1 (i32.const 0))) + (local.set 0x1a1 (i64.load offset=0x1a1 align=1 (i32.const 0))) + (local.set 0x1a2 (i64.load offset=0x1a2 align=1 (i32.const 0))) + (local.set 0x1a3 (i64.load offset=0x1a3 align=1 (i32.const 0))) + (local.set 0x1a4 (i64.load offset=0x1a4 align=1 (i32.const 0))) + (local.set 0x1a5 (i64.load offset=0x1a5 align=1 (i32.const 0))) + (local.set 0x1a6 (i64.load offset=0x1a6 align=1 (i32.const 0))) + (local.set 0x1a7 (i64.load offset=0x1a7 align=1 (i32.const 0))) + (local.set 0x1a8 (i64.load offset=0x1a8 align=1 (i32.const 0))) + (local.set 0x1a9 (i64.load offset=0x1a9 align=1 (i32.const 0))) + (local.set 0x1aa (i64.load offset=0x1aa align=1 (i32.const 0))) + (local.set 0x1ab (i64.load offset=0x1ab align=1 (i32.const 0))) + (local.set 0x1ac (i64.load offset=0x1ac align=1 (i32.const 0))) + (local.set 0x1ad (i64.load offset=0x1ad align=1 (i32.const 0))) + (local.set 0x1ae (i64.load offset=0x1ae align=1 (i32.const 0))) + (local.set 0x1af (i64.load offset=0x1af align=1 (i32.const 0))) + (local.set 0x1b0 (i64.load offset=0x1b0 align=1 (i32.const 0))) + (local.set 0x1b1 (i64.load offset=0x1b1 align=1 (i32.const 0))) + (local.set 0x1b2 (i64.load offset=0x1b2 align=1 (i32.const 0))) + (local.set 0x1b3 (i64.load offset=0x1b3 align=1 (i32.const 0))) + (local.set 0x1b4 (i64.load offset=0x1b4 align=1 (i32.const 0))) + (local.set 0x1b5 (i64.load offset=0x1b5 align=1 (i32.const 0))) + (local.set 0x1b6 (i64.load offset=0x1b6 align=1 (i32.const 0))) + (local.set 0x1b7 (i64.load offset=0x1b7 align=1 (i32.const 0))) + (local.set 0x1b8 (i64.load offset=0x1b8 align=1 (i32.const 0))) + (local.set 0x1b9 (i64.load offset=0x1b9 align=1 (i32.const 0))) + (local.set 0x1ba (i64.load offset=0x1ba align=1 (i32.const 0))) + (local.set 0x1bb (i64.load offset=0x1bb align=1 (i32.const 0))) + (local.set 0x1bc (i64.load offset=0x1bc align=1 (i32.const 0))) + (local.set 0x1bd (i64.load offset=0x1bd align=1 (i32.const 0))) + (local.set 0x1be (i64.load offset=0x1be align=1 (i32.const 0))) + (local.set 0x1bf (i64.load offset=0x1bf align=1 (i32.const 0))) + (local.set 0x1c0 (i64.load offset=0x1c0 align=1 (i32.const 0))) + (local.set 0x1c1 (i64.load offset=0x1c1 align=1 (i32.const 0))) + (local.set 0x1c2 (i64.load offset=0x1c2 align=1 (i32.const 0))) + (local.set 0x1c3 (i64.load offset=0x1c3 align=1 (i32.const 0))) + (local.set 0x1c4 (i64.load offset=0x1c4 align=1 (i32.const 0))) + (local.set 0x1c5 (i64.load offset=0x1c5 align=1 (i32.const 0))) + (local.set 0x1c6 (i64.load offset=0x1c6 align=1 (i32.const 0))) + (local.set 0x1c7 (i64.load offset=0x1c7 align=1 (i32.const 0))) + (local.set 0x1c8 (i64.load offset=0x1c8 align=1 (i32.const 0))) + (local.set 0x1c9 (i64.load offset=0x1c9 align=1 (i32.const 0))) + (local.set 0x1ca (i64.load offset=0x1ca align=1 (i32.const 0))) + (local.set 0x1cb (i64.load offset=0x1cb align=1 (i32.const 0))) + (local.set 0x1cc (i64.load offset=0x1cc align=1 (i32.const 0))) + (local.set 0x1cd (i64.load offset=0x1cd align=1 (i32.const 0))) + (local.set 0x1ce (i64.load offset=0x1ce align=1 (i32.const 0))) + (local.set 0x1cf (i64.load offset=0x1cf align=1 (i32.const 0))) + (local.set 0x1d0 (i64.load offset=0x1d0 align=1 (i32.const 0))) + (local.set 0x1d1 (i64.load offset=0x1d1 align=1 (i32.const 0))) + (local.set 0x1d2 (i64.load offset=0x1d2 align=1 (i32.const 0))) + (local.set 0x1d3 (i64.load offset=0x1d3 align=1 (i32.const 0))) + (local.set 0x1d4 (i64.load offset=0x1d4 align=1 (i32.const 0))) + (local.set 0x1d5 (i64.load offset=0x1d5 align=1 (i32.const 0))) + (local.set 0x1d6 (i64.load offset=0x1d6 align=1 (i32.const 0))) + (local.set 0x1d7 (i64.load offset=0x1d7 align=1 (i32.const 0))) + (local.set 0x1d8 (i64.load offset=0x1d8 align=1 (i32.const 0))) + (local.set 0x1d9 (i64.load offset=0x1d9 align=1 (i32.const 0))) + (local.set 0x1da (i64.load offset=0x1da align=1 (i32.const 0))) + (local.set 0x1db (i64.load offset=0x1db align=1 (i32.const 0))) + (local.set 0x1dc (i64.load offset=0x1dc align=1 (i32.const 0))) + (local.set 0x1dd (i64.load offset=0x1dd align=1 (i32.const 0))) + (local.set 0x1de (i64.load offset=0x1de align=1 (i32.const 0))) + (local.set 0x1df (i64.load offset=0x1df align=1 (i32.const 0))) + (local.set 0x1e0 (i64.load offset=0x1e0 align=1 (i32.const 0))) + (local.set 0x1e1 (i64.load offset=0x1e1 align=1 (i32.const 0))) + (local.set 0x1e2 (i64.load offset=0x1e2 align=1 (i32.const 0))) + (local.set 0x1e3 (i64.load offset=0x1e3 align=1 (i32.const 0))) + (local.set 0x1e4 (i64.load offset=0x1e4 align=1 (i32.const 0))) + (local.set 0x1e5 (i64.load offset=0x1e5 align=1 (i32.const 0))) + (local.set 0x1e6 (i64.load offset=0x1e6 align=1 (i32.const 0))) + (local.set 0x1e7 (i64.load offset=0x1e7 align=1 (i32.const 0))) + (local.set 0x1e8 (i64.load offset=0x1e8 align=1 (i32.const 0))) + (local.set 0x1e9 (i64.load offset=0x1e9 align=1 (i32.const 0))) + (local.set 0x1ea (i64.load offset=0x1ea align=1 (i32.const 0))) + (local.set 0x1eb (i64.load offset=0x1eb align=1 (i32.const 0))) + (local.set 0x1ec (i64.load offset=0x1ec align=1 (i32.const 0))) + (local.set 0x1ed (i64.load offset=0x1ed align=1 (i32.const 0))) + (local.set 0x1ee (i64.load offset=0x1ee align=1 (i32.const 0))) + (local.set 0x1ef (i64.load offset=0x1ef align=1 (i32.const 0))) + (local.set 0x1f0 (i64.load offset=0x1f0 align=1 (i32.const 0))) + (local.set 0x1f1 (i64.load offset=0x1f1 align=1 (i32.const 0))) + (local.set 0x1f2 (i64.load offset=0x1f2 align=1 (i32.const 0))) + (local.set 0x1f3 (i64.load offset=0x1f3 align=1 (i32.const 0))) + (local.set 0x1f4 (i64.load offset=0x1f4 align=1 (i32.const 0))) + (local.set 0x1f5 (i64.load offset=0x1f5 align=1 (i32.const 0))) + (local.set 0x1f6 (i64.load offset=0x1f6 align=1 (i32.const 0))) + (local.set 0x1f7 (i64.load offset=0x1f7 align=1 (i32.const 0))) + (local.set 0x1f8 (i64.load offset=0x1f8 align=1 (i32.const 0))) + (local.set 0x1f9 (i64.load offset=0x1f9 align=1 (i32.const 0))) + (local.set 0x1fa (i64.load offset=0x1fa align=1 (i32.const 0))) + (local.set 0x1fb (i64.load offset=0x1fb align=1 (i32.const 0))) + (local.set 0x1fc (i64.load offset=0x1fc align=1 (i32.const 0))) + (local.set 0x1fd (i64.load offset=0x1fd align=1 (i32.const 0))) + (local.set 0x1fe (i64.load offset=0x1fe align=1 (i32.const 0))) + (local.set 0x1ff (i64.load offset=0x1ff align=1 (i32.const 0))) + (local.set 0x200 (i64.load offset=0x200 align=1 (i32.const 0))) + (local.set 0x201 (i64.load offset=0x201 align=1 (i32.const 0))) + (local.set 0x202 (i64.load offset=0x202 align=1 (i32.const 0))) + (local.set 0x203 (i64.load offset=0x203 align=1 (i32.const 0))) + (local.set 0x204 (i64.load offset=0x204 align=1 (i32.const 0))) + (local.set 0x205 (i64.load offset=0x205 align=1 (i32.const 0))) + (local.set 0x206 (i64.load offset=0x206 align=1 (i32.const 0))) + (local.set 0x207 (i64.load offset=0x207 align=1 (i32.const 0))) + (local.set 0x208 (i64.load offset=0x208 align=1 (i32.const 0))) + (local.set 0x209 (i64.load offset=0x209 align=1 (i32.const 0))) + (local.set 0x20a (i64.load offset=0x20a align=1 (i32.const 0))) + (local.set 0x20b (i64.load offset=0x20b align=1 (i32.const 0))) + (local.set 0x20c (i64.load offset=0x20c align=1 (i32.const 0))) + (local.set 0x20d (i64.load offset=0x20d align=1 (i32.const 0))) + (local.set 0x20e (i64.load offset=0x20e align=1 (i32.const 0))) + (local.set 0x20f (i64.load offset=0x20f align=1 (i32.const 0))) + (local.set 0x210 (i64.load offset=0x210 align=1 (i32.const 0))) + (local.set 0x211 (i64.load offset=0x211 align=1 (i32.const 0))) + (local.set 0x212 (i64.load offset=0x212 align=1 (i32.const 0))) + (local.set 0x213 (i64.load offset=0x213 align=1 (i32.const 0))) + (local.set 0x214 (i64.load offset=0x214 align=1 (i32.const 0))) + (local.set 0x215 (i64.load offset=0x215 align=1 (i32.const 0))) + (local.set 0x216 (i64.load offset=0x216 align=1 (i32.const 0))) + (local.set 0x217 (i64.load offset=0x217 align=1 (i32.const 0))) + (local.set 0x218 (i64.load offset=0x218 align=1 (i32.const 0))) + (local.set 0x219 (i64.load offset=0x219 align=1 (i32.const 0))) + (local.set 0x21a (i64.load offset=0x21a align=1 (i32.const 0))) + (local.set 0x21b (i64.load offset=0x21b align=1 (i32.const 0))) + (local.set 0x21c (i64.load offset=0x21c align=1 (i32.const 0))) + (local.set 0x21d (i64.load offset=0x21d align=1 (i32.const 0))) + (local.set 0x21e (i64.load offset=0x21e align=1 (i32.const 0))) + (local.set 0x21f (i64.load offset=0x21f align=1 (i32.const 0))) + (local.set 0x220 (i64.load offset=0x220 align=1 (i32.const 0))) + (local.set 0x221 (i64.load offset=0x221 align=1 (i32.const 0))) + (local.set 0x222 (i64.load offset=0x222 align=1 (i32.const 0))) + (local.set 0x223 (i64.load offset=0x223 align=1 (i32.const 0))) + (local.set 0x224 (i64.load offset=0x224 align=1 (i32.const 0))) + (local.set 0x225 (i64.load offset=0x225 align=1 (i32.const 0))) + (local.set 0x226 (i64.load offset=0x226 align=1 (i32.const 0))) + (local.set 0x227 (i64.load offset=0x227 align=1 (i32.const 0))) + (local.set 0x228 (i64.load offset=0x228 align=1 (i32.const 0))) + (local.set 0x229 (i64.load offset=0x229 align=1 (i32.const 0))) + (local.set 0x22a (i64.load offset=0x22a align=1 (i32.const 0))) + (local.set 0x22b (i64.load offset=0x22b align=1 (i32.const 0))) + (local.set 0x22c (i64.load offset=0x22c align=1 (i32.const 0))) + (local.set 0x22d (i64.load offset=0x22d align=1 (i32.const 0))) + (local.set 0x22e (i64.load offset=0x22e align=1 (i32.const 0))) + (local.set 0x22f (i64.load offset=0x22f align=1 (i32.const 0))) + (local.set 0x230 (i64.load offset=0x230 align=1 (i32.const 0))) + (local.set 0x231 (i64.load offset=0x231 align=1 (i32.const 0))) + (local.set 0x232 (i64.load offset=0x232 align=1 (i32.const 0))) + (local.set 0x233 (i64.load offset=0x233 align=1 (i32.const 0))) + (local.set 0x234 (i64.load offset=0x234 align=1 (i32.const 0))) + (local.set 0x235 (i64.load offset=0x235 align=1 (i32.const 0))) + (local.set 0x236 (i64.load offset=0x236 align=1 (i32.const 0))) + (local.set 0x237 (i64.load offset=0x237 align=1 (i32.const 0))) + (local.set 0x238 (i64.load offset=0x238 align=1 (i32.const 0))) + (local.set 0x239 (i64.load offset=0x239 align=1 (i32.const 0))) + (local.set 0x23a (i64.load offset=0x23a align=1 (i32.const 0))) + (local.set 0x23b (i64.load offset=0x23b align=1 (i32.const 0))) + (local.set 0x23c (i64.load offset=0x23c align=1 (i32.const 0))) + (local.set 0x23d (i64.load offset=0x23d align=1 (i32.const 0))) + (local.set 0x23e (i64.load offset=0x23e align=1 (i32.const 0))) + (local.set 0x23f (i64.load offset=0x23f align=1 (i32.const 0))) + (local.set 0x240 (i64.load offset=0x240 align=1 (i32.const 0))) + (local.set 0x241 (i64.load offset=0x241 align=1 (i32.const 0))) + (local.set 0x242 (i64.load offset=0x242 align=1 (i32.const 0))) + (local.set 0x243 (i64.load offset=0x243 align=1 (i32.const 0))) + (local.set 0x244 (i64.load offset=0x244 align=1 (i32.const 0))) + (local.set 0x245 (i64.load offset=0x245 align=1 (i32.const 0))) + (local.set 0x246 (i64.load offset=0x246 align=1 (i32.const 0))) + (local.set 0x247 (i64.load offset=0x247 align=1 (i32.const 0))) + (local.set 0x248 (i64.load offset=0x248 align=1 (i32.const 0))) + (local.set 0x249 (i64.load offset=0x249 align=1 (i32.const 0))) + (local.set 0x24a (i64.load offset=0x24a align=1 (i32.const 0))) + (local.set 0x24b (i64.load offset=0x24b align=1 (i32.const 0))) + (local.set 0x24c (i64.load offset=0x24c align=1 (i32.const 0))) + (local.set 0x24d (i64.load offset=0x24d align=1 (i32.const 0))) + (local.set 0x24e (i64.load offset=0x24e align=1 (i32.const 0))) + (local.set 0x24f (i64.load offset=0x24f align=1 (i32.const 0))) + (local.set 0x250 (i64.load offset=0x250 align=1 (i32.const 0))) + (local.set 0x251 (i64.load offset=0x251 align=1 (i32.const 0))) + (local.set 0x252 (i64.load offset=0x252 align=1 (i32.const 0))) + (local.set 0x253 (i64.load offset=0x253 align=1 (i32.const 0))) + (local.set 0x254 (i64.load offset=0x254 align=1 (i32.const 0))) + (local.set 0x255 (i64.load offset=0x255 align=1 (i32.const 0))) + (local.set 0x256 (i64.load offset=0x256 align=1 (i32.const 0))) + (local.set 0x257 (i64.load offset=0x257 align=1 (i32.const 0))) + (local.set 0x258 (i64.load offset=0x258 align=1 (i32.const 0))) + (local.set 0x259 (i64.load offset=0x259 align=1 (i32.const 0))) + (local.set 0x25a (i64.load offset=0x25a align=1 (i32.const 0))) + (local.set 0x25b (i64.load offset=0x25b align=1 (i32.const 0))) + (local.set 0x25c (i64.load offset=0x25c align=1 (i32.const 0))) + (local.set 0x25d (i64.load offset=0x25d align=1 (i32.const 0))) + (local.set 0x25e (i64.load offset=0x25e align=1 (i32.const 0))) + (local.set 0x25f (i64.load offset=0x25f align=1 (i32.const 0))) + (local.set 0x260 (i64.load offset=0x260 align=1 (i32.const 0))) + (local.set 0x261 (i64.load offset=0x261 align=1 (i32.const 0))) + (local.set 0x262 (i64.load offset=0x262 align=1 (i32.const 0))) + (local.set 0x263 (i64.load offset=0x263 align=1 (i32.const 0))) + (local.set 0x264 (i64.load offset=0x264 align=1 (i32.const 0))) + (local.set 0x265 (i64.load offset=0x265 align=1 (i32.const 0))) + (local.set 0x266 (i64.load offset=0x266 align=1 (i32.const 0))) + (local.set 0x267 (i64.load offset=0x267 align=1 (i32.const 0))) + (local.set 0x268 (i64.load offset=0x268 align=1 (i32.const 0))) + (local.set 0x269 (i64.load offset=0x269 align=1 (i32.const 0))) + (local.set 0x26a (i64.load offset=0x26a align=1 (i32.const 0))) + (local.set 0x26b (i64.load offset=0x26b align=1 (i32.const 0))) + (local.set 0x26c (i64.load offset=0x26c align=1 (i32.const 0))) + (local.set 0x26d (i64.load offset=0x26d align=1 (i32.const 0))) + (local.set 0x26e (i64.load offset=0x26e align=1 (i32.const 0))) + (local.set 0x26f (i64.load offset=0x26f align=1 (i32.const 0))) + (local.set 0x270 (i64.load offset=0x270 align=1 (i32.const 0))) + (local.set 0x271 (i64.load offset=0x271 align=1 (i32.const 0))) + (local.set 0x272 (i64.load offset=0x272 align=1 (i32.const 0))) + (local.set 0x273 (i64.load offset=0x273 align=1 (i32.const 0))) + (local.set 0x274 (i64.load offset=0x274 align=1 (i32.const 0))) + (local.set 0x275 (i64.load offset=0x275 align=1 (i32.const 0))) + (local.set 0x276 (i64.load offset=0x276 align=1 (i32.const 0))) + (local.set 0x277 (i64.load offset=0x277 align=1 (i32.const 0))) + (local.set 0x278 (i64.load offset=0x278 align=1 (i32.const 0))) + (local.set 0x279 (i64.load offset=0x279 align=1 (i32.const 0))) + (local.set 0x27a (i64.load offset=0x27a align=1 (i32.const 0))) + (local.set 0x27b (i64.load offset=0x27b align=1 (i32.const 0))) + (local.set 0x27c (i64.load offset=0x27c align=1 (i32.const 0))) + (local.set 0x27d (i64.load offset=0x27d align=1 (i32.const 0))) + (local.set 0x27e (i64.load offset=0x27e align=1 (i32.const 0))) + (local.set 0x27f (i64.load offset=0x27f align=1 (i32.const 0))) + (local.set 0x280 (i64.load offset=0x280 align=1 (i32.const 0))) + (local.set 0x281 (i64.load offset=0x281 align=1 (i32.const 0))) + (local.set 0x282 (i64.load offset=0x282 align=1 (i32.const 0))) + (local.set 0x283 (i64.load offset=0x283 align=1 (i32.const 0))) + (local.set 0x284 (i64.load offset=0x284 align=1 (i32.const 0))) + (local.set 0x285 (i64.load offset=0x285 align=1 (i32.const 0))) + (local.set 0x286 (i64.load offset=0x286 align=1 (i32.const 0))) + (local.set 0x287 (i64.load offset=0x287 align=1 (i32.const 0))) + (local.set 0x288 (i64.load offset=0x288 align=1 (i32.const 0))) + (local.set 0x289 (i64.load offset=0x289 align=1 (i32.const 0))) + (local.set 0x28a (i64.load offset=0x28a align=1 (i32.const 0))) + (local.set 0x28b (i64.load offset=0x28b align=1 (i32.const 0))) + (local.set 0x28c (i64.load offset=0x28c align=1 (i32.const 0))) + (local.set 0x28d (i64.load offset=0x28d align=1 (i32.const 0))) + (local.set 0x28e (i64.load offset=0x28e align=1 (i32.const 0))) + (local.set 0x28f (i64.load offset=0x28f align=1 (i32.const 0))) + (local.set 0x290 (i64.load offset=0x290 align=1 (i32.const 0))) + (local.set 0x291 (i64.load offset=0x291 align=1 (i32.const 0))) + (local.set 0x292 (i64.load offset=0x292 align=1 (i32.const 0))) + (local.set 0x293 (i64.load offset=0x293 align=1 (i32.const 0))) + (local.set 0x294 (i64.load offset=0x294 align=1 (i32.const 0))) + (local.set 0x295 (i64.load offset=0x295 align=1 (i32.const 0))) + (local.set 0x296 (i64.load offset=0x296 align=1 (i32.const 0))) + (local.set 0x297 (i64.load offset=0x297 align=1 (i32.const 0))) + (local.set 0x298 (i64.load offset=0x298 align=1 (i32.const 0))) + (local.set 0x299 (i64.load offset=0x299 align=1 (i32.const 0))) + (local.set 0x29a (i64.load offset=0x29a align=1 (i32.const 0))) + (local.set 0x29b (i64.load offset=0x29b align=1 (i32.const 0))) + (local.set 0x29c (i64.load offset=0x29c align=1 (i32.const 0))) + (local.set 0x29d (i64.load offset=0x29d align=1 (i32.const 0))) + (local.set 0x29e (i64.load offset=0x29e align=1 (i32.const 0))) + (local.set 0x29f (i64.load offset=0x29f align=1 (i32.const 0))) + (local.set 0x2a0 (i64.load offset=0x2a0 align=1 (i32.const 0))) + (local.set 0x2a1 (i64.load offset=0x2a1 align=1 (i32.const 0))) + (local.set 0x2a2 (i64.load offset=0x2a2 align=1 (i32.const 0))) + (local.set 0x2a3 (i64.load offset=0x2a3 align=1 (i32.const 0))) + (local.set 0x2a4 (i64.load offset=0x2a4 align=1 (i32.const 0))) + (local.set 0x2a5 (i64.load offset=0x2a5 align=1 (i32.const 0))) + (local.set 0x2a6 (i64.load offset=0x2a6 align=1 (i32.const 0))) + (local.set 0x2a7 (i64.load offset=0x2a7 align=1 (i32.const 0))) + (local.set 0x2a8 (i64.load offset=0x2a8 align=1 (i32.const 0))) + (local.set 0x2a9 (i64.load offset=0x2a9 align=1 (i32.const 0))) + (local.set 0x2aa (i64.load offset=0x2aa align=1 (i32.const 0))) + (local.set 0x2ab (i64.load offset=0x2ab align=1 (i32.const 0))) + (local.set 0x2ac (i64.load offset=0x2ac align=1 (i32.const 0))) + (local.set 0x2ad (i64.load offset=0x2ad align=1 (i32.const 0))) + (local.set 0x2ae (i64.load offset=0x2ae align=1 (i32.const 0))) + (local.set 0x2af (i64.load offset=0x2af align=1 (i32.const 0))) + (local.set 0x2b0 (i64.load offset=0x2b0 align=1 (i32.const 0))) + (local.set 0x2b1 (i64.load offset=0x2b1 align=1 (i32.const 0))) + (local.set 0x2b2 (i64.load offset=0x2b2 align=1 (i32.const 0))) + (local.set 0x2b3 (i64.load offset=0x2b3 align=1 (i32.const 0))) + (local.set 0x2b4 (i64.load offset=0x2b4 align=1 (i32.const 0))) + (local.set 0x2b5 (i64.load offset=0x2b5 align=1 (i32.const 0))) + (local.set 0x2b6 (i64.load offset=0x2b6 align=1 (i32.const 0))) + (local.set 0x2b7 (i64.load offset=0x2b7 align=1 (i32.const 0))) + (local.set 0x2b8 (i64.load offset=0x2b8 align=1 (i32.const 0))) + (local.set 0x2b9 (i64.load offset=0x2b9 align=1 (i32.const 0))) + (local.set 0x2ba (i64.load offset=0x2ba align=1 (i32.const 0))) + (local.set 0x2bb (i64.load offset=0x2bb align=1 (i32.const 0))) + (local.set 0x2bc (i64.load offset=0x2bc align=1 (i32.const 0))) + (local.set 0x2bd (i64.load offset=0x2bd align=1 (i32.const 0))) + (local.set 0x2be (i64.load offset=0x2be align=1 (i32.const 0))) + (local.set 0x2bf (i64.load offset=0x2bf align=1 (i32.const 0))) + (local.set 0x2c0 (i64.load offset=0x2c0 align=1 (i32.const 0))) + (local.set 0x2c1 (i64.load offset=0x2c1 align=1 (i32.const 0))) + (local.set 0x2c2 (i64.load offset=0x2c2 align=1 (i32.const 0))) + (local.set 0x2c3 (i64.load offset=0x2c3 align=1 (i32.const 0))) + (local.set 0x2c4 (i64.load offset=0x2c4 align=1 (i32.const 0))) + (local.set 0x2c5 (i64.load offset=0x2c5 align=1 (i32.const 0))) + (local.set 0x2c6 (i64.load offset=0x2c6 align=1 (i32.const 0))) + (local.set 0x2c7 (i64.load offset=0x2c7 align=1 (i32.const 0))) + (local.set 0x2c8 (i64.load offset=0x2c8 align=1 (i32.const 0))) + (local.set 0x2c9 (i64.load offset=0x2c9 align=1 (i32.const 0))) + (local.set 0x2ca (i64.load offset=0x2ca align=1 (i32.const 0))) + (local.set 0x2cb (i64.load offset=0x2cb align=1 (i32.const 0))) + (local.set 0x2cc (i64.load offset=0x2cc align=1 (i32.const 0))) + (local.set 0x2cd (i64.load offset=0x2cd align=1 (i32.const 0))) + (local.set 0x2ce (i64.load offset=0x2ce align=1 (i32.const 0))) + (local.set 0x2cf (i64.load offset=0x2cf align=1 (i32.const 0))) + (local.set 0x2d0 (i64.load offset=0x2d0 align=1 (i32.const 0))) + (local.set 0x2d1 (i64.load offset=0x2d1 align=1 (i32.const 0))) + (local.set 0x2d2 (i64.load offset=0x2d2 align=1 (i32.const 0))) + (local.set 0x2d3 (i64.load offset=0x2d3 align=1 (i32.const 0))) + (local.set 0x2d4 (i64.load offset=0x2d4 align=1 (i32.const 0))) + (local.set 0x2d5 (i64.load offset=0x2d5 align=1 (i32.const 0))) + (local.set 0x2d6 (i64.load offset=0x2d6 align=1 (i32.const 0))) + (local.set 0x2d7 (i64.load offset=0x2d7 align=1 (i32.const 0))) + (local.set 0x2d8 (i64.load offset=0x2d8 align=1 (i32.const 0))) + (local.set 0x2d9 (i64.load offset=0x2d9 align=1 (i32.const 0))) + (local.set 0x2da (i64.load offset=0x2da align=1 (i32.const 0))) + (local.set 0x2db (i64.load offset=0x2db align=1 (i32.const 0))) + (local.set 0x2dc (i64.load offset=0x2dc align=1 (i32.const 0))) + (local.set 0x2dd (i64.load offset=0x2dd align=1 (i32.const 0))) + (local.set 0x2de (i64.load offset=0x2de align=1 (i32.const 0))) + (local.set 0x2df (i64.load offset=0x2df align=1 (i32.const 0))) + (local.set 0x2e0 (i64.load offset=0x2e0 align=1 (i32.const 0))) + (local.set 0x2e1 (i64.load offset=0x2e1 align=1 (i32.const 0))) + (local.set 0x2e2 (i64.load offset=0x2e2 align=1 (i32.const 0))) + (local.set 0x2e3 (i64.load offset=0x2e3 align=1 (i32.const 0))) + (local.set 0x2e4 (i64.load offset=0x2e4 align=1 (i32.const 0))) + (local.set 0x2e5 (i64.load offset=0x2e5 align=1 (i32.const 0))) + (local.set 0x2e6 (i64.load offset=0x2e6 align=1 (i32.const 0))) + (local.set 0x2e7 (i64.load offset=0x2e7 align=1 (i32.const 0))) + (local.set 0x2e8 (i64.load offset=0x2e8 align=1 (i32.const 0))) + (local.set 0x2e9 (i64.load offset=0x2e9 align=1 (i32.const 0))) + (local.set 0x2ea (i64.load offset=0x2ea align=1 (i32.const 0))) + (local.set 0x2eb (i64.load offset=0x2eb align=1 (i32.const 0))) + (local.set 0x2ec (i64.load offset=0x2ec align=1 (i32.const 0))) + (local.set 0x2ed (i64.load offset=0x2ed align=1 (i32.const 0))) + (local.set 0x2ee (i64.load offset=0x2ee align=1 (i32.const 0))) + (local.set 0x2ef (i64.load offset=0x2ef align=1 (i32.const 0))) + (local.set 0x2f0 (i64.load offset=0x2f0 align=1 (i32.const 0))) + (local.set 0x2f1 (i64.load offset=0x2f1 align=1 (i32.const 0))) + (local.set 0x2f2 (i64.load offset=0x2f2 align=1 (i32.const 0))) + (local.set 0x2f3 (i64.load offset=0x2f3 align=1 (i32.const 0))) + (local.set 0x2f4 (i64.load offset=0x2f4 align=1 (i32.const 0))) + (local.set 0x2f5 (i64.load offset=0x2f5 align=1 (i32.const 0))) + (local.set 0x2f6 (i64.load offset=0x2f6 align=1 (i32.const 0))) + (local.set 0x2f7 (i64.load offset=0x2f7 align=1 (i32.const 0))) + (local.set 0x2f8 (i64.load offset=0x2f8 align=1 (i32.const 0))) + (local.set 0x2f9 (i64.load offset=0x2f9 align=1 (i32.const 0))) + (local.set 0x2fa (i64.load offset=0x2fa align=1 (i32.const 0))) + (local.set 0x2fb (i64.load offset=0x2fb align=1 (i32.const 0))) + (local.set 0x2fc (i64.load offset=0x2fc align=1 (i32.const 0))) + (local.set 0x2fd (i64.load offset=0x2fd align=1 (i32.const 0))) + (local.set 0x2fe (i64.load offset=0x2fe align=1 (i32.const 0))) + (local.set 0x2ff (i64.load offset=0x2ff align=1 (i32.const 0))) + (local.set 0x300 (i64.load offset=0x300 align=1 (i32.const 0))) + (local.set 0x301 (i64.load offset=0x301 align=1 (i32.const 0))) + (local.set 0x302 (i64.load offset=0x302 align=1 (i32.const 0))) + (local.set 0x303 (i64.load offset=0x303 align=1 (i32.const 0))) + (local.set 0x304 (i64.load offset=0x304 align=1 (i32.const 0))) + (local.set 0x305 (i64.load offset=0x305 align=1 (i32.const 0))) + (local.set 0x306 (i64.load offset=0x306 align=1 (i32.const 0))) + (local.set 0x307 (i64.load offset=0x307 align=1 (i32.const 0))) + (local.set 0x308 (i64.load offset=0x308 align=1 (i32.const 0))) + (local.set 0x309 (i64.load offset=0x309 align=1 (i32.const 0))) + (local.set 0x30a (i64.load offset=0x30a align=1 (i32.const 0))) + (local.set 0x30b (i64.load offset=0x30b align=1 (i32.const 0))) + (local.set 0x30c (i64.load offset=0x30c align=1 (i32.const 0))) + (local.set 0x30d (i64.load offset=0x30d align=1 (i32.const 0))) + (local.set 0x30e (i64.load offset=0x30e align=1 (i32.const 0))) + (local.set 0x30f (i64.load offset=0x30f align=1 (i32.const 0))) + (local.set 0x310 (i64.load offset=0x310 align=1 (i32.const 0))) + (local.set 0x311 (i64.load offset=0x311 align=1 (i32.const 0))) + (local.set 0x312 (i64.load offset=0x312 align=1 (i32.const 0))) + (local.set 0x313 (i64.load offset=0x313 align=1 (i32.const 0))) + (local.set 0x314 (i64.load offset=0x314 align=1 (i32.const 0))) + (local.set 0x315 (i64.load offset=0x315 align=1 (i32.const 0))) + (local.set 0x316 (i64.load offset=0x316 align=1 (i32.const 0))) + (local.set 0x317 (i64.load offset=0x317 align=1 (i32.const 0))) + (local.set 0x318 (i64.load offset=0x318 align=1 (i32.const 0))) + (local.set 0x319 (i64.load offset=0x319 align=1 (i32.const 0))) + (local.set 0x31a (i64.load offset=0x31a align=1 (i32.const 0))) + (local.set 0x31b (i64.load offset=0x31b align=1 (i32.const 0))) + (local.set 0x31c (i64.load offset=0x31c align=1 (i32.const 0))) + (local.set 0x31d (i64.load offset=0x31d align=1 (i32.const 0))) + (local.set 0x31e (i64.load offset=0x31e align=1 (i32.const 0))) + (local.set 0x31f (i64.load offset=0x31f align=1 (i32.const 0))) + (local.set 0x320 (i64.load offset=0x320 align=1 (i32.const 0))) + (local.set 0x321 (i64.load offset=0x321 align=1 (i32.const 0))) + (local.set 0x322 (i64.load offset=0x322 align=1 (i32.const 0))) + (local.set 0x323 (i64.load offset=0x323 align=1 (i32.const 0))) + (local.set 0x324 (i64.load offset=0x324 align=1 (i32.const 0))) + (local.set 0x325 (i64.load offset=0x325 align=1 (i32.const 0))) + (local.set 0x326 (i64.load offset=0x326 align=1 (i32.const 0))) + (local.set 0x327 (i64.load offset=0x327 align=1 (i32.const 0))) + (local.set 0x328 (i64.load offset=0x328 align=1 (i32.const 0))) + (local.set 0x329 (i64.load offset=0x329 align=1 (i32.const 0))) + (local.set 0x32a (i64.load offset=0x32a align=1 (i32.const 0))) + (local.set 0x32b (i64.load offset=0x32b align=1 (i32.const 0))) + (local.set 0x32c (i64.load offset=0x32c align=1 (i32.const 0))) + (local.set 0x32d (i64.load offset=0x32d align=1 (i32.const 0))) + (local.set 0x32e (i64.load offset=0x32e align=1 (i32.const 0))) + (local.set 0x32f (i64.load offset=0x32f align=1 (i32.const 0))) + (local.set 0x330 (i64.load offset=0x330 align=1 (i32.const 0))) + (local.set 0x331 (i64.load offset=0x331 align=1 (i32.const 0))) + (local.set 0x332 (i64.load offset=0x332 align=1 (i32.const 0))) + (local.set 0x333 (i64.load offset=0x333 align=1 (i32.const 0))) + (local.set 0x334 (i64.load offset=0x334 align=1 (i32.const 0))) + (local.set 0x335 (i64.load offset=0x335 align=1 (i32.const 0))) + (local.set 0x336 (i64.load offset=0x336 align=1 (i32.const 0))) + (local.set 0x337 (i64.load offset=0x337 align=1 (i32.const 0))) + (local.set 0x338 (i64.load offset=0x338 align=1 (i32.const 0))) + (local.set 0x339 (i64.load offset=0x339 align=1 (i32.const 0))) + (local.set 0x33a (i64.load offset=0x33a align=1 (i32.const 0))) + (local.set 0x33b (i64.load offset=0x33b align=1 (i32.const 0))) + (local.set 0x33c (i64.load offset=0x33c align=1 (i32.const 0))) + (local.set 0x33d (i64.load offset=0x33d align=1 (i32.const 0))) + (local.set 0x33e (i64.load offset=0x33e align=1 (i32.const 0))) + (local.set 0x33f (i64.load offset=0x33f align=1 (i32.const 0))) + (local.set 0x340 (i64.load offset=0x340 align=1 (i32.const 0))) + (local.set 0x341 (i64.load offset=0x341 align=1 (i32.const 0))) + (local.set 0x342 (i64.load offset=0x342 align=1 (i32.const 0))) + (local.set 0x343 (i64.load offset=0x343 align=1 (i32.const 0))) + (local.set 0x344 (i64.load offset=0x344 align=1 (i32.const 0))) + (local.set 0x345 (i64.load offset=0x345 align=1 (i32.const 0))) + (local.set 0x346 (i64.load offset=0x346 align=1 (i32.const 0))) + (local.set 0x347 (i64.load offset=0x347 align=1 (i32.const 0))) + (local.set 0x348 (i64.load offset=0x348 align=1 (i32.const 0))) + (local.set 0x349 (i64.load offset=0x349 align=1 (i32.const 0))) + (local.set 0x34a (i64.load offset=0x34a align=1 (i32.const 0))) + (local.set 0x34b (i64.load offset=0x34b align=1 (i32.const 0))) + (local.set 0x34c (i64.load offset=0x34c align=1 (i32.const 0))) + (local.set 0x34d (i64.load offset=0x34d align=1 (i32.const 0))) + (local.set 0x34e (i64.load offset=0x34e align=1 (i32.const 0))) + (local.set 0x34f (i64.load offset=0x34f align=1 (i32.const 0))) + (local.set 0x350 (i64.load offset=0x350 align=1 (i32.const 0))) + (local.set 0x351 (i64.load offset=0x351 align=1 (i32.const 0))) + (local.set 0x352 (i64.load offset=0x352 align=1 (i32.const 0))) + (local.set 0x353 (i64.load offset=0x353 align=1 (i32.const 0))) + (local.set 0x354 (i64.load offset=0x354 align=1 (i32.const 0))) + (local.set 0x355 (i64.load offset=0x355 align=1 (i32.const 0))) + (local.set 0x356 (i64.load offset=0x356 align=1 (i32.const 0))) + (local.set 0x357 (i64.load offset=0x357 align=1 (i32.const 0))) + (local.set 0x358 (i64.load offset=0x358 align=1 (i32.const 0))) + (local.set 0x359 (i64.load offset=0x359 align=1 (i32.const 0))) + (local.set 0x35a (i64.load offset=0x35a align=1 (i32.const 0))) + (local.set 0x35b (i64.load offset=0x35b align=1 (i32.const 0))) + (local.set 0x35c (i64.load offset=0x35c align=1 (i32.const 0))) + (local.set 0x35d (i64.load offset=0x35d align=1 (i32.const 0))) + (local.set 0x35e (i64.load offset=0x35e align=1 (i32.const 0))) + (local.set 0x35f (i64.load offset=0x35f align=1 (i32.const 0))) + (local.set 0x360 (i64.load offset=0x360 align=1 (i32.const 0))) + (local.set 0x361 (i64.load offset=0x361 align=1 (i32.const 0))) + (local.set 0x362 (i64.load offset=0x362 align=1 (i32.const 0))) + (local.set 0x363 (i64.load offset=0x363 align=1 (i32.const 0))) + (local.set 0x364 (i64.load offset=0x364 align=1 (i32.const 0))) + (local.set 0x365 (i64.load offset=0x365 align=1 (i32.const 0))) + (local.set 0x366 (i64.load offset=0x366 align=1 (i32.const 0))) + (local.set 0x367 (i64.load offset=0x367 align=1 (i32.const 0))) + (local.set 0x368 (i64.load offset=0x368 align=1 (i32.const 0))) + (local.set 0x369 (i64.load offset=0x369 align=1 (i32.const 0))) + (local.set 0x36a (i64.load offset=0x36a align=1 (i32.const 0))) + (local.set 0x36b (i64.load offset=0x36b align=1 (i32.const 0))) + (local.set 0x36c (i64.load offset=0x36c align=1 (i32.const 0))) + (local.set 0x36d (i64.load offset=0x36d align=1 (i32.const 0))) + (local.set 0x36e (i64.load offset=0x36e align=1 (i32.const 0))) + (local.set 0x36f (i64.load offset=0x36f align=1 (i32.const 0))) + (local.set 0x370 (i64.load offset=0x370 align=1 (i32.const 0))) + (local.set 0x371 (i64.load offset=0x371 align=1 (i32.const 0))) + (local.set 0x372 (i64.load offset=0x372 align=1 (i32.const 0))) + (local.set 0x373 (i64.load offset=0x373 align=1 (i32.const 0))) + (local.set 0x374 (i64.load offset=0x374 align=1 (i32.const 0))) + (local.set 0x375 (i64.load offset=0x375 align=1 (i32.const 0))) + (local.set 0x376 (i64.load offset=0x376 align=1 (i32.const 0))) + (local.set 0x377 (i64.load offset=0x377 align=1 (i32.const 0))) + (local.set 0x378 (i64.load offset=0x378 align=1 (i32.const 0))) + (local.set 0x379 (i64.load offset=0x379 align=1 (i32.const 0))) + (local.set 0x37a (i64.load offset=0x37a align=1 (i32.const 0))) + (local.set 0x37b (i64.load offset=0x37b align=1 (i32.const 0))) + (local.set 0x37c (i64.load offset=0x37c align=1 (i32.const 0))) + (local.set 0x37d (i64.load offset=0x37d align=1 (i32.const 0))) + (local.set 0x37e (i64.load offset=0x37e align=1 (i32.const 0))) + (local.set 0x37f (i64.load offset=0x37f align=1 (i32.const 0))) + (local.set 0x380 (i64.load offset=0x380 align=1 (i32.const 0))) + (local.set 0x381 (i64.load offset=0x381 align=1 (i32.const 0))) + (local.set 0x382 (i64.load offset=0x382 align=1 (i32.const 0))) + (local.set 0x383 (i64.load offset=0x383 align=1 (i32.const 0))) + (local.set 0x384 (i64.load offset=0x384 align=1 (i32.const 0))) + (local.set 0x385 (i64.load offset=0x385 align=1 (i32.const 0))) + (local.set 0x386 (i64.load offset=0x386 align=1 (i32.const 0))) + (local.set 0x387 (i64.load offset=0x387 align=1 (i32.const 0))) + (local.set 0x388 (i64.load offset=0x388 align=1 (i32.const 0))) + (local.set 0x389 (i64.load offset=0x389 align=1 (i32.const 0))) + (local.set 0x38a (i64.load offset=0x38a align=1 (i32.const 0))) + (local.set 0x38b (i64.load offset=0x38b align=1 (i32.const 0))) + (local.set 0x38c (i64.load offset=0x38c align=1 (i32.const 0))) + (local.set 0x38d (i64.load offset=0x38d align=1 (i32.const 0))) + (local.set 0x38e (i64.load offset=0x38e align=1 (i32.const 0))) + (local.set 0x38f (i64.load offset=0x38f align=1 (i32.const 0))) + (local.set 0x390 (i64.load offset=0x390 align=1 (i32.const 0))) + (local.set 0x391 (i64.load offset=0x391 align=1 (i32.const 0))) + (local.set 0x392 (i64.load offset=0x392 align=1 (i32.const 0))) + (local.set 0x393 (i64.load offset=0x393 align=1 (i32.const 0))) + (local.set 0x394 (i64.load offset=0x394 align=1 (i32.const 0))) + (local.set 0x395 (i64.load offset=0x395 align=1 (i32.const 0))) + (local.set 0x396 (i64.load offset=0x396 align=1 (i32.const 0))) + (local.set 0x397 (i64.load offset=0x397 align=1 (i32.const 0))) + (local.set 0x398 (i64.load offset=0x398 align=1 (i32.const 0))) + (local.set 0x399 (i64.load offset=0x399 align=1 (i32.const 0))) + (local.set 0x39a (i64.load offset=0x39a align=1 (i32.const 0))) + (local.set 0x39b (i64.load offset=0x39b align=1 (i32.const 0))) + (local.set 0x39c (i64.load offset=0x39c align=1 (i32.const 0))) + (local.set 0x39d (i64.load offset=0x39d align=1 (i32.const 0))) + (local.set 0x39e (i64.load offset=0x39e align=1 (i32.const 0))) + (local.set 0x39f (i64.load offset=0x39f align=1 (i32.const 0))) + (local.set 0x3a0 (i64.load offset=0x3a0 align=1 (i32.const 0))) + (local.set 0x3a1 (i64.load offset=0x3a1 align=1 (i32.const 0))) + (local.set 0x3a2 (i64.load offset=0x3a2 align=1 (i32.const 0))) + (local.set 0x3a3 (i64.load offset=0x3a3 align=1 (i32.const 0))) + (local.set 0x3a4 (i64.load offset=0x3a4 align=1 (i32.const 0))) + (local.set 0x3a5 (i64.load offset=0x3a5 align=1 (i32.const 0))) + (local.set 0x3a6 (i64.load offset=0x3a6 align=1 (i32.const 0))) + (local.set 0x3a7 (i64.load offset=0x3a7 align=1 (i32.const 0))) + (local.set 0x3a8 (i64.load offset=0x3a8 align=1 (i32.const 0))) + (local.set 0x3a9 (i64.load offset=0x3a9 align=1 (i32.const 0))) + (local.set 0x3aa (i64.load offset=0x3aa align=1 (i32.const 0))) + (local.set 0x3ab (i64.load offset=0x3ab align=1 (i32.const 0))) + (local.set 0x3ac (i64.load offset=0x3ac align=1 (i32.const 0))) + (local.set 0x3ad (i64.load offset=0x3ad align=1 (i32.const 0))) + (local.set 0x3ae (i64.load offset=0x3ae align=1 (i32.const 0))) + (local.set 0x3af (i64.load offset=0x3af align=1 (i32.const 0))) + (local.set 0x3b0 (i64.load offset=0x3b0 align=1 (i32.const 0))) + (local.set 0x3b1 (i64.load offset=0x3b1 align=1 (i32.const 0))) + (local.set 0x3b2 (i64.load offset=0x3b2 align=1 (i32.const 0))) + (local.set 0x3b3 (i64.load offset=0x3b3 align=1 (i32.const 0))) + (local.set 0x3b4 (i64.load offset=0x3b4 align=1 (i32.const 0))) + (local.set 0x3b5 (i64.load offset=0x3b5 align=1 (i32.const 0))) + (local.set 0x3b6 (i64.load offset=0x3b6 align=1 (i32.const 0))) + (local.set 0x3b7 (i64.load offset=0x3b7 align=1 (i32.const 0))) + (local.set 0x3b8 (i64.load offset=0x3b8 align=1 (i32.const 0))) + (local.set 0x3b9 (i64.load offset=0x3b9 align=1 (i32.const 0))) + (local.set 0x3ba (i64.load offset=0x3ba align=1 (i32.const 0))) + (local.set 0x3bb (i64.load offset=0x3bb align=1 (i32.const 0))) + (local.set 0x3bc (i64.load offset=0x3bc align=1 (i32.const 0))) + (local.set 0x3bd (i64.load offset=0x3bd align=1 (i32.const 0))) + (local.set 0x3be (i64.load offset=0x3be align=1 (i32.const 0))) + (local.set 0x3bf (i64.load offset=0x3bf align=1 (i32.const 0))) + (local.set 0x3c0 (i64.load offset=0x3c0 align=1 (i32.const 0))) + (local.set 0x3c1 (i64.load offset=0x3c1 align=1 (i32.const 0))) + (local.set 0x3c2 (i64.load offset=0x3c2 align=1 (i32.const 0))) + (local.set 0x3c3 (i64.load offset=0x3c3 align=1 (i32.const 0))) + (local.set 0x3c4 (i64.load offset=0x3c4 align=1 (i32.const 0))) + (local.set 0x3c5 (i64.load offset=0x3c5 align=1 (i32.const 0))) + (local.set 0x3c6 (i64.load offset=0x3c6 align=1 (i32.const 0))) + (local.set 0x3c7 (i64.load offset=0x3c7 align=1 (i32.const 0))) + (local.set 0x3c8 (i64.load offset=0x3c8 align=1 (i32.const 0))) + (local.set 0x3c9 (i64.load offset=0x3c9 align=1 (i32.const 0))) + (local.set 0x3ca (i64.load offset=0x3ca align=1 (i32.const 0))) + (local.set 0x3cb (i64.load offset=0x3cb align=1 (i32.const 0))) + (local.set 0x3cc (i64.load offset=0x3cc align=1 (i32.const 0))) + (local.set 0x3cd (i64.load offset=0x3cd align=1 (i32.const 0))) + (local.set 0x3ce (i64.load offset=0x3ce align=1 (i32.const 0))) + (local.set 0x3cf (i64.load offset=0x3cf align=1 (i32.const 0))) + (local.set 0x3d0 (i64.load offset=0x3d0 align=1 (i32.const 0))) + (local.set 0x3d1 (i64.load offset=0x3d1 align=1 (i32.const 0))) + (local.set 0x3d2 (i64.load offset=0x3d2 align=1 (i32.const 0))) + (local.set 0x3d3 (i64.load offset=0x3d3 align=1 (i32.const 0))) + (local.set 0x3d4 (i64.load offset=0x3d4 align=1 (i32.const 0))) + (local.set 0x3d5 (i64.load offset=0x3d5 align=1 (i32.const 0))) + (local.set 0x3d6 (i64.load offset=0x3d6 align=1 (i32.const 0))) + (local.set 0x3d7 (i64.load offset=0x3d7 align=1 (i32.const 0))) + (local.set 0x3d8 (i64.load offset=0x3d8 align=1 (i32.const 0))) + (local.set 0x3d9 (i64.load offset=0x3d9 align=1 (i32.const 0))) + (local.set 0x3da (i64.load offset=0x3da align=1 (i32.const 0))) + (local.set 0x3db (i64.load offset=0x3db align=1 (i32.const 0))) + (local.set 0x3dc (i64.load offset=0x3dc align=1 (i32.const 0))) + (local.set 0x3dd (i64.load offset=0x3dd align=1 (i32.const 0))) + (local.set 0x3de (i64.load offset=0x3de align=1 (i32.const 0))) + (local.set 0x3df (i64.load offset=0x3df align=1 (i32.const 0))) + (local.set 0x3e0 (i64.load offset=0x3e0 align=1 (i32.const 0))) + (local.set 0x3e1 (i64.load offset=0x3e1 align=1 (i32.const 0))) + (local.set 0x3e2 (i64.load offset=0x3e2 align=1 (i32.const 0))) + (local.set 0x3e3 (i64.load offset=0x3e3 align=1 (i32.const 0))) + (local.set 0x3e4 (i64.load offset=0x3e4 align=1 (i32.const 0))) + (local.set 0x3e5 (i64.load offset=0x3e5 align=1 (i32.const 0))) + (local.set 0x3e6 (i64.load offset=0x3e6 align=1 (i32.const 0))) + (local.set 0x3e7 (i64.load offset=0x3e7 align=1 (i32.const 0))) + (local.set 0x3e8 (i64.load offset=0x3e8 align=1 (i32.const 0))) + (local.set 0x3e9 (i64.load offset=0x3e9 align=1 (i32.const 0))) + (local.set 0x3ea (i64.load offset=0x3ea align=1 (i32.const 0))) + (local.set 0x3eb (i64.load offset=0x3eb align=1 (i32.const 0))) + (local.set 0x3ec (i64.load offset=0x3ec align=1 (i32.const 0))) + (local.set 0x3ed (i64.load offset=0x3ed align=1 (i32.const 0))) + (local.set 0x3ee (i64.load offset=0x3ee align=1 (i32.const 0))) + (local.set 0x3ef (i64.load offset=0x3ef align=1 (i32.const 0))) + (local.set 0x3f0 (i64.load offset=0x3f0 align=1 (i32.const 0))) + (local.set 0x3f1 (i64.load offset=0x3f1 align=1 (i32.const 0))) + (local.set 0x3f2 (i64.load offset=0x3f2 align=1 (i32.const 0))) + (local.set 0x3f3 (i64.load offset=0x3f3 align=1 (i32.const 0))) + (local.set 0x3f4 (i64.load offset=0x3f4 align=1 (i32.const 0))) + (local.set 0x3f5 (i64.load offset=0x3f5 align=1 (i32.const 0))) + (local.set 0x3f6 (i64.load offset=0x3f6 align=1 (i32.const 0))) + (local.set 0x3f7 (i64.load offset=0x3f7 align=1 (i32.const 0))) + (local.set 0x3f8 (i64.load offset=0x3f8 align=1 (i32.const 0))) + (local.set 0x3f9 (i64.load offset=0x3f9 align=1 (i32.const 0))) + (local.set 0x3fa (i64.load offset=0x3fa align=1 (i32.const 0))) + (local.set 0x3fb (i64.load offset=0x3fb align=1 (i32.const 0))) + (local.set 0x3fc (i64.load offset=0x3fc align=1 (i32.const 0))) + (local.set 0x3fd (i64.load offset=0x3fd align=1 (i32.const 0))) + (local.set 0x3fe (i64.load offset=0x3fe align=1 (i32.const 0))) + (local.set 0x3ff (i64.load offset=0x3ff align=1 (i32.const 0))) + (local.set 0x400 (i64.load offset=0x400 align=1 (i32.const 0))) + (local.set 0x401 (i64.load offset=0x401 align=1 (i32.const 0))) + (local.set 0x402 (i64.load offset=0x402 align=1 (i32.const 0))) + (local.set 0x403 (i64.load offset=0x403 align=1 (i32.const 0))) + (local.set 0x404 (i64.load offset=0x404 align=1 (i32.const 0))) + (local.set 0x405 (i64.load offset=0x405 align=1 (i32.const 0))) + (local.set 0x406 (i64.load offset=0x406 align=1 (i32.const 0))) + (local.set 0x407 (i64.load offset=0x407 align=1 (i32.const 0))) + (local.set 0x408 (i64.load offset=0x408 align=1 (i32.const 0))) + (local.set 0x409 (i64.load offset=0x409 align=1 (i32.const 0))) + (local.set 0x40a (i64.load offset=0x40a align=1 (i32.const 0))) + (local.set 0x40b (i64.load offset=0x40b align=1 (i32.const 0))) + (local.set 0x40c (i64.load offset=0x40c align=1 (i32.const 0))) + (local.set 0x40d (i64.load offset=0x40d align=1 (i32.const 0))) + (local.set 0x40e (i64.load offset=0x40e align=1 (i32.const 0))) + (local.set 0x40f (i64.load offset=0x40f align=1 (i32.const 0))) + (local.set 0x410 (i64.load offset=0x410 align=1 (i32.const 0))) + (local.set 0x411 (i64.load offset=0x411 align=1 (i32.const 0))) + (local.set 0x412 (i64.load offset=0x412 align=1 (i32.const 0))) + (local.set 0x413 (i64.load offset=0x413 align=1 (i32.const 0))) + (local.set 0x414 (i64.load offset=0x414 align=1 (i32.const 0))) + (local.set 0x415 (i64.load offset=0x415 align=1 (i32.const 0))) + (local.set 0x416 (i64.load offset=0x416 align=1 (i32.const 0))) + (local.set 0x417 (i64.load offset=0x417 align=1 (i32.const 0))) + (local.set 0x418 (i64.load offset=0x418 align=1 (i32.const 0))) + (local.set 0x419 (i64.load offset=0x419 align=1 (i32.const 0))) + (local.set 0x41a (i64.load offset=0x41a align=1 (i32.const 0))) + (local.set 0x41b (i64.load offset=0x41b align=1 (i32.const 0))) + (local.set 0x41c (i64.load offset=0x41c align=1 (i32.const 0))) + (local.set 0x41d (i64.load offset=0x41d align=1 (i32.const 0))) + (local.set 0x41e (i64.load offset=0x41e align=1 (i32.const 0))) + (local.set 0x41f (i64.load offset=0x41f align=1 (i32.const 0))) + + ;; store the locals back to memory + (i64.store offset=0x000 align=1 (i32.const 0) (local.get 0x000)) + (i64.store offset=0x001 align=1 (i32.const 0) (local.get 0x001)) + (i64.store offset=0x002 align=1 (i32.const 0) (local.get 0x002)) + (i64.store offset=0x003 align=1 (i32.const 0) (local.get 0x003)) + (i64.store offset=0x004 align=1 (i32.const 0) (local.get 0x004)) + (i64.store offset=0x005 align=1 (i32.const 0) (local.get 0x005)) + (i64.store offset=0x006 align=1 (i32.const 0) (local.get 0x006)) + (i64.store offset=0x007 align=1 (i32.const 0) (local.get 0x007)) + (i64.store offset=0x008 align=1 (i32.const 0) (local.get 0x008)) + (i64.store offset=0x009 align=1 (i32.const 0) (local.get 0x009)) + (i64.store offset=0x00a align=1 (i32.const 0) (local.get 0x00a)) + (i64.store offset=0x00b align=1 (i32.const 0) (local.get 0x00b)) + (i64.store offset=0x00c align=1 (i32.const 0) (local.get 0x00c)) + (i64.store offset=0x00d align=1 (i32.const 0) (local.get 0x00d)) + (i64.store offset=0x00e align=1 (i32.const 0) (local.get 0x00e)) + (i64.store offset=0x00f align=1 (i32.const 0) (local.get 0x00f)) + (i64.store offset=0x010 align=1 (i32.const 0) (local.get 0x010)) + (i64.store offset=0x011 align=1 (i32.const 0) (local.get 0x011)) + (i64.store offset=0x012 align=1 (i32.const 0) (local.get 0x012)) + (i64.store offset=0x013 align=1 (i32.const 0) (local.get 0x013)) + (i64.store offset=0x014 align=1 (i32.const 0) (local.get 0x014)) + (i64.store offset=0x015 align=1 (i32.const 0) (local.get 0x015)) + (i64.store offset=0x016 align=1 (i32.const 0) (local.get 0x016)) + (i64.store offset=0x017 align=1 (i32.const 0) (local.get 0x017)) + (i64.store offset=0x018 align=1 (i32.const 0) (local.get 0x018)) + (i64.store offset=0x019 align=1 (i32.const 0) (local.get 0x019)) + (i64.store offset=0x01a align=1 (i32.const 0) (local.get 0x01a)) + (i64.store offset=0x01b align=1 (i32.const 0) (local.get 0x01b)) + (i64.store offset=0x01c align=1 (i32.const 0) (local.get 0x01c)) + (i64.store offset=0x01d align=1 (i32.const 0) (local.get 0x01d)) + (i64.store offset=0x01e align=1 (i32.const 0) (local.get 0x01e)) + (i64.store offset=0x01f align=1 (i32.const 0) (local.get 0x01f)) + (i64.store offset=0x020 align=1 (i32.const 0) (local.get 0x020)) + (i64.store offset=0x021 align=1 (i32.const 0) (local.get 0x021)) + (i64.store offset=0x022 align=1 (i32.const 0) (local.get 0x022)) + (i64.store offset=0x023 align=1 (i32.const 0) (local.get 0x023)) + (i64.store offset=0x024 align=1 (i32.const 0) (local.get 0x024)) + (i64.store offset=0x025 align=1 (i32.const 0) (local.get 0x025)) + (i64.store offset=0x026 align=1 (i32.const 0) (local.get 0x026)) + (i64.store offset=0x027 align=1 (i32.const 0) (local.get 0x027)) + (i64.store offset=0x028 align=1 (i32.const 0) (local.get 0x028)) + (i64.store offset=0x029 align=1 (i32.const 0) (local.get 0x029)) + (i64.store offset=0x02a align=1 (i32.const 0) (local.get 0x02a)) + (i64.store offset=0x02b align=1 (i32.const 0) (local.get 0x02b)) + (i64.store offset=0x02c align=1 (i32.const 0) (local.get 0x02c)) + (i64.store offset=0x02d align=1 (i32.const 0) (local.get 0x02d)) + (i64.store offset=0x02e align=1 (i32.const 0) (local.get 0x02e)) + (i64.store offset=0x02f align=1 (i32.const 0) (local.get 0x02f)) + (i64.store offset=0x030 align=1 (i32.const 0) (local.get 0x030)) + (i64.store offset=0x031 align=1 (i32.const 0) (local.get 0x031)) + (i64.store offset=0x032 align=1 (i32.const 0) (local.get 0x032)) + (i64.store offset=0x033 align=1 (i32.const 0) (local.get 0x033)) + (i64.store offset=0x034 align=1 (i32.const 0) (local.get 0x034)) + (i64.store offset=0x035 align=1 (i32.const 0) (local.get 0x035)) + (i64.store offset=0x036 align=1 (i32.const 0) (local.get 0x036)) + (i64.store offset=0x037 align=1 (i32.const 0) (local.get 0x037)) + (i64.store offset=0x038 align=1 (i32.const 0) (local.get 0x038)) + (i64.store offset=0x039 align=1 (i32.const 0) (local.get 0x039)) + (i64.store offset=0x03a align=1 (i32.const 0) (local.get 0x03a)) + (i64.store offset=0x03b align=1 (i32.const 0) (local.get 0x03b)) + (i64.store offset=0x03c align=1 (i32.const 0) (local.get 0x03c)) + (i64.store offset=0x03d align=1 (i32.const 0) (local.get 0x03d)) + (i64.store offset=0x03e align=1 (i32.const 0) (local.get 0x03e)) + (i64.store offset=0x03f align=1 (i32.const 0) (local.get 0x03f)) + (i64.store offset=0x040 align=1 (i32.const 0) (local.get 0x040)) + (i64.store offset=0x041 align=1 (i32.const 0) (local.get 0x041)) + (i64.store offset=0x042 align=1 (i32.const 0) (local.get 0x042)) + (i64.store offset=0x043 align=1 (i32.const 0) (local.get 0x043)) + (i64.store offset=0x044 align=1 (i32.const 0) (local.get 0x044)) + (i64.store offset=0x045 align=1 (i32.const 0) (local.get 0x045)) + (i64.store offset=0x046 align=1 (i32.const 0) (local.get 0x046)) + (i64.store offset=0x047 align=1 (i32.const 0) (local.get 0x047)) + (i64.store offset=0x048 align=1 (i32.const 0) (local.get 0x048)) + (i64.store offset=0x049 align=1 (i32.const 0) (local.get 0x049)) + (i64.store offset=0x04a align=1 (i32.const 0) (local.get 0x04a)) + (i64.store offset=0x04b align=1 (i32.const 0) (local.get 0x04b)) + (i64.store offset=0x04c align=1 (i32.const 0) (local.get 0x04c)) + (i64.store offset=0x04d align=1 (i32.const 0) (local.get 0x04d)) + (i64.store offset=0x04e align=1 (i32.const 0) (local.get 0x04e)) + (i64.store offset=0x04f align=1 (i32.const 0) (local.get 0x04f)) + (i64.store offset=0x050 align=1 (i32.const 0) (local.get 0x050)) + (i64.store offset=0x051 align=1 (i32.const 0) (local.get 0x051)) + (i64.store offset=0x052 align=1 (i32.const 0) (local.get 0x052)) + (i64.store offset=0x053 align=1 (i32.const 0) (local.get 0x053)) + (i64.store offset=0x054 align=1 (i32.const 0) (local.get 0x054)) + (i64.store offset=0x055 align=1 (i32.const 0) (local.get 0x055)) + (i64.store offset=0x056 align=1 (i32.const 0) (local.get 0x056)) + (i64.store offset=0x057 align=1 (i32.const 0) (local.get 0x057)) + (i64.store offset=0x058 align=1 (i32.const 0) (local.get 0x058)) + (i64.store offset=0x059 align=1 (i32.const 0) (local.get 0x059)) + (i64.store offset=0x05a align=1 (i32.const 0) (local.get 0x05a)) + (i64.store offset=0x05b align=1 (i32.const 0) (local.get 0x05b)) + (i64.store offset=0x05c align=1 (i32.const 0) (local.get 0x05c)) + (i64.store offset=0x05d align=1 (i32.const 0) (local.get 0x05d)) + (i64.store offset=0x05e align=1 (i32.const 0) (local.get 0x05e)) + (i64.store offset=0x05f align=1 (i32.const 0) (local.get 0x05f)) + (i64.store offset=0x060 align=1 (i32.const 0) (local.get 0x060)) + (i64.store offset=0x061 align=1 (i32.const 0) (local.get 0x061)) + (i64.store offset=0x062 align=1 (i32.const 0) (local.get 0x062)) + (i64.store offset=0x063 align=1 (i32.const 0) (local.get 0x063)) + (i64.store offset=0x064 align=1 (i32.const 0) (local.get 0x064)) + (i64.store offset=0x065 align=1 (i32.const 0) (local.get 0x065)) + (i64.store offset=0x066 align=1 (i32.const 0) (local.get 0x066)) + (i64.store offset=0x067 align=1 (i32.const 0) (local.get 0x067)) + (i64.store offset=0x068 align=1 (i32.const 0) (local.get 0x068)) + (i64.store offset=0x069 align=1 (i32.const 0) (local.get 0x069)) + (i64.store offset=0x06a align=1 (i32.const 0) (local.get 0x06a)) + (i64.store offset=0x06b align=1 (i32.const 0) (local.get 0x06b)) + (i64.store offset=0x06c align=1 (i32.const 0) (local.get 0x06c)) + (i64.store offset=0x06d align=1 (i32.const 0) (local.get 0x06d)) + (i64.store offset=0x06e align=1 (i32.const 0) (local.get 0x06e)) + (i64.store offset=0x06f align=1 (i32.const 0) (local.get 0x06f)) + (i64.store offset=0x070 align=1 (i32.const 0) (local.get 0x070)) + (i64.store offset=0x071 align=1 (i32.const 0) (local.get 0x071)) + (i64.store offset=0x072 align=1 (i32.const 0) (local.get 0x072)) + (i64.store offset=0x073 align=1 (i32.const 0) (local.get 0x073)) + (i64.store offset=0x074 align=1 (i32.const 0) (local.get 0x074)) + (i64.store offset=0x075 align=1 (i32.const 0) (local.get 0x075)) + (i64.store offset=0x076 align=1 (i32.const 0) (local.get 0x076)) + (i64.store offset=0x077 align=1 (i32.const 0) (local.get 0x077)) + (i64.store offset=0x078 align=1 (i32.const 0) (local.get 0x078)) + (i64.store offset=0x079 align=1 (i32.const 0) (local.get 0x079)) + (i64.store offset=0x07a align=1 (i32.const 0) (local.get 0x07a)) + (i64.store offset=0x07b align=1 (i32.const 0) (local.get 0x07b)) + (i64.store offset=0x07c align=1 (i32.const 0) (local.get 0x07c)) + (i64.store offset=0x07d align=1 (i32.const 0) (local.get 0x07d)) + (i64.store offset=0x07e align=1 (i32.const 0) (local.get 0x07e)) + (i64.store offset=0x07f align=1 (i32.const 0) (local.get 0x07f)) + (i64.store offset=0x080 align=1 (i32.const 0) (local.get 0x080)) + (i64.store offset=0x081 align=1 (i32.const 0) (local.get 0x081)) + (i64.store offset=0x082 align=1 (i32.const 0) (local.get 0x082)) + (i64.store offset=0x083 align=1 (i32.const 0) (local.get 0x083)) + (i64.store offset=0x084 align=1 (i32.const 0) (local.get 0x084)) + (i64.store offset=0x085 align=1 (i32.const 0) (local.get 0x085)) + (i64.store offset=0x086 align=1 (i32.const 0) (local.get 0x086)) + (i64.store offset=0x087 align=1 (i32.const 0) (local.get 0x087)) + (i64.store offset=0x088 align=1 (i32.const 0) (local.get 0x088)) + (i64.store offset=0x089 align=1 (i32.const 0) (local.get 0x089)) + (i64.store offset=0x08a align=1 (i32.const 0) (local.get 0x08a)) + (i64.store offset=0x08b align=1 (i32.const 0) (local.get 0x08b)) + (i64.store offset=0x08c align=1 (i32.const 0) (local.get 0x08c)) + (i64.store offset=0x08d align=1 (i32.const 0) (local.get 0x08d)) + (i64.store offset=0x08e align=1 (i32.const 0) (local.get 0x08e)) + (i64.store offset=0x08f align=1 (i32.const 0) (local.get 0x08f)) + (i64.store offset=0x090 align=1 (i32.const 0) (local.get 0x090)) + (i64.store offset=0x091 align=1 (i32.const 0) (local.get 0x091)) + (i64.store offset=0x092 align=1 (i32.const 0) (local.get 0x092)) + (i64.store offset=0x093 align=1 (i32.const 0) (local.get 0x093)) + (i64.store offset=0x094 align=1 (i32.const 0) (local.get 0x094)) + (i64.store offset=0x095 align=1 (i32.const 0) (local.get 0x095)) + (i64.store offset=0x096 align=1 (i32.const 0) (local.get 0x096)) + (i64.store offset=0x097 align=1 (i32.const 0) (local.get 0x097)) + (i64.store offset=0x098 align=1 (i32.const 0) (local.get 0x098)) + (i64.store offset=0x099 align=1 (i32.const 0) (local.get 0x099)) + (i64.store offset=0x09a align=1 (i32.const 0) (local.get 0x09a)) + (i64.store offset=0x09b align=1 (i32.const 0) (local.get 0x09b)) + (i64.store offset=0x09c align=1 (i32.const 0) (local.get 0x09c)) + (i64.store offset=0x09d align=1 (i32.const 0) (local.get 0x09d)) + (i64.store offset=0x09e align=1 (i32.const 0) (local.get 0x09e)) + (i64.store offset=0x09f align=1 (i32.const 0) (local.get 0x09f)) + (i64.store offset=0x0a0 align=1 (i32.const 0) (local.get 0x0a0)) + (i64.store offset=0x0a1 align=1 (i32.const 0) (local.get 0x0a1)) + (i64.store offset=0x0a2 align=1 (i32.const 0) (local.get 0x0a2)) + (i64.store offset=0x0a3 align=1 (i32.const 0) (local.get 0x0a3)) + (i64.store offset=0x0a4 align=1 (i32.const 0) (local.get 0x0a4)) + (i64.store offset=0x0a5 align=1 (i32.const 0) (local.get 0x0a5)) + (i64.store offset=0x0a6 align=1 (i32.const 0) (local.get 0x0a6)) + (i64.store offset=0x0a7 align=1 (i32.const 0) (local.get 0x0a7)) + (i64.store offset=0x0a8 align=1 (i32.const 0) (local.get 0x0a8)) + (i64.store offset=0x0a9 align=1 (i32.const 0) (local.get 0x0a9)) + (i64.store offset=0x0aa align=1 (i32.const 0) (local.get 0x0aa)) + (i64.store offset=0x0ab align=1 (i32.const 0) (local.get 0x0ab)) + (i64.store offset=0x0ac align=1 (i32.const 0) (local.get 0x0ac)) + (i64.store offset=0x0ad align=1 (i32.const 0) (local.get 0x0ad)) + (i64.store offset=0x0ae align=1 (i32.const 0) (local.get 0x0ae)) + (i64.store offset=0x0af align=1 (i32.const 0) (local.get 0x0af)) + (i64.store offset=0x0b0 align=1 (i32.const 0) (local.get 0x0b0)) + (i64.store offset=0x0b1 align=1 (i32.const 0) (local.get 0x0b1)) + (i64.store offset=0x0b2 align=1 (i32.const 0) (local.get 0x0b2)) + (i64.store offset=0x0b3 align=1 (i32.const 0) (local.get 0x0b3)) + (i64.store offset=0x0b4 align=1 (i32.const 0) (local.get 0x0b4)) + (i64.store offset=0x0b5 align=1 (i32.const 0) (local.get 0x0b5)) + (i64.store offset=0x0b6 align=1 (i32.const 0) (local.get 0x0b6)) + (i64.store offset=0x0b7 align=1 (i32.const 0) (local.get 0x0b7)) + (i64.store offset=0x0b8 align=1 (i32.const 0) (local.get 0x0b8)) + (i64.store offset=0x0b9 align=1 (i32.const 0) (local.get 0x0b9)) + (i64.store offset=0x0ba align=1 (i32.const 0) (local.get 0x0ba)) + (i64.store offset=0x0bb align=1 (i32.const 0) (local.get 0x0bb)) + (i64.store offset=0x0bc align=1 (i32.const 0) (local.get 0x0bc)) + (i64.store offset=0x0bd align=1 (i32.const 0) (local.get 0x0bd)) + (i64.store offset=0x0be align=1 (i32.const 0) (local.get 0x0be)) + (i64.store offset=0x0bf align=1 (i32.const 0) (local.get 0x0bf)) + (i64.store offset=0x0c0 align=1 (i32.const 0) (local.get 0x0c0)) + (i64.store offset=0x0c1 align=1 (i32.const 0) (local.get 0x0c1)) + (i64.store offset=0x0c2 align=1 (i32.const 0) (local.get 0x0c2)) + (i64.store offset=0x0c3 align=1 (i32.const 0) (local.get 0x0c3)) + (i64.store offset=0x0c4 align=1 (i32.const 0) (local.get 0x0c4)) + (i64.store offset=0x0c5 align=1 (i32.const 0) (local.get 0x0c5)) + (i64.store offset=0x0c6 align=1 (i32.const 0) (local.get 0x0c6)) + (i64.store offset=0x0c7 align=1 (i32.const 0) (local.get 0x0c7)) + (i64.store offset=0x0c8 align=1 (i32.const 0) (local.get 0x0c8)) + (i64.store offset=0x0c9 align=1 (i32.const 0) (local.get 0x0c9)) + (i64.store offset=0x0ca align=1 (i32.const 0) (local.get 0x0ca)) + (i64.store offset=0x0cb align=1 (i32.const 0) (local.get 0x0cb)) + (i64.store offset=0x0cc align=1 (i32.const 0) (local.get 0x0cc)) + (i64.store offset=0x0cd align=1 (i32.const 0) (local.get 0x0cd)) + (i64.store offset=0x0ce align=1 (i32.const 0) (local.get 0x0ce)) + (i64.store offset=0x0cf align=1 (i32.const 0) (local.get 0x0cf)) + (i64.store offset=0x0d0 align=1 (i32.const 0) (local.get 0x0d0)) + (i64.store offset=0x0d1 align=1 (i32.const 0) (local.get 0x0d1)) + (i64.store offset=0x0d2 align=1 (i32.const 0) (local.get 0x0d2)) + (i64.store offset=0x0d3 align=1 (i32.const 0) (local.get 0x0d3)) + (i64.store offset=0x0d4 align=1 (i32.const 0) (local.get 0x0d4)) + (i64.store offset=0x0d5 align=1 (i32.const 0) (local.get 0x0d5)) + (i64.store offset=0x0d6 align=1 (i32.const 0) (local.get 0x0d6)) + (i64.store offset=0x0d7 align=1 (i32.const 0) (local.get 0x0d7)) + (i64.store offset=0x0d8 align=1 (i32.const 0) (local.get 0x0d8)) + (i64.store offset=0x0d9 align=1 (i32.const 0) (local.get 0x0d9)) + (i64.store offset=0x0da align=1 (i32.const 0) (local.get 0x0da)) + (i64.store offset=0x0db align=1 (i32.const 0) (local.get 0x0db)) + (i64.store offset=0x0dc align=1 (i32.const 0) (local.get 0x0dc)) + (i64.store offset=0x0dd align=1 (i32.const 0) (local.get 0x0dd)) + (i64.store offset=0x0de align=1 (i32.const 0) (local.get 0x0de)) + (i64.store offset=0x0df align=1 (i32.const 0) (local.get 0x0df)) + (i64.store offset=0x0e0 align=1 (i32.const 0) (local.get 0x0e0)) + (i64.store offset=0x0e1 align=1 (i32.const 0) (local.get 0x0e1)) + (i64.store offset=0x0e2 align=1 (i32.const 0) (local.get 0x0e2)) + (i64.store offset=0x0e3 align=1 (i32.const 0) (local.get 0x0e3)) + (i64.store offset=0x0e4 align=1 (i32.const 0) (local.get 0x0e4)) + (i64.store offset=0x0e5 align=1 (i32.const 0) (local.get 0x0e5)) + (i64.store offset=0x0e6 align=1 (i32.const 0) (local.get 0x0e6)) + (i64.store offset=0x0e7 align=1 (i32.const 0) (local.get 0x0e7)) + (i64.store offset=0x0e8 align=1 (i32.const 0) (local.get 0x0e8)) + (i64.store offset=0x0e9 align=1 (i32.const 0) (local.get 0x0e9)) + (i64.store offset=0x0ea align=1 (i32.const 0) (local.get 0x0ea)) + (i64.store offset=0x0eb align=1 (i32.const 0) (local.get 0x0eb)) + (i64.store offset=0x0ec align=1 (i32.const 0) (local.get 0x0ec)) + (i64.store offset=0x0ed align=1 (i32.const 0) (local.get 0x0ed)) + (i64.store offset=0x0ee align=1 (i32.const 0) (local.get 0x0ee)) + (i64.store offset=0x0ef align=1 (i32.const 0) (local.get 0x0ef)) + (i64.store offset=0x0f0 align=1 (i32.const 0) (local.get 0x0f0)) + (i64.store offset=0x0f1 align=1 (i32.const 0) (local.get 0x0f1)) + (i64.store offset=0x0f2 align=1 (i32.const 0) (local.get 0x0f2)) + (i64.store offset=0x0f3 align=1 (i32.const 0) (local.get 0x0f3)) + (i64.store offset=0x0f4 align=1 (i32.const 0) (local.get 0x0f4)) + (i64.store offset=0x0f5 align=1 (i32.const 0) (local.get 0x0f5)) + (i64.store offset=0x0f6 align=1 (i32.const 0) (local.get 0x0f6)) + (i64.store offset=0x0f7 align=1 (i32.const 0) (local.get 0x0f7)) + (i64.store offset=0x0f8 align=1 (i32.const 0) (local.get 0x0f8)) + (i64.store offset=0x0f9 align=1 (i32.const 0) (local.get 0x0f9)) + (i64.store offset=0x0fa align=1 (i32.const 0) (local.get 0x0fa)) + (i64.store offset=0x0fb align=1 (i32.const 0) (local.get 0x0fb)) + (i64.store offset=0x0fc align=1 (i32.const 0) (local.get 0x0fc)) + (i64.store offset=0x0fd align=1 (i32.const 0) (local.get 0x0fd)) + (i64.store offset=0x0fe align=1 (i32.const 0) (local.get 0x0fe)) + (i64.store offset=0x0ff align=1 (i32.const 0) (local.get 0x0ff)) + (i64.store offset=0x100 align=1 (i32.const 0) (local.get 0x100)) + (i64.store offset=0x101 align=1 (i32.const 0) (local.get 0x101)) + (i64.store offset=0x102 align=1 (i32.const 0) (local.get 0x102)) + (i64.store offset=0x103 align=1 (i32.const 0) (local.get 0x103)) + (i64.store offset=0x104 align=1 (i32.const 0) (local.get 0x104)) + (i64.store offset=0x105 align=1 (i32.const 0) (local.get 0x105)) + (i64.store offset=0x106 align=1 (i32.const 0) (local.get 0x106)) + (i64.store offset=0x107 align=1 (i32.const 0) (local.get 0x107)) + (i64.store offset=0x108 align=1 (i32.const 0) (local.get 0x108)) + (i64.store offset=0x109 align=1 (i32.const 0) (local.get 0x109)) + (i64.store offset=0x10a align=1 (i32.const 0) (local.get 0x10a)) + (i64.store offset=0x10b align=1 (i32.const 0) (local.get 0x10b)) + (i64.store offset=0x10c align=1 (i32.const 0) (local.get 0x10c)) + (i64.store offset=0x10d align=1 (i32.const 0) (local.get 0x10d)) + (i64.store offset=0x10e align=1 (i32.const 0) (local.get 0x10e)) + (i64.store offset=0x10f align=1 (i32.const 0) (local.get 0x10f)) + (i64.store offset=0x110 align=1 (i32.const 0) (local.get 0x110)) + (i64.store offset=0x111 align=1 (i32.const 0) (local.get 0x111)) + (i64.store offset=0x112 align=1 (i32.const 0) (local.get 0x112)) + (i64.store offset=0x113 align=1 (i32.const 0) (local.get 0x113)) + (i64.store offset=0x114 align=1 (i32.const 0) (local.get 0x114)) + (i64.store offset=0x115 align=1 (i32.const 0) (local.get 0x115)) + (i64.store offset=0x116 align=1 (i32.const 0) (local.get 0x116)) + (i64.store offset=0x117 align=1 (i32.const 0) (local.get 0x117)) + (i64.store offset=0x118 align=1 (i32.const 0) (local.get 0x118)) + (i64.store offset=0x119 align=1 (i32.const 0) (local.get 0x119)) + (i64.store offset=0x11a align=1 (i32.const 0) (local.get 0x11a)) + (i64.store offset=0x11b align=1 (i32.const 0) (local.get 0x11b)) + (i64.store offset=0x11c align=1 (i32.const 0) (local.get 0x11c)) + (i64.store offset=0x11d align=1 (i32.const 0) (local.get 0x11d)) + (i64.store offset=0x11e align=1 (i32.const 0) (local.get 0x11e)) + (i64.store offset=0x11f align=1 (i32.const 0) (local.get 0x11f)) + (i64.store offset=0x120 align=1 (i32.const 0) (local.get 0x120)) + (i64.store offset=0x121 align=1 (i32.const 0) (local.get 0x121)) + (i64.store offset=0x122 align=1 (i32.const 0) (local.get 0x122)) + (i64.store offset=0x123 align=1 (i32.const 0) (local.get 0x123)) + (i64.store offset=0x124 align=1 (i32.const 0) (local.get 0x124)) + (i64.store offset=0x125 align=1 (i32.const 0) (local.get 0x125)) + (i64.store offset=0x126 align=1 (i32.const 0) (local.get 0x126)) + (i64.store offset=0x127 align=1 (i32.const 0) (local.get 0x127)) + (i64.store offset=0x128 align=1 (i32.const 0) (local.get 0x128)) + (i64.store offset=0x129 align=1 (i32.const 0) (local.get 0x129)) + (i64.store offset=0x12a align=1 (i32.const 0) (local.get 0x12a)) + (i64.store offset=0x12b align=1 (i32.const 0) (local.get 0x12b)) + (i64.store offset=0x12c align=1 (i32.const 0) (local.get 0x12c)) + (i64.store offset=0x12d align=1 (i32.const 0) (local.get 0x12d)) + (i64.store offset=0x12e align=1 (i32.const 0) (local.get 0x12e)) + (i64.store offset=0x12f align=1 (i32.const 0) (local.get 0x12f)) + (i64.store offset=0x130 align=1 (i32.const 0) (local.get 0x130)) + (i64.store offset=0x131 align=1 (i32.const 0) (local.get 0x131)) + (i64.store offset=0x132 align=1 (i32.const 0) (local.get 0x132)) + (i64.store offset=0x133 align=1 (i32.const 0) (local.get 0x133)) + (i64.store offset=0x134 align=1 (i32.const 0) (local.get 0x134)) + (i64.store offset=0x135 align=1 (i32.const 0) (local.get 0x135)) + (i64.store offset=0x136 align=1 (i32.const 0) (local.get 0x136)) + (i64.store offset=0x137 align=1 (i32.const 0) (local.get 0x137)) + (i64.store offset=0x138 align=1 (i32.const 0) (local.get 0x138)) + (i64.store offset=0x139 align=1 (i32.const 0) (local.get 0x139)) + (i64.store offset=0x13a align=1 (i32.const 0) (local.get 0x13a)) + (i64.store offset=0x13b align=1 (i32.const 0) (local.get 0x13b)) + (i64.store offset=0x13c align=1 (i32.const 0) (local.get 0x13c)) + (i64.store offset=0x13d align=1 (i32.const 0) (local.get 0x13d)) + (i64.store offset=0x13e align=1 (i32.const 0) (local.get 0x13e)) + (i64.store offset=0x13f align=1 (i32.const 0) (local.get 0x13f)) + (i64.store offset=0x140 align=1 (i32.const 0) (local.get 0x140)) + (i64.store offset=0x141 align=1 (i32.const 0) (local.get 0x141)) + (i64.store offset=0x142 align=1 (i32.const 0) (local.get 0x142)) + (i64.store offset=0x143 align=1 (i32.const 0) (local.get 0x143)) + (i64.store offset=0x144 align=1 (i32.const 0) (local.get 0x144)) + (i64.store offset=0x145 align=1 (i32.const 0) (local.get 0x145)) + (i64.store offset=0x146 align=1 (i32.const 0) (local.get 0x146)) + (i64.store offset=0x147 align=1 (i32.const 0) (local.get 0x147)) + (i64.store offset=0x148 align=1 (i32.const 0) (local.get 0x148)) + (i64.store offset=0x149 align=1 (i32.const 0) (local.get 0x149)) + (i64.store offset=0x14a align=1 (i32.const 0) (local.get 0x14a)) + (i64.store offset=0x14b align=1 (i32.const 0) (local.get 0x14b)) + (i64.store offset=0x14c align=1 (i32.const 0) (local.get 0x14c)) + (i64.store offset=0x14d align=1 (i32.const 0) (local.get 0x14d)) + (i64.store offset=0x14e align=1 (i32.const 0) (local.get 0x14e)) + (i64.store offset=0x14f align=1 (i32.const 0) (local.get 0x14f)) + (i64.store offset=0x150 align=1 (i32.const 0) (local.get 0x150)) + (i64.store offset=0x151 align=1 (i32.const 0) (local.get 0x151)) + (i64.store offset=0x152 align=1 (i32.const 0) (local.get 0x152)) + (i64.store offset=0x153 align=1 (i32.const 0) (local.get 0x153)) + (i64.store offset=0x154 align=1 (i32.const 0) (local.get 0x154)) + (i64.store offset=0x155 align=1 (i32.const 0) (local.get 0x155)) + (i64.store offset=0x156 align=1 (i32.const 0) (local.get 0x156)) + (i64.store offset=0x157 align=1 (i32.const 0) (local.get 0x157)) + (i64.store offset=0x158 align=1 (i32.const 0) (local.get 0x158)) + (i64.store offset=0x159 align=1 (i32.const 0) (local.get 0x159)) + (i64.store offset=0x15a align=1 (i32.const 0) (local.get 0x15a)) + (i64.store offset=0x15b align=1 (i32.const 0) (local.get 0x15b)) + (i64.store offset=0x15c align=1 (i32.const 0) (local.get 0x15c)) + (i64.store offset=0x15d align=1 (i32.const 0) (local.get 0x15d)) + (i64.store offset=0x15e align=1 (i32.const 0) (local.get 0x15e)) + (i64.store offset=0x15f align=1 (i32.const 0) (local.get 0x15f)) + (i64.store offset=0x160 align=1 (i32.const 0) (local.get 0x160)) + (i64.store offset=0x161 align=1 (i32.const 0) (local.get 0x161)) + (i64.store offset=0x162 align=1 (i32.const 0) (local.get 0x162)) + (i64.store offset=0x163 align=1 (i32.const 0) (local.get 0x163)) + (i64.store offset=0x164 align=1 (i32.const 0) (local.get 0x164)) + (i64.store offset=0x165 align=1 (i32.const 0) (local.get 0x165)) + (i64.store offset=0x166 align=1 (i32.const 0) (local.get 0x166)) + (i64.store offset=0x167 align=1 (i32.const 0) (local.get 0x167)) + (i64.store offset=0x168 align=1 (i32.const 0) (local.get 0x168)) + (i64.store offset=0x169 align=1 (i32.const 0) (local.get 0x169)) + (i64.store offset=0x16a align=1 (i32.const 0) (local.get 0x16a)) + (i64.store offset=0x16b align=1 (i32.const 0) (local.get 0x16b)) + (i64.store offset=0x16c align=1 (i32.const 0) (local.get 0x16c)) + (i64.store offset=0x16d align=1 (i32.const 0) (local.get 0x16d)) + (i64.store offset=0x16e align=1 (i32.const 0) (local.get 0x16e)) + (i64.store offset=0x16f align=1 (i32.const 0) (local.get 0x16f)) + (i64.store offset=0x170 align=1 (i32.const 0) (local.get 0x170)) + (i64.store offset=0x171 align=1 (i32.const 0) (local.get 0x171)) + (i64.store offset=0x172 align=1 (i32.const 0) (local.get 0x172)) + (i64.store offset=0x173 align=1 (i32.const 0) (local.get 0x173)) + (i64.store offset=0x174 align=1 (i32.const 0) (local.get 0x174)) + (i64.store offset=0x175 align=1 (i32.const 0) (local.get 0x175)) + (i64.store offset=0x176 align=1 (i32.const 0) (local.get 0x176)) + (i64.store offset=0x177 align=1 (i32.const 0) (local.get 0x177)) + (i64.store offset=0x178 align=1 (i32.const 0) (local.get 0x178)) + (i64.store offset=0x179 align=1 (i32.const 0) (local.get 0x179)) + (i64.store offset=0x17a align=1 (i32.const 0) (local.get 0x17a)) + (i64.store offset=0x17b align=1 (i32.const 0) (local.get 0x17b)) + (i64.store offset=0x17c align=1 (i32.const 0) (local.get 0x17c)) + (i64.store offset=0x17d align=1 (i32.const 0) (local.get 0x17d)) + (i64.store offset=0x17e align=1 (i32.const 0) (local.get 0x17e)) + (i64.store offset=0x17f align=1 (i32.const 0) (local.get 0x17f)) + (i64.store offset=0x180 align=1 (i32.const 0) (local.get 0x180)) + (i64.store offset=0x181 align=1 (i32.const 0) (local.get 0x181)) + (i64.store offset=0x182 align=1 (i32.const 0) (local.get 0x182)) + (i64.store offset=0x183 align=1 (i32.const 0) (local.get 0x183)) + (i64.store offset=0x184 align=1 (i32.const 0) (local.get 0x184)) + (i64.store offset=0x185 align=1 (i32.const 0) (local.get 0x185)) + (i64.store offset=0x186 align=1 (i32.const 0) (local.get 0x186)) + (i64.store offset=0x187 align=1 (i32.const 0) (local.get 0x187)) + (i64.store offset=0x188 align=1 (i32.const 0) (local.get 0x188)) + (i64.store offset=0x189 align=1 (i32.const 0) (local.get 0x189)) + (i64.store offset=0x18a align=1 (i32.const 0) (local.get 0x18a)) + (i64.store offset=0x18b align=1 (i32.const 0) (local.get 0x18b)) + (i64.store offset=0x18c align=1 (i32.const 0) (local.get 0x18c)) + (i64.store offset=0x18d align=1 (i32.const 0) (local.get 0x18d)) + (i64.store offset=0x18e align=1 (i32.const 0) (local.get 0x18e)) + (i64.store offset=0x18f align=1 (i32.const 0) (local.get 0x18f)) + (i64.store offset=0x190 align=1 (i32.const 0) (local.get 0x190)) + (i64.store offset=0x191 align=1 (i32.const 0) (local.get 0x191)) + (i64.store offset=0x192 align=1 (i32.const 0) (local.get 0x192)) + (i64.store offset=0x193 align=1 (i32.const 0) (local.get 0x193)) + (i64.store offset=0x194 align=1 (i32.const 0) (local.get 0x194)) + (i64.store offset=0x195 align=1 (i32.const 0) (local.get 0x195)) + (i64.store offset=0x196 align=1 (i32.const 0) (local.get 0x196)) + (i64.store offset=0x197 align=1 (i32.const 0) (local.get 0x197)) + (i64.store offset=0x198 align=1 (i32.const 0) (local.get 0x198)) + (i64.store offset=0x199 align=1 (i32.const 0) (local.get 0x199)) + (i64.store offset=0x19a align=1 (i32.const 0) (local.get 0x19a)) + (i64.store offset=0x19b align=1 (i32.const 0) (local.get 0x19b)) + (i64.store offset=0x19c align=1 (i32.const 0) (local.get 0x19c)) + (i64.store offset=0x19d align=1 (i32.const 0) (local.get 0x19d)) + (i64.store offset=0x19e align=1 (i32.const 0) (local.get 0x19e)) + (i64.store offset=0x19f align=1 (i32.const 0) (local.get 0x19f)) + (i64.store offset=0x1a0 align=1 (i32.const 0) (local.get 0x1a0)) + (i64.store offset=0x1a1 align=1 (i32.const 0) (local.get 0x1a1)) + (i64.store offset=0x1a2 align=1 (i32.const 0) (local.get 0x1a2)) + (i64.store offset=0x1a3 align=1 (i32.const 0) (local.get 0x1a3)) + (i64.store offset=0x1a4 align=1 (i32.const 0) (local.get 0x1a4)) + (i64.store offset=0x1a5 align=1 (i32.const 0) (local.get 0x1a5)) + (i64.store offset=0x1a6 align=1 (i32.const 0) (local.get 0x1a6)) + (i64.store offset=0x1a7 align=1 (i32.const 0) (local.get 0x1a7)) + (i64.store offset=0x1a8 align=1 (i32.const 0) (local.get 0x1a8)) + (i64.store offset=0x1a9 align=1 (i32.const 0) (local.get 0x1a9)) + (i64.store offset=0x1aa align=1 (i32.const 0) (local.get 0x1aa)) + (i64.store offset=0x1ab align=1 (i32.const 0) (local.get 0x1ab)) + (i64.store offset=0x1ac align=1 (i32.const 0) (local.get 0x1ac)) + (i64.store offset=0x1ad align=1 (i32.const 0) (local.get 0x1ad)) + (i64.store offset=0x1ae align=1 (i32.const 0) (local.get 0x1ae)) + (i64.store offset=0x1af align=1 (i32.const 0) (local.get 0x1af)) + (i64.store offset=0x1b0 align=1 (i32.const 0) (local.get 0x1b0)) + (i64.store offset=0x1b1 align=1 (i32.const 0) (local.get 0x1b1)) + (i64.store offset=0x1b2 align=1 (i32.const 0) (local.get 0x1b2)) + (i64.store offset=0x1b3 align=1 (i32.const 0) (local.get 0x1b3)) + (i64.store offset=0x1b4 align=1 (i32.const 0) (local.get 0x1b4)) + (i64.store offset=0x1b5 align=1 (i32.const 0) (local.get 0x1b5)) + (i64.store offset=0x1b6 align=1 (i32.const 0) (local.get 0x1b6)) + (i64.store offset=0x1b7 align=1 (i32.const 0) (local.get 0x1b7)) + (i64.store offset=0x1b8 align=1 (i32.const 0) (local.get 0x1b8)) + (i64.store offset=0x1b9 align=1 (i32.const 0) (local.get 0x1b9)) + (i64.store offset=0x1ba align=1 (i32.const 0) (local.get 0x1ba)) + (i64.store offset=0x1bb align=1 (i32.const 0) (local.get 0x1bb)) + (i64.store offset=0x1bc align=1 (i32.const 0) (local.get 0x1bc)) + (i64.store offset=0x1bd align=1 (i32.const 0) (local.get 0x1bd)) + (i64.store offset=0x1be align=1 (i32.const 0) (local.get 0x1be)) + (i64.store offset=0x1bf align=1 (i32.const 0) (local.get 0x1bf)) + (i64.store offset=0x1c0 align=1 (i32.const 0) (local.get 0x1c0)) + (i64.store offset=0x1c1 align=1 (i32.const 0) (local.get 0x1c1)) + (i64.store offset=0x1c2 align=1 (i32.const 0) (local.get 0x1c2)) + (i64.store offset=0x1c3 align=1 (i32.const 0) (local.get 0x1c3)) + (i64.store offset=0x1c4 align=1 (i32.const 0) (local.get 0x1c4)) + (i64.store offset=0x1c5 align=1 (i32.const 0) (local.get 0x1c5)) + (i64.store offset=0x1c6 align=1 (i32.const 0) (local.get 0x1c6)) + (i64.store offset=0x1c7 align=1 (i32.const 0) (local.get 0x1c7)) + (i64.store offset=0x1c8 align=1 (i32.const 0) (local.get 0x1c8)) + (i64.store offset=0x1c9 align=1 (i32.const 0) (local.get 0x1c9)) + (i64.store offset=0x1ca align=1 (i32.const 0) (local.get 0x1ca)) + (i64.store offset=0x1cb align=1 (i32.const 0) (local.get 0x1cb)) + (i64.store offset=0x1cc align=1 (i32.const 0) (local.get 0x1cc)) + (i64.store offset=0x1cd align=1 (i32.const 0) (local.get 0x1cd)) + (i64.store offset=0x1ce align=1 (i32.const 0) (local.get 0x1ce)) + (i64.store offset=0x1cf align=1 (i32.const 0) (local.get 0x1cf)) + (i64.store offset=0x1d0 align=1 (i32.const 0) (local.get 0x1d0)) + (i64.store offset=0x1d1 align=1 (i32.const 0) (local.get 0x1d1)) + (i64.store offset=0x1d2 align=1 (i32.const 0) (local.get 0x1d2)) + (i64.store offset=0x1d3 align=1 (i32.const 0) (local.get 0x1d3)) + (i64.store offset=0x1d4 align=1 (i32.const 0) (local.get 0x1d4)) + (i64.store offset=0x1d5 align=1 (i32.const 0) (local.get 0x1d5)) + (i64.store offset=0x1d6 align=1 (i32.const 0) (local.get 0x1d6)) + (i64.store offset=0x1d7 align=1 (i32.const 0) (local.get 0x1d7)) + (i64.store offset=0x1d8 align=1 (i32.const 0) (local.get 0x1d8)) + (i64.store offset=0x1d9 align=1 (i32.const 0) (local.get 0x1d9)) + (i64.store offset=0x1da align=1 (i32.const 0) (local.get 0x1da)) + (i64.store offset=0x1db align=1 (i32.const 0) (local.get 0x1db)) + (i64.store offset=0x1dc align=1 (i32.const 0) (local.get 0x1dc)) + (i64.store offset=0x1dd align=1 (i32.const 0) (local.get 0x1dd)) + (i64.store offset=0x1de align=1 (i32.const 0) (local.get 0x1de)) + (i64.store offset=0x1df align=1 (i32.const 0) (local.get 0x1df)) + (i64.store offset=0x1e0 align=1 (i32.const 0) (local.get 0x1e0)) + (i64.store offset=0x1e1 align=1 (i32.const 0) (local.get 0x1e1)) + (i64.store offset=0x1e2 align=1 (i32.const 0) (local.get 0x1e2)) + (i64.store offset=0x1e3 align=1 (i32.const 0) (local.get 0x1e3)) + (i64.store offset=0x1e4 align=1 (i32.const 0) (local.get 0x1e4)) + (i64.store offset=0x1e5 align=1 (i32.const 0) (local.get 0x1e5)) + (i64.store offset=0x1e6 align=1 (i32.const 0) (local.get 0x1e6)) + (i64.store offset=0x1e7 align=1 (i32.const 0) (local.get 0x1e7)) + (i64.store offset=0x1e8 align=1 (i32.const 0) (local.get 0x1e8)) + (i64.store offset=0x1e9 align=1 (i32.const 0) (local.get 0x1e9)) + (i64.store offset=0x1ea align=1 (i32.const 0) (local.get 0x1ea)) + (i64.store offset=0x1eb align=1 (i32.const 0) (local.get 0x1eb)) + (i64.store offset=0x1ec align=1 (i32.const 0) (local.get 0x1ec)) + (i64.store offset=0x1ed align=1 (i32.const 0) (local.get 0x1ed)) + (i64.store offset=0x1ee align=1 (i32.const 0) (local.get 0x1ee)) + (i64.store offset=0x1ef align=1 (i32.const 0) (local.get 0x1ef)) + (i64.store offset=0x1f0 align=1 (i32.const 0) (local.get 0x1f0)) + (i64.store offset=0x1f1 align=1 (i32.const 0) (local.get 0x1f1)) + (i64.store offset=0x1f2 align=1 (i32.const 0) (local.get 0x1f2)) + (i64.store offset=0x1f3 align=1 (i32.const 0) (local.get 0x1f3)) + (i64.store offset=0x1f4 align=1 (i32.const 0) (local.get 0x1f4)) + (i64.store offset=0x1f5 align=1 (i32.const 0) (local.get 0x1f5)) + (i64.store offset=0x1f6 align=1 (i32.const 0) (local.get 0x1f6)) + (i64.store offset=0x1f7 align=1 (i32.const 0) (local.get 0x1f7)) + (i64.store offset=0x1f8 align=1 (i32.const 0) (local.get 0x1f8)) + (i64.store offset=0x1f9 align=1 (i32.const 0) (local.get 0x1f9)) + (i64.store offset=0x1fa align=1 (i32.const 0) (local.get 0x1fa)) + (i64.store offset=0x1fb align=1 (i32.const 0) (local.get 0x1fb)) + (i64.store offset=0x1fc align=1 (i32.const 0) (local.get 0x1fc)) + (i64.store offset=0x1fd align=1 (i32.const 0) (local.get 0x1fd)) + (i64.store offset=0x1fe align=1 (i32.const 0) (local.get 0x1fe)) + (i64.store offset=0x1ff align=1 (i32.const 0) (local.get 0x1ff)) + (i64.store offset=0x200 align=1 (i32.const 0) (local.get 0x200)) + (i64.store offset=0x201 align=1 (i32.const 0) (local.get 0x201)) + (i64.store offset=0x202 align=1 (i32.const 0) (local.get 0x202)) + (i64.store offset=0x203 align=1 (i32.const 0) (local.get 0x203)) + (i64.store offset=0x204 align=1 (i32.const 0) (local.get 0x204)) + (i64.store offset=0x205 align=1 (i32.const 0) (local.get 0x205)) + (i64.store offset=0x206 align=1 (i32.const 0) (local.get 0x206)) + (i64.store offset=0x207 align=1 (i32.const 0) (local.get 0x207)) + (i64.store offset=0x208 align=1 (i32.const 0) (local.get 0x208)) + (i64.store offset=0x209 align=1 (i32.const 0) (local.get 0x209)) + (i64.store offset=0x20a align=1 (i32.const 0) (local.get 0x20a)) + (i64.store offset=0x20b align=1 (i32.const 0) (local.get 0x20b)) + (i64.store offset=0x20c align=1 (i32.const 0) (local.get 0x20c)) + (i64.store offset=0x20d align=1 (i32.const 0) (local.get 0x20d)) + (i64.store offset=0x20e align=1 (i32.const 0) (local.get 0x20e)) + (i64.store offset=0x20f align=1 (i32.const 0) (local.get 0x20f)) + (i64.store offset=0x210 align=1 (i32.const 0) (local.get 0x210)) + (i64.store offset=0x211 align=1 (i32.const 0) (local.get 0x211)) + (i64.store offset=0x212 align=1 (i32.const 0) (local.get 0x212)) + (i64.store offset=0x213 align=1 (i32.const 0) (local.get 0x213)) + (i64.store offset=0x214 align=1 (i32.const 0) (local.get 0x214)) + (i64.store offset=0x215 align=1 (i32.const 0) (local.get 0x215)) + (i64.store offset=0x216 align=1 (i32.const 0) (local.get 0x216)) + (i64.store offset=0x217 align=1 (i32.const 0) (local.get 0x217)) + (i64.store offset=0x218 align=1 (i32.const 0) (local.get 0x218)) + (i64.store offset=0x219 align=1 (i32.const 0) (local.get 0x219)) + (i64.store offset=0x21a align=1 (i32.const 0) (local.get 0x21a)) + (i64.store offset=0x21b align=1 (i32.const 0) (local.get 0x21b)) + (i64.store offset=0x21c align=1 (i32.const 0) (local.get 0x21c)) + (i64.store offset=0x21d align=1 (i32.const 0) (local.get 0x21d)) + (i64.store offset=0x21e align=1 (i32.const 0) (local.get 0x21e)) + (i64.store offset=0x21f align=1 (i32.const 0) (local.get 0x21f)) + (i64.store offset=0x220 align=1 (i32.const 0) (local.get 0x220)) + (i64.store offset=0x221 align=1 (i32.const 0) (local.get 0x221)) + (i64.store offset=0x222 align=1 (i32.const 0) (local.get 0x222)) + (i64.store offset=0x223 align=1 (i32.const 0) (local.get 0x223)) + (i64.store offset=0x224 align=1 (i32.const 0) (local.get 0x224)) + (i64.store offset=0x225 align=1 (i32.const 0) (local.get 0x225)) + (i64.store offset=0x226 align=1 (i32.const 0) (local.get 0x226)) + (i64.store offset=0x227 align=1 (i32.const 0) (local.get 0x227)) + (i64.store offset=0x228 align=1 (i32.const 0) (local.get 0x228)) + (i64.store offset=0x229 align=1 (i32.const 0) (local.get 0x229)) + (i64.store offset=0x22a align=1 (i32.const 0) (local.get 0x22a)) + (i64.store offset=0x22b align=1 (i32.const 0) (local.get 0x22b)) + (i64.store offset=0x22c align=1 (i32.const 0) (local.get 0x22c)) + (i64.store offset=0x22d align=1 (i32.const 0) (local.get 0x22d)) + (i64.store offset=0x22e align=1 (i32.const 0) (local.get 0x22e)) + (i64.store offset=0x22f align=1 (i32.const 0) (local.get 0x22f)) + (i64.store offset=0x230 align=1 (i32.const 0) (local.get 0x230)) + (i64.store offset=0x231 align=1 (i32.const 0) (local.get 0x231)) + (i64.store offset=0x232 align=1 (i32.const 0) (local.get 0x232)) + (i64.store offset=0x233 align=1 (i32.const 0) (local.get 0x233)) + (i64.store offset=0x234 align=1 (i32.const 0) (local.get 0x234)) + (i64.store offset=0x235 align=1 (i32.const 0) (local.get 0x235)) + (i64.store offset=0x236 align=1 (i32.const 0) (local.get 0x236)) + (i64.store offset=0x237 align=1 (i32.const 0) (local.get 0x237)) + (i64.store offset=0x238 align=1 (i32.const 0) (local.get 0x238)) + (i64.store offset=0x239 align=1 (i32.const 0) (local.get 0x239)) + (i64.store offset=0x23a align=1 (i32.const 0) (local.get 0x23a)) + (i64.store offset=0x23b align=1 (i32.const 0) (local.get 0x23b)) + (i64.store offset=0x23c align=1 (i32.const 0) (local.get 0x23c)) + (i64.store offset=0x23d align=1 (i32.const 0) (local.get 0x23d)) + (i64.store offset=0x23e align=1 (i32.const 0) (local.get 0x23e)) + (i64.store offset=0x23f align=1 (i32.const 0) (local.get 0x23f)) + (i64.store offset=0x240 align=1 (i32.const 0) (local.get 0x240)) + (i64.store offset=0x241 align=1 (i32.const 0) (local.get 0x241)) + (i64.store offset=0x242 align=1 (i32.const 0) (local.get 0x242)) + (i64.store offset=0x243 align=1 (i32.const 0) (local.get 0x243)) + (i64.store offset=0x244 align=1 (i32.const 0) (local.get 0x244)) + (i64.store offset=0x245 align=1 (i32.const 0) (local.get 0x245)) + (i64.store offset=0x246 align=1 (i32.const 0) (local.get 0x246)) + (i64.store offset=0x247 align=1 (i32.const 0) (local.get 0x247)) + (i64.store offset=0x248 align=1 (i32.const 0) (local.get 0x248)) + (i64.store offset=0x249 align=1 (i32.const 0) (local.get 0x249)) + (i64.store offset=0x24a align=1 (i32.const 0) (local.get 0x24a)) + (i64.store offset=0x24b align=1 (i32.const 0) (local.get 0x24b)) + (i64.store offset=0x24c align=1 (i32.const 0) (local.get 0x24c)) + (i64.store offset=0x24d align=1 (i32.const 0) (local.get 0x24d)) + (i64.store offset=0x24e align=1 (i32.const 0) (local.get 0x24e)) + (i64.store offset=0x24f align=1 (i32.const 0) (local.get 0x24f)) + (i64.store offset=0x250 align=1 (i32.const 0) (local.get 0x250)) + (i64.store offset=0x251 align=1 (i32.const 0) (local.get 0x251)) + (i64.store offset=0x252 align=1 (i32.const 0) (local.get 0x252)) + (i64.store offset=0x253 align=1 (i32.const 0) (local.get 0x253)) + (i64.store offset=0x254 align=1 (i32.const 0) (local.get 0x254)) + (i64.store offset=0x255 align=1 (i32.const 0) (local.get 0x255)) + (i64.store offset=0x256 align=1 (i32.const 0) (local.get 0x256)) + (i64.store offset=0x257 align=1 (i32.const 0) (local.get 0x257)) + (i64.store offset=0x258 align=1 (i32.const 0) (local.get 0x258)) + (i64.store offset=0x259 align=1 (i32.const 0) (local.get 0x259)) + (i64.store offset=0x25a align=1 (i32.const 0) (local.get 0x25a)) + (i64.store offset=0x25b align=1 (i32.const 0) (local.get 0x25b)) + (i64.store offset=0x25c align=1 (i32.const 0) (local.get 0x25c)) + (i64.store offset=0x25d align=1 (i32.const 0) (local.get 0x25d)) + (i64.store offset=0x25e align=1 (i32.const 0) (local.get 0x25e)) + (i64.store offset=0x25f align=1 (i32.const 0) (local.get 0x25f)) + (i64.store offset=0x260 align=1 (i32.const 0) (local.get 0x260)) + (i64.store offset=0x261 align=1 (i32.const 0) (local.get 0x261)) + (i64.store offset=0x262 align=1 (i32.const 0) (local.get 0x262)) + (i64.store offset=0x263 align=1 (i32.const 0) (local.get 0x263)) + (i64.store offset=0x264 align=1 (i32.const 0) (local.get 0x264)) + (i64.store offset=0x265 align=1 (i32.const 0) (local.get 0x265)) + (i64.store offset=0x266 align=1 (i32.const 0) (local.get 0x266)) + (i64.store offset=0x267 align=1 (i32.const 0) (local.get 0x267)) + (i64.store offset=0x268 align=1 (i32.const 0) (local.get 0x268)) + (i64.store offset=0x269 align=1 (i32.const 0) (local.get 0x269)) + (i64.store offset=0x26a align=1 (i32.const 0) (local.get 0x26a)) + (i64.store offset=0x26b align=1 (i32.const 0) (local.get 0x26b)) + (i64.store offset=0x26c align=1 (i32.const 0) (local.get 0x26c)) + (i64.store offset=0x26d align=1 (i32.const 0) (local.get 0x26d)) + (i64.store offset=0x26e align=1 (i32.const 0) (local.get 0x26e)) + (i64.store offset=0x26f align=1 (i32.const 0) (local.get 0x26f)) + (i64.store offset=0x270 align=1 (i32.const 0) (local.get 0x270)) + (i64.store offset=0x271 align=1 (i32.const 0) (local.get 0x271)) + (i64.store offset=0x272 align=1 (i32.const 0) (local.get 0x272)) + (i64.store offset=0x273 align=1 (i32.const 0) (local.get 0x273)) + (i64.store offset=0x274 align=1 (i32.const 0) (local.get 0x274)) + (i64.store offset=0x275 align=1 (i32.const 0) (local.get 0x275)) + (i64.store offset=0x276 align=1 (i32.const 0) (local.get 0x276)) + (i64.store offset=0x277 align=1 (i32.const 0) (local.get 0x277)) + (i64.store offset=0x278 align=1 (i32.const 0) (local.get 0x278)) + (i64.store offset=0x279 align=1 (i32.const 0) (local.get 0x279)) + (i64.store offset=0x27a align=1 (i32.const 0) (local.get 0x27a)) + (i64.store offset=0x27b align=1 (i32.const 0) (local.get 0x27b)) + (i64.store offset=0x27c align=1 (i32.const 0) (local.get 0x27c)) + (i64.store offset=0x27d align=1 (i32.const 0) (local.get 0x27d)) + (i64.store offset=0x27e align=1 (i32.const 0) (local.get 0x27e)) + (i64.store offset=0x27f align=1 (i32.const 0) (local.get 0x27f)) + (i64.store offset=0x280 align=1 (i32.const 0) (local.get 0x280)) + (i64.store offset=0x281 align=1 (i32.const 0) (local.get 0x281)) + (i64.store offset=0x282 align=1 (i32.const 0) (local.get 0x282)) + (i64.store offset=0x283 align=1 (i32.const 0) (local.get 0x283)) + (i64.store offset=0x284 align=1 (i32.const 0) (local.get 0x284)) + (i64.store offset=0x285 align=1 (i32.const 0) (local.get 0x285)) + (i64.store offset=0x286 align=1 (i32.const 0) (local.get 0x286)) + (i64.store offset=0x287 align=1 (i32.const 0) (local.get 0x287)) + (i64.store offset=0x288 align=1 (i32.const 0) (local.get 0x288)) + (i64.store offset=0x289 align=1 (i32.const 0) (local.get 0x289)) + (i64.store offset=0x28a align=1 (i32.const 0) (local.get 0x28a)) + (i64.store offset=0x28b align=1 (i32.const 0) (local.get 0x28b)) + (i64.store offset=0x28c align=1 (i32.const 0) (local.get 0x28c)) + (i64.store offset=0x28d align=1 (i32.const 0) (local.get 0x28d)) + (i64.store offset=0x28e align=1 (i32.const 0) (local.get 0x28e)) + (i64.store offset=0x28f align=1 (i32.const 0) (local.get 0x28f)) + (i64.store offset=0x290 align=1 (i32.const 0) (local.get 0x290)) + (i64.store offset=0x291 align=1 (i32.const 0) (local.get 0x291)) + (i64.store offset=0x292 align=1 (i32.const 0) (local.get 0x292)) + (i64.store offset=0x293 align=1 (i32.const 0) (local.get 0x293)) + (i64.store offset=0x294 align=1 (i32.const 0) (local.get 0x294)) + (i64.store offset=0x295 align=1 (i32.const 0) (local.get 0x295)) + (i64.store offset=0x296 align=1 (i32.const 0) (local.get 0x296)) + (i64.store offset=0x297 align=1 (i32.const 0) (local.get 0x297)) + (i64.store offset=0x298 align=1 (i32.const 0) (local.get 0x298)) + (i64.store offset=0x299 align=1 (i32.const 0) (local.get 0x299)) + (i64.store offset=0x29a align=1 (i32.const 0) (local.get 0x29a)) + (i64.store offset=0x29b align=1 (i32.const 0) (local.get 0x29b)) + (i64.store offset=0x29c align=1 (i32.const 0) (local.get 0x29c)) + (i64.store offset=0x29d align=1 (i32.const 0) (local.get 0x29d)) + (i64.store offset=0x29e align=1 (i32.const 0) (local.get 0x29e)) + (i64.store offset=0x29f align=1 (i32.const 0) (local.get 0x29f)) + (i64.store offset=0x2a0 align=1 (i32.const 0) (local.get 0x2a0)) + (i64.store offset=0x2a1 align=1 (i32.const 0) (local.get 0x2a1)) + (i64.store offset=0x2a2 align=1 (i32.const 0) (local.get 0x2a2)) + (i64.store offset=0x2a3 align=1 (i32.const 0) (local.get 0x2a3)) + (i64.store offset=0x2a4 align=1 (i32.const 0) (local.get 0x2a4)) + (i64.store offset=0x2a5 align=1 (i32.const 0) (local.get 0x2a5)) + (i64.store offset=0x2a6 align=1 (i32.const 0) (local.get 0x2a6)) + (i64.store offset=0x2a7 align=1 (i32.const 0) (local.get 0x2a7)) + (i64.store offset=0x2a8 align=1 (i32.const 0) (local.get 0x2a8)) + (i64.store offset=0x2a9 align=1 (i32.const 0) (local.get 0x2a9)) + (i64.store offset=0x2aa align=1 (i32.const 0) (local.get 0x2aa)) + (i64.store offset=0x2ab align=1 (i32.const 0) (local.get 0x2ab)) + (i64.store offset=0x2ac align=1 (i32.const 0) (local.get 0x2ac)) + (i64.store offset=0x2ad align=1 (i32.const 0) (local.get 0x2ad)) + (i64.store offset=0x2ae align=1 (i32.const 0) (local.get 0x2ae)) + (i64.store offset=0x2af align=1 (i32.const 0) (local.get 0x2af)) + (i64.store offset=0x2b0 align=1 (i32.const 0) (local.get 0x2b0)) + (i64.store offset=0x2b1 align=1 (i32.const 0) (local.get 0x2b1)) + (i64.store offset=0x2b2 align=1 (i32.const 0) (local.get 0x2b2)) + (i64.store offset=0x2b3 align=1 (i32.const 0) (local.get 0x2b3)) + (i64.store offset=0x2b4 align=1 (i32.const 0) (local.get 0x2b4)) + (i64.store offset=0x2b5 align=1 (i32.const 0) (local.get 0x2b5)) + (i64.store offset=0x2b6 align=1 (i32.const 0) (local.get 0x2b6)) + (i64.store offset=0x2b7 align=1 (i32.const 0) (local.get 0x2b7)) + (i64.store offset=0x2b8 align=1 (i32.const 0) (local.get 0x2b8)) + (i64.store offset=0x2b9 align=1 (i32.const 0) (local.get 0x2b9)) + (i64.store offset=0x2ba align=1 (i32.const 0) (local.get 0x2ba)) + (i64.store offset=0x2bb align=1 (i32.const 0) (local.get 0x2bb)) + (i64.store offset=0x2bc align=1 (i32.const 0) (local.get 0x2bc)) + (i64.store offset=0x2bd align=1 (i32.const 0) (local.get 0x2bd)) + (i64.store offset=0x2be align=1 (i32.const 0) (local.get 0x2be)) + (i64.store offset=0x2bf align=1 (i32.const 0) (local.get 0x2bf)) + (i64.store offset=0x2c0 align=1 (i32.const 0) (local.get 0x2c0)) + (i64.store offset=0x2c1 align=1 (i32.const 0) (local.get 0x2c1)) + (i64.store offset=0x2c2 align=1 (i32.const 0) (local.get 0x2c2)) + (i64.store offset=0x2c3 align=1 (i32.const 0) (local.get 0x2c3)) + (i64.store offset=0x2c4 align=1 (i32.const 0) (local.get 0x2c4)) + (i64.store offset=0x2c5 align=1 (i32.const 0) (local.get 0x2c5)) + (i64.store offset=0x2c6 align=1 (i32.const 0) (local.get 0x2c6)) + (i64.store offset=0x2c7 align=1 (i32.const 0) (local.get 0x2c7)) + (i64.store offset=0x2c8 align=1 (i32.const 0) (local.get 0x2c8)) + (i64.store offset=0x2c9 align=1 (i32.const 0) (local.get 0x2c9)) + (i64.store offset=0x2ca align=1 (i32.const 0) (local.get 0x2ca)) + (i64.store offset=0x2cb align=1 (i32.const 0) (local.get 0x2cb)) + (i64.store offset=0x2cc align=1 (i32.const 0) (local.get 0x2cc)) + (i64.store offset=0x2cd align=1 (i32.const 0) (local.get 0x2cd)) + (i64.store offset=0x2ce align=1 (i32.const 0) (local.get 0x2ce)) + (i64.store offset=0x2cf align=1 (i32.const 0) (local.get 0x2cf)) + (i64.store offset=0x2d0 align=1 (i32.const 0) (local.get 0x2d0)) + (i64.store offset=0x2d1 align=1 (i32.const 0) (local.get 0x2d1)) + (i64.store offset=0x2d2 align=1 (i32.const 0) (local.get 0x2d2)) + (i64.store offset=0x2d3 align=1 (i32.const 0) (local.get 0x2d3)) + (i64.store offset=0x2d4 align=1 (i32.const 0) (local.get 0x2d4)) + (i64.store offset=0x2d5 align=1 (i32.const 0) (local.get 0x2d5)) + (i64.store offset=0x2d6 align=1 (i32.const 0) (local.get 0x2d6)) + (i64.store offset=0x2d7 align=1 (i32.const 0) (local.get 0x2d7)) + (i64.store offset=0x2d8 align=1 (i32.const 0) (local.get 0x2d8)) + (i64.store offset=0x2d9 align=1 (i32.const 0) (local.get 0x2d9)) + (i64.store offset=0x2da align=1 (i32.const 0) (local.get 0x2da)) + (i64.store offset=0x2db align=1 (i32.const 0) (local.get 0x2db)) + (i64.store offset=0x2dc align=1 (i32.const 0) (local.get 0x2dc)) + (i64.store offset=0x2dd align=1 (i32.const 0) (local.get 0x2dd)) + (i64.store offset=0x2de align=1 (i32.const 0) (local.get 0x2de)) + (i64.store offset=0x2df align=1 (i32.const 0) (local.get 0x2df)) + (i64.store offset=0x2e0 align=1 (i32.const 0) (local.get 0x2e0)) + (i64.store offset=0x2e1 align=1 (i32.const 0) (local.get 0x2e1)) + (i64.store offset=0x2e2 align=1 (i32.const 0) (local.get 0x2e2)) + (i64.store offset=0x2e3 align=1 (i32.const 0) (local.get 0x2e3)) + (i64.store offset=0x2e4 align=1 (i32.const 0) (local.get 0x2e4)) + (i64.store offset=0x2e5 align=1 (i32.const 0) (local.get 0x2e5)) + (i64.store offset=0x2e6 align=1 (i32.const 0) (local.get 0x2e6)) + (i64.store offset=0x2e7 align=1 (i32.const 0) (local.get 0x2e7)) + (i64.store offset=0x2e8 align=1 (i32.const 0) (local.get 0x2e8)) + (i64.store offset=0x2e9 align=1 (i32.const 0) (local.get 0x2e9)) + (i64.store offset=0x2ea align=1 (i32.const 0) (local.get 0x2ea)) + (i64.store offset=0x2eb align=1 (i32.const 0) (local.get 0x2eb)) + (i64.store offset=0x2ec align=1 (i32.const 0) (local.get 0x2ec)) + (i64.store offset=0x2ed align=1 (i32.const 0) (local.get 0x2ed)) + (i64.store offset=0x2ee align=1 (i32.const 0) (local.get 0x2ee)) + (i64.store offset=0x2ef align=1 (i32.const 0) (local.get 0x2ef)) + (i64.store offset=0x2f0 align=1 (i32.const 0) (local.get 0x2f0)) + (i64.store offset=0x2f1 align=1 (i32.const 0) (local.get 0x2f1)) + (i64.store offset=0x2f2 align=1 (i32.const 0) (local.get 0x2f2)) + (i64.store offset=0x2f3 align=1 (i32.const 0) (local.get 0x2f3)) + (i64.store offset=0x2f4 align=1 (i32.const 0) (local.get 0x2f4)) + (i64.store offset=0x2f5 align=1 (i32.const 0) (local.get 0x2f5)) + (i64.store offset=0x2f6 align=1 (i32.const 0) (local.get 0x2f6)) + (i64.store offset=0x2f7 align=1 (i32.const 0) (local.get 0x2f7)) + (i64.store offset=0x2f8 align=1 (i32.const 0) (local.get 0x2f8)) + (i64.store offset=0x2f9 align=1 (i32.const 0) (local.get 0x2f9)) + (i64.store offset=0x2fa align=1 (i32.const 0) (local.get 0x2fa)) + (i64.store offset=0x2fb align=1 (i32.const 0) (local.get 0x2fb)) + (i64.store offset=0x2fc align=1 (i32.const 0) (local.get 0x2fc)) + (i64.store offset=0x2fd align=1 (i32.const 0) (local.get 0x2fd)) + (i64.store offset=0x2fe align=1 (i32.const 0) (local.get 0x2fe)) + (i64.store offset=0x2ff align=1 (i32.const 0) (local.get 0x2ff)) + (i64.store offset=0x300 align=1 (i32.const 0) (local.get 0x300)) + (i64.store offset=0x301 align=1 (i32.const 0) (local.get 0x301)) + (i64.store offset=0x302 align=1 (i32.const 0) (local.get 0x302)) + (i64.store offset=0x303 align=1 (i32.const 0) (local.get 0x303)) + (i64.store offset=0x304 align=1 (i32.const 0) (local.get 0x304)) + (i64.store offset=0x305 align=1 (i32.const 0) (local.get 0x305)) + (i64.store offset=0x306 align=1 (i32.const 0) (local.get 0x306)) + (i64.store offset=0x307 align=1 (i32.const 0) (local.get 0x307)) + (i64.store offset=0x308 align=1 (i32.const 0) (local.get 0x308)) + (i64.store offset=0x309 align=1 (i32.const 0) (local.get 0x309)) + (i64.store offset=0x30a align=1 (i32.const 0) (local.get 0x30a)) + (i64.store offset=0x30b align=1 (i32.const 0) (local.get 0x30b)) + (i64.store offset=0x30c align=1 (i32.const 0) (local.get 0x30c)) + (i64.store offset=0x30d align=1 (i32.const 0) (local.get 0x30d)) + (i64.store offset=0x30e align=1 (i32.const 0) (local.get 0x30e)) + (i64.store offset=0x30f align=1 (i32.const 0) (local.get 0x30f)) + (i64.store offset=0x310 align=1 (i32.const 0) (local.get 0x310)) + (i64.store offset=0x311 align=1 (i32.const 0) (local.get 0x311)) + (i64.store offset=0x312 align=1 (i32.const 0) (local.get 0x312)) + (i64.store offset=0x313 align=1 (i32.const 0) (local.get 0x313)) + (i64.store offset=0x314 align=1 (i32.const 0) (local.get 0x314)) + (i64.store offset=0x315 align=1 (i32.const 0) (local.get 0x315)) + (i64.store offset=0x316 align=1 (i32.const 0) (local.get 0x316)) + (i64.store offset=0x317 align=1 (i32.const 0) (local.get 0x317)) + (i64.store offset=0x318 align=1 (i32.const 0) (local.get 0x318)) + (i64.store offset=0x319 align=1 (i32.const 0) (local.get 0x319)) + (i64.store offset=0x31a align=1 (i32.const 0) (local.get 0x31a)) + (i64.store offset=0x31b align=1 (i32.const 0) (local.get 0x31b)) + (i64.store offset=0x31c align=1 (i32.const 0) (local.get 0x31c)) + (i64.store offset=0x31d align=1 (i32.const 0) (local.get 0x31d)) + (i64.store offset=0x31e align=1 (i32.const 0) (local.get 0x31e)) + (i64.store offset=0x31f align=1 (i32.const 0) (local.get 0x31f)) + (i64.store offset=0x320 align=1 (i32.const 0) (local.get 0x320)) + (i64.store offset=0x321 align=1 (i32.const 0) (local.get 0x321)) + (i64.store offset=0x322 align=1 (i32.const 0) (local.get 0x322)) + (i64.store offset=0x323 align=1 (i32.const 0) (local.get 0x323)) + (i64.store offset=0x324 align=1 (i32.const 0) (local.get 0x324)) + (i64.store offset=0x325 align=1 (i32.const 0) (local.get 0x325)) + (i64.store offset=0x326 align=1 (i32.const 0) (local.get 0x326)) + (i64.store offset=0x327 align=1 (i32.const 0) (local.get 0x327)) + (i64.store offset=0x328 align=1 (i32.const 0) (local.get 0x328)) + (i64.store offset=0x329 align=1 (i32.const 0) (local.get 0x329)) + (i64.store offset=0x32a align=1 (i32.const 0) (local.get 0x32a)) + (i64.store offset=0x32b align=1 (i32.const 0) (local.get 0x32b)) + (i64.store offset=0x32c align=1 (i32.const 0) (local.get 0x32c)) + (i64.store offset=0x32d align=1 (i32.const 0) (local.get 0x32d)) + (i64.store offset=0x32e align=1 (i32.const 0) (local.get 0x32e)) + (i64.store offset=0x32f align=1 (i32.const 0) (local.get 0x32f)) + (i64.store offset=0x330 align=1 (i32.const 0) (local.get 0x330)) + (i64.store offset=0x331 align=1 (i32.const 0) (local.get 0x331)) + (i64.store offset=0x332 align=1 (i32.const 0) (local.get 0x332)) + (i64.store offset=0x333 align=1 (i32.const 0) (local.get 0x333)) + (i64.store offset=0x334 align=1 (i32.const 0) (local.get 0x334)) + (i64.store offset=0x335 align=1 (i32.const 0) (local.get 0x335)) + (i64.store offset=0x336 align=1 (i32.const 0) (local.get 0x336)) + (i64.store offset=0x337 align=1 (i32.const 0) (local.get 0x337)) + (i64.store offset=0x338 align=1 (i32.const 0) (local.get 0x338)) + (i64.store offset=0x339 align=1 (i32.const 0) (local.get 0x339)) + (i64.store offset=0x33a align=1 (i32.const 0) (local.get 0x33a)) + (i64.store offset=0x33b align=1 (i32.const 0) (local.get 0x33b)) + (i64.store offset=0x33c align=1 (i32.const 0) (local.get 0x33c)) + (i64.store offset=0x33d align=1 (i32.const 0) (local.get 0x33d)) + (i64.store offset=0x33e align=1 (i32.const 0) (local.get 0x33e)) + (i64.store offset=0x33f align=1 (i32.const 0) (local.get 0x33f)) + (i64.store offset=0x340 align=1 (i32.const 0) (local.get 0x340)) + (i64.store offset=0x341 align=1 (i32.const 0) (local.get 0x341)) + (i64.store offset=0x342 align=1 (i32.const 0) (local.get 0x342)) + (i64.store offset=0x343 align=1 (i32.const 0) (local.get 0x343)) + (i64.store offset=0x344 align=1 (i32.const 0) (local.get 0x344)) + (i64.store offset=0x345 align=1 (i32.const 0) (local.get 0x345)) + (i64.store offset=0x346 align=1 (i32.const 0) (local.get 0x346)) + (i64.store offset=0x347 align=1 (i32.const 0) (local.get 0x347)) + (i64.store offset=0x348 align=1 (i32.const 0) (local.get 0x348)) + (i64.store offset=0x349 align=1 (i32.const 0) (local.get 0x349)) + (i64.store offset=0x34a align=1 (i32.const 0) (local.get 0x34a)) + (i64.store offset=0x34b align=1 (i32.const 0) (local.get 0x34b)) + (i64.store offset=0x34c align=1 (i32.const 0) (local.get 0x34c)) + (i64.store offset=0x34d align=1 (i32.const 0) (local.get 0x34d)) + (i64.store offset=0x34e align=1 (i32.const 0) (local.get 0x34e)) + (i64.store offset=0x34f align=1 (i32.const 0) (local.get 0x34f)) + (i64.store offset=0x350 align=1 (i32.const 0) (local.get 0x350)) + (i64.store offset=0x351 align=1 (i32.const 0) (local.get 0x351)) + (i64.store offset=0x352 align=1 (i32.const 0) (local.get 0x352)) + (i64.store offset=0x353 align=1 (i32.const 0) (local.get 0x353)) + (i64.store offset=0x354 align=1 (i32.const 0) (local.get 0x354)) + (i64.store offset=0x355 align=1 (i32.const 0) (local.get 0x355)) + (i64.store offset=0x356 align=1 (i32.const 0) (local.get 0x356)) + (i64.store offset=0x357 align=1 (i32.const 0) (local.get 0x357)) + (i64.store offset=0x358 align=1 (i32.const 0) (local.get 0x358)) + (i64.store offset=0x359 align=1 (i32.const 0) (local.get 0x359)) + (i64.store offset=0x35a align=1 (i32.const 0) (local.get 0x35a)) + (i64.store offset=0x35b align=1 (i32.const 0) (local.get 0x35b)) + (i64.store offset=0x35c align=1 (i32.const 0) (local.get 0x35c)) + (i64.store offset=0x35d align=1 (i32.const 0) (local.get 0x35d)) + (i64.store offset=0x35e align=1 (i32.const 0) (local.get 0x35e)) + (i64.store offset=0x35f align=1 (i32.const 0) (local.get 0x35f)) + (i64.store offset=0x360 align=1 (i32.const 0) (local.get 0x360)) + (i64.store offset=0x361 align=1 (i32.const 0) (local.get 0x361)) + (i64.store offset=0x362 align=1 (i32.const 0) (local.get 0x362)) + (i64.store offset=0x363 align=1 (i32.const 0) (local.get 0x363)) + (i64.store offset=0x364 align=1 (i32.const 0) (local.get 0x364)) + (i64.store offset=0x365 align=1 (i32.const 0) (local.get 0x365)) + (i64.store offset=0x366 align=1 (i32.const 0) (local.get 0x366)) + (i64.store offset=0x367 align=1 (i32.const 0) (local.get 0x367)) + (i64.store offset=0x368 align=1 (i32.const 0) (local.get 0x368)) + (i64.store offset=0x369 align=1 (i32.const 0) (local.get 0x369)) + (i64.store offset=0x36a align=1 (i32.const 0) (local.get 0x36a)) + (i64.store offset=0x36b align=1 (i32.const 0) (local.get 0x36b)) + (i64.store offset=0x36c align=1 (i32.const 0) (local.get 0x36c)) + (i64.store offset=0x36d align=1 (i32.const 0) (local.get 0x36d)) + (i64.store offset=0x36e align=1 (i32.const 0) (local.get 0x36e)) + (i64.store offset=0x36f align=1 (i32.const 0) (local.get 0x36f)) + (i64.store offset=0x370 align=1 (i32.const 0) (local.get 0x370)) + (i64.store offset=0x371 align=1 (i32.const 0) (local.get 0x371)) + (i64.store offset=0x372 align=1 (i32.const 0) (local.get 0x372)) + (i64.store offset=0x373 align=1 (i32.const 0) (local.get 0x373)) + (i64.store offset=0x374 align=1 (i32.const 0) (local.get 0x374)) + (i64.store offset=0x375 align=1 (i32.const 0) (local.get 0x375)) + (i64.store offset=0x376 align=1 (i32.const 0) (local.get 0x376)) + (i64.store offset=0x377 align=1 (i32.const 0) (local.get 0x377)) + (i64.store offset=0x378 align=1 (i32.const 0) (local.get 0x378)) + (i64.store offset=0x379 align=1 (i32.const 0) (local.get 0x379)) + (i64.store offset=0x37a align=1 (i32.const 0) (local.get 0x37a)) + (i64.store offset=0x37b align=1 (i32.const 0) (local.get 0x37b)) + (i64.store offset=0x37c align=1 (i32.const 0) (local.get 0x37c)) + (i64.store offset=0x37d align=1 (i32.const 0) (local.get 0x37d)) + (i64.store offset=0x37e align=1 (i32.const 0) (local.get 0x37e)) + (i64.store offset=0x37f align=1 (i32.const 0) (local.get 0x37f)) + (i64.store offset=0x380 align=1 (i32.const 0) (local.get 0x380)) + (i64.store offset=0x381 align=1 (i32.const 0) (local.get 0x381)) + (i64.store offset=0x382 align=1 (i32.const 0) (local.get 0x382)) + (i64.store offset=0x383 align=1 (i32.const 0) (local.get 0x383)) + (i64.store offset=0x384 align=1 (i32.const 0) (local.get 0x384)) + (i64.store offset=0x385 align=1 (i32.const 0) (local.get 0x385)) + (i64.store offset=0x386 align=1 (i32.const 0) (local.get 0x386)) + (i64.store offset=0x387 align=1 (i32.const 0) (local.get 0x387)) + (i64.store offset=0x388 align=1 (i32.const 0) (local.get 0x388)) + (i64.store offset=0x389 align=1 (i32.const 0) (local.get 0x389)) + (i64.store offset=0x38a align=1 (i32.const 0) (local.get 0x38a)) + (i64.store offset=0x38b align=1 (i32.const 0) (local.get 0x38b)) + (i64.store offset=0x38c align=1 (i32.const 0) (local.get 0x38c)) + (i64.store offset=0x38d align=1 (i32.const 0) (local.get 0x38d)) + (i64.store offset=0x38e align=1 (i32.const 0) (local.get 0x38e)) + (i64.store offset=0x38f align=1 (i32.const 0) (local.get 0x38f)) + (i64.store offset=0x390 align=1 (i32.const 0) (local.get 0x390)) + (i64.store offset=0x391 align=1 (i32.const 0) (local.get 0x391)) + (i64.store offset=0x392 align=1 (i32.const 0) (local.get 0x392)) + (i64.store offset=0x393 align=1 (i32.const 0) (local.get 0x393)) + (i64.store offset=0x394 align=1 (i32.const 0) (local.get 0x394)) + (i64.store offset=0x395 align=1 (i32.const 0) (local.get 0x395)) + (i64.store offset=0x396 align=1 (i32.const 0) (local.get 0x396)) + (i64.store offset=0x397 align=1 (i32.const 0) (local.get 0x397)) + (i64.store offset=0x398 align=1 (i32.const 0) (local.get 0x398)) + (i64.store offset=0x399 align=1 (i32.const 0) (local.get 0x399)) + (i64.store offset=0x39a align=1 (i32.const 0) (local.get 0x39a)) + (i64.store offset=0x39b align=1 (i32.const 0) (local.get 0x39b)) + (i64.store offset=0x39c align=1 (i32.const 0) (local.get 0x39c)) + (i64.store offset=0x39d align=1 (i32.const 0) (local.get 0x39d)) + (i64.store offset=0x39e align=1 (i32.const 0) (local.get 0x39e)) + (i64.store offset=0x39f align=1 (i32.const 0) (local.get 0x39f)) + (i64.store offset=0x3a0 align=1 (i32.const 0) (local.get 0x3a0)) + (i64.store offset=0x3a1 align=1 (i32.const 0) (local.get 0x3a1)) + (i64.store offset=0x3a2 align=1 (i32.const 0) (local.get 0x3a2)) + (i64.store offset=0x3a3 align=1 (i32.const 0) (local.get 0x3a3)) + (i64.store offset=0x3a4 align=1 (i32.const 0) (local.get 0x3a4)) + (i64.store offset=0x3a5 align=1 (i32.const 0) (local.get 0x3a5)) + (i64.store offset=0x3a6 align=1 (i32.const 0) (local.get 0x3a6)) + (i64.store offset=0x3a7 align=1 (i32.const 0) (local.get 0x3a7)) + (i64.store offset=0x3a8 align=1 (i32.const 0) (local.get 0x3a8)) + (i64.store offset=0x3a9 align=1 (i32.const 0) (local.get 0x3a9)) + (i64.store offset=0x3aa align=1 (i32.const 0) (local.get 0x3aa)) + (i64.store offset=0x3ab align=1 (i32.const 0) (local.get 0x3ab)) + (i64.store offset=0x3ac align=1 (i32.const 0) (local.get 0x3ac)) + (i64.store offset=0x3ad align=1 (i32.const 0) (local.get 0x3ad)) + (i64.store offset=0x3ae align=1 (i32.const 0) (local.get 0x3ae)) + (i64.store offset=0x3af align=1 (i32.const 0) (local.get 0x3af)) + (i64.store offset=0x3b0 align=1 (i32.const 0) (local.get 0x3b0)) + (i64.store offset=0x3b1 align=1 (i32.const 0) (local.get 0x3b1)) + (i64.store offset=0x3b2 align=1 (i32.const 0) (local.get 0x3b2)) + (i64.store offset=0x3b3 align=1 (i32.const 0) (local.get 0x3b3)) + (i64.store offset=0x3b4 align=1 (i32.const 0) (local.get 0x3b4)) + (i64.store offset=0x3b5 align=1 (i32.const 0) (local.get 0x3b5)) + (i64.store offset=0x3b6 align=1 (i32.const 0) (local.get 0x3b6)) + (i64.store offset=0x3b7 align=1 (i32.const 0) (local.get 0x3b7)) + (i64.store offset=0x3b8 align=1 (i32.const 0) (local.get 0x3b8)) + (i64.store offset=0x3b9 align=1 (i32.const 0) (local.get 0x3b9)) + (i64.store offset=0x3ba align=1 (i32.const 0) (local.get 0x3ba)) + (i64.store offset=0x3bb align=1 (i32.const 0) (local.get 0x3bb)) + (i64.store offset=0x3bc align=1 (i32.const 0) (local.get 0x3bc)) + (i64.store offset=0x3bd align=1 (i32.const 0) (local.get 0x3bd)) + (i64.store offset=0x3be align=1 (i32.const 0) (local.get 0x3be)) + (i64.store offset=0x3bf align=1 (i32.const 0) (local.get 0x3bf)) + (i64.store offset=0x3c0 align=1 (i32.const 0) (local.get 0x3c0)) + (i64.store offset=0x3c1 align=1 (i32.const 0) (local.get 0x3c1)) + (i64.store offset=0x3c2 align=1 (i32.const 0) (local.get 0x3c2)) + (i64.store offset=0x3c3 align=1 (i32.const 0) (local.get 0x3c3)) + (i64.store offset=0x3c4 align=1 (i32.const 0) (local.get 0x3c4)) + (i64.store offset=0x3c5 align=1 (i32.const 0) (local.get 0x3c5)) + (i64.store offset=0x3c6 align=1 (i32.const 0) (local.get 0x3c6)) + (i64.store offset=0x3c7 align=1 (i32.const 0) (local.get 0x3c7)) + (i64.store offset=0x3c8 align=1 (i32.const 0) (local.get 0x3c8)) + (i64.store offset=0x3c9 align=1 (i32.const 0) (local.get 0x3c9)) + (i64.store offset=0x3ca align=1 (i32.const 0) (local.get 0x3ca)) + (i64.store offset=0x3cb align=1 (i32.const 0) (local.get 0x3cb)) + (i64.store offset=0x3cc align=1 (i32.const 0) (local.get 0x3cc)) + (i64.store offset=0x3cd align=1 (i32.const 0) (local.get 0x3cd)) + (i64.store offset=0x3ce align=1 (i32.const 0) (local.get 0x3ce)) + (i64.store offset=0x3cf align=1 (i32.const 0) (local.get 0x3cf)) + (i64.store offset=0x3d0 align=1 (i32.const 0) (local.get 0x3d0)) + (i64.store offset=0x3d1 align=1 (i32.const 0) (local.get 0x3d1)) + (i64.store offset=0x3d2 align=1 (i32.const 0) (local.get 0x3d2)) + (i64.store offset=0x3d3 align=1 (i32.const 0) (local.get 0x3d3)) + (i64.store offset=0x3d4 align=1 (i32.const 0) (local.get 0x3d4)) + (i64.store offset=0x3d5 align=1 (i32.const 0) (local.get 0x3d5)) + (i64.store offset=0x3d6 align=1 (i32.const 0) (local.get 0x3d6)) + (i64.store offset=0x3d7 align=1 (i32.const 0) (local.get 0x3d7)) + (i64.store offset=0x3d8 align=1 (i32.const 0) (local.get 0x3d8)) + (i64.store offset=0x3d9 align=1 (i32.const 0) (local.get 0x3d9)) + (i64.store offset=0x3da align=1 (i32.const 0) (local.get 0x3da)) + (i64.store offset=0x3db align=1 (i32.const 0) (local.get 0x3db)) + (i64.store offset=0x3dc align=1 (i32.const 0) (local.get 0x3dc)) + (i64.store offset=0x3dd align=1 (i32.const 0) (local.get 0x3dd)) + (i64.store offset=0x3de align=1 (i32.const 0) (local.get 0x3de)) + (i64.store offset=0x3df align=1 (i32.const 0) (local.get 0x3df)) + (i64.store offset=0x3e0 align=1 (i32.const 0) (local.get 0x3e0)) + (i64.store offset=0x3e1 align=1 (i32.const 0) (local.get 0x3e1)) + (i64.store offset=0x3e2 align=1 (i32.const 0) (local.get 0x3e2)) + (i64.store offset=0x3e3 align=1 (i32.const 0) (local.get 0x3e3)) + (i64.store offset=0x3e4 align=1 (i32.const 0) (local.get 0x3e4)) + (i64.store offset=0x3e5 align=1 (i32.const 0) (local.get 0x3e5)) + (i64.store offset=0x3e6 align=1 (i32.const 0) (local.get 0x3e6)) + (i64.store offset=0x3e7 align=1 (i32.const 0) (local.get 0x3e7)) + (i64.store offset=0x3e8 align=1 (i32.const 0) (local.get 0x3e8)) + (i64.store offset=0x3e9 align=1 (i32.const 0) (local.get 0x3e9)) + (i64.store offset=0x3ea align=1 (i32.const 0) (local.get 0x3ea)) + (i64.store offset=0x3eb align=1 (i32.const 0) (local.get 0x3eb)) + (i64.store offset=0x3ec align=1 (i32.const 0) (local.get 0x3ec)) + (i64.store offset=0x3ed align=1 (i32.const 0) (local.get 0x3ed)) + (i64.store offset=0x3ee align=1 (i32.const 0) (local.get 0x3ee)) + (i64.store offset=0x3ef align=1 (i32.const 0) (local.get 0x3ef)) + (i64.store offset=0x3f0 align=1 (i32.const 0) (local.get 0x3f0)) + (i64.store offset=0x3f1 align=1 (i32.const 0) (local.get 0x3f1)) + (i64.store offset=0x3f2 align=1 (i32.const 0) (local.get 0x3f2)) + (i64.store offset=0x3f3 align=1 (i32.const 0) (local.get 0x3f3)) + (i64.store offset=0x3f4 align=1 (i32.const 0) (local.get 0x3f4)) + (i64.store offset=0x3f5 align=1 (i32.const 0) (local.get 0x3f5)) + (i64.store offset=0x3f6 align=1 (i32.const 0) (local.get 0x3f6)) + (i64.store offset=0x3f7 align=1 (i32.const 0) (local.get 0x3f7)) + (i64.store offset=0x3f8 align=1 (i32.const 0) (local.get 0x3f8)) + (i64.store offset=0x3f9 align=1 (i32.const 0) (local.get 0x3f9)) + (i64.store offset=0x3fa align=1 (i32.const 0) (local.get 0x3fa)) + (i64.store offset=0x3fb align=1 (i32.const 0) (local.get 0x3fb)) + (i64.store offset=0x3fc align=1 (i32.const 0) (local.get 0x3fc)) + (i64.store offset=0x3fd align=1 (i32.const 0) (local.get 0x3fd)) + (i64.store offset=0x3fe align=1 (i32.const 0) (local.get 0x3fe)) + (i64.store offset=0x3ff align=1 (i32.const 0) (local.get 0x3ff)) + (i64.store offset=0x400 align=1 (i32.const 0) (local.get 0x400)) + (i64.store offset=0x401 align=1 (i32.const 0) (local.get 0x401)) + (i64.store offset=0x402 align=1 (i32.const 0) (local.get 0x402)) + (i64.store offset=0x403 align=1 (i32.const 0) (local.get 0x403)) + (i64.store offset=0x404 align=1 (i32.const 0) (local.get 0x404)) + (i64.store offset=0x405 align=1 (i32.const 0) (local.get 0x405)) + (i64.store offset=0x406 align=1 (i32.const 0) (local.get 0x406)) + (i64.store offset=0x407 align=1 (i32.const 0) (local.get 0x407)) + (i64.store offset=0x408 align=1 (i32.const 0) (local.get 0x408)) + (i64.store offset=0x409 align=1 (i32.const 0) (local.get 0x409)) + (i64.store offset=0x40a align=1 (i32.const 0) (local.get 0x40a)) + (i64.store offset=0x40b align=1 (i32.const 0) (local.get 0x40b)) + (i64.store offset=0x40c align=1 (i32.const 0) (local.get 0x40c)) + (i64.store offset=0x40d align=1 (i32.const 0) (local.get 0x40d)) + (i64.store offset=0x40e align=1 (i32.const 0) (local.get 0x40e)) + (i64.store offset=0x40f align=1 (i32.const 0) (local.get 0x40f)) + (i64.store offset=0x410 align=1 (i32.const 0) (local.get 0x410)) + (i64.store offset=0x411 align=1 (i32.const 0) (local.get 0x411)) + (i64.store offset=0x412 align=1 (i32.const 0) (local.get 0x412)) + (i64.store offset=0x413 align=1 (i32.const 0) (local.get 0x413)) + (i64.store offset=0x414 align=1 (i32.const 0) (local.get 0x414)) + (i64.store offset=0x415 align=1 (i32.const 0) (local.get 0x415)) + (i64.store offset=0x416 align=1 (i32.const 0) (local.get 0x416)) + (i64.store offset=0x417 align=1 (i32.const 0) (local.get 0x417)) + (i64.store offset=0x418 align=1 (i32.const 0) (local.get 0x418)) + (i64.store offset=0x419 align=1 (i32.const 0) (local.get 0x419)) + (i64.store offset=0x41a align=1 (i32.const 0) (local.get 0x41a)) + (i64.store offset=0x41b align=1 (i32.const 0) (local.get 0x41b)) + (i64.store offset=0x41c align=1 (i32.const 0) (local.get 0x41c)) + (i64.store offset=0x41d align=1 (i32.const 0) (local.get 0x41d)) + (i64.store offset=0x41e align=1 (i32.const 0) (local.get 0x41e)) + (i64.store offset=0x41f align=1 (i32.const 0) (local.get 0x41f)) + ) +) diff --git a/substrate/runtime-executor/wasmtime/src/tests.rs b/substrate/runtime-executor/wasmtime/src/tests.rs new file mode 100644 index 00000000000..116b960d70d --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/tests.rs @@ -0,0 +1,551 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use codec::{Decode as _, Encode as _}; +use sc_executor_common::{ + error::Error, + runtime_blob::RuntimeBlob, + wasm_runtime::{DEFAULT_HEAP_ALLOC_STRATEGY, HeapAllocStrategy, WasmModule}, +}; +use sc_runtime_test::wasm_binary_unwrap; + +use crate::InstantiationStrategy; + +type HostFunctions = sp_io::SubstrateHostFunctions; + +#[macro_export] +macro_rules! test_wasm_execution { + ($method_name:ident) => { + paste::item! { + #[test] + fn [<$method_name _recreate_instance_cow>]() { + $method_name( + InstantiationStrategy::RecreateInstanceCopyOnWrite + ); + } + + #[test] + fn [<$method_name _recreate_instance_vanilla>]() { + $method_name( + InstantiationStrategy::RecreateInstance + ); + } + + #[test] + fn [<$method_name _pooling_cow>]() { + $method_name( + InstantiationStrategy::PoolingCopyOnWrite + ); + } + + #[test] + fn [<$method_name _pooling_vanilla>]() { + $method_name( + InstantiationStrategy::Pooling + ); + } + } + }; +} + +struct RuntimeBuilder { + code: Option, + instantiation_strategy: InstantiationStrategy, + canonicalize_nans: bool, + deterministic_stack: bool, + heap_pages: HeapAllocStrategy, + precompile_runtime: bool, + tmpdir: Option, +} + +impl RuntimeBuilder { + fn new(instantiation_strategy: InstantiationStrategy) -> Self { + Self { + code: None, + instantiation_strategy, + canonicalize_nans: false, + deterministic_stack: false, + heap_pages: DEFAULT_HEAP_ALLOC_STRATEGY, + precompile_runtime: false, + tmpdir: None, + } + } + + fn use_wat(mut self, code: String) -> Self { + self.code = Some(code); + self + } + + fn canonicalize_nans(mut self, canonicalize_nans: bool) -> Self { + self.canonicalize_nans = canonicalize_nans; + self + } + + fn deterministic_stack(mut self, deterministic_stack: bool) -> Self { + self.deterministic_stack = deterministic_stack; + self + } + + fn precompile_runtime(mut self, precompile_runtime: bool) -> Self { + self.precompile_runtime = precompile_runtime; + self + } + + fn heap_alloc_strategy(mut self, heap_pages: HeapAllocStrategy) -> Self { + self.heap_pages = heap_pages; + self + } + + fn build(&mut self) -> impl WasmModule + '_ { + let blob = { + let wasm: Vec; + + let wasm = match self.code { + None => wasm_binary_unwrap(), + Some(ref wat) => { + wasm = wat::parse_str(wat).expect("wat parsing failed"); + &wasm + } + }; + + RuntimeBlob::uncompress_if_needed(wasm) + .expect("failed to create a runtime blob out of test runtime") + }; + + let config = crate::Config { + allow_missing_func_imports: true, + cache_path: None, + semantics: crate::Semantics { + instantiation_strategy: self.instantiation_strategy, + deterministic_stack_limit: match self.deterministic_stack { + true => Some(crate::DeterministicStackLimit { + logical_max: 65536, + native_stack_max: 256 * 1024 * 1024, + }), + false => None, + }, + canonicalize_nans: self.canonicalize_nans, + parallel_compilation: true, + heap_alloc_strategy: self.heap_pages, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, + }, + }; + + if self.precompile_runtime { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("runtime.bin"); + + // Delay the removal of the temporary directory until we're dropped. + self.tmpdir = Some(dir); + + let artifact = crate::prepare_runtime_artifact(blob, &config.semantics).unwrap(); + std::fs::write(&path, artifact).unwrap(); + unsafe { crate::create_runtime_from_artifact::(&path, config) } + } else { + crate::create_runtime::(blob, config) + } + .expect("cannot create runtime") + } +} + +fn deep_call_stack_wat(depth: usize) -> String { + format!( + r#" + (module + (memory $0 32) + (export "memory" (memory $0)) + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "overflow") call 0) + + (func $overflow (param $0 i32) + (block $label$1 + (br_if $label$1 + (i32.ge_u + (local.get $0) + (i32.const {depth}) + ) + ) + (call $overflow + (i32.add + (local.get $0) + (i32.const 1) + ) + ) + ) + ) + + (func (export "main") + (param i32 i32) (result i64) + (call $overflow (i32.const 0)) + (i64.const 0) + ) + ) + "# + ) +} + +// These two tests ensure that the `wasmtime`'s stack size limit and the amount of +// stack space used by a single stack frame doesn't suddenly change without us noticing. +// +// If they do (e.g. because we've pulled in a new version of `wasmtime`) we want to know +// that it did, regardless of how small the change was. +// +// If these tests starting failing it doesn't necessarily mean that something is broken; +// what it means is that one (or multiple) of the following has to be done: +// a) the tests may need to be updated for the new call depth, +// b) the stack limit may need to be changed to maintain backwards compatibility, +// c) the root cause of the new call depth limit determined, and potentially fixed, +// d) the new call depth limit may need to be validated to ensure it doesn't prevent any +// existing chain from syncing (if it was effectively decreased) + +// We need two limits here since depending on whether the code is compiled in debug +// or in release mode the maximum call depth is slightly different. +const CALL_DEPTH_LOWER_LIMIT: usize = 65_455; +const CALL_DEPTH_UPPER_LIMIT: usize = 65_509; + +test_wasm_execution!(test_consume_under_1mb_of_stack_does_not_trap); +fn test_consume_under_1mb_of_stack_does_not_trap(instantiation_strategy: InstantiationStrategy) { + let wat = deep_call_stack_wat(CALL_DEPTH_LOWER_LIMIT); + let mut builder = RuntimeBuilder::new(instantiation_strategy).use_wat(wat); + let runtime = builder.build(); + let mut instance = runtime + .new_instance() + .expect("failed to instantiate a runtime"); + instance.call_export("main", &[]).unwrap(); +} + +test_wasm_execution!(test_consume_over_1mb_of_stack_does_trap); +fn test_consume_over_1mb_of_stack_does_trap(instantiation_strategy: InstantiationStrategy) { + let wat = deep_call_stack_wat(CALL_DEPTH_UPPER_LIMIT + 1); + let mut builder = RuntimeBuilder::new(instantiation_strategy).use_wat(wat); + let runtime = builder.build(); + let mut instance = runtime + .new_instance() + .expect("failed to instantiate a runtime"); + match instance.call_export("main", &[]).unwrap_err() { + Error::AbortedDueToTrap(error) => { + let expected = "wasm trap: call stack exhausted"; + assert_eq!(error.message, expected); + } + error => panic!("unexpected error: {:?}", error), + } +} + +test_wasm_execution!(test_nan_canonicalization); +fn test_nan_canonicalization(instantiation_strategy: InstantiationStrategy) { + let mut builder = RuntimeBuilder::new(instantiation_strategy).canonicalize_nans(true); + let runtime = builder.build(); + + let mut instance = runtime + .new_instance() + .expect("failed to instantiate a runtime"); + + /// A NaN with canonical payload bits. + const CANONICAL_NAN_BITS: u32 = 0x7fc00000; + /// A NaN value with an arbitrary payload. + const ARBITRARY_NAN_BITS: u32 = 0x7f812345; + + // This test works like this: we essentially do + // + // a + b + // + // where + // + // * a is a nan with arbitrary bits in its payload + // * b is 1. + // + // according to the wasm spec, if one of the inputs to the operation is a non-canonical NaN + // then the value be a NaN with non-deterministic payload bits. + // + // However, with the `canonicalize_nans` option turned on above, we expect that the output will + // be a canonical NaN. + // + // We extrapolate the results of this tests so that we assume that all intermediate computations + // that involve floats are sanitized and cannot produce a non-deterministic NaN. + + let params = (u32::to_le_bytes(ARBITRARY_NAN_BITS), u32::to_le_bytes(1)).encode(); + let res = { + let raw_result = instance.call_export("test_fp_f32add", ¶ms).unwrap(); + u32::from_le_bytes(<[u8; 4]>::decode(&mut &raw_result[..]).unwrap()) + }; + assert_eq!(res, CANONICAL_NAN_BITS); +} + +test_wasm_execution!(test_stack_depth_reaching); +fn test_stack_depth_reaching(instantiation_strategy: InstantiationStrategy) { + const TEST_GUARD_PAGE_SKIP: &str = include_str!("test-guard-page-skip.wat"); + + let mut builder = RuntimeBuilder::new(instantiation_strategy) + .use_wat(TEST_GUARD_PAGE_SKIP.to_string()) + .deterministic_stack(true); + + let runtime = builder.build(); + let mut instance = runtime + .new_instance() + .expect("failed to instantiate a runtime"); + + match instance.call_export("test-many-locals", &[]).unwrap_err() { + Error::AbortedDueToTrap(error) => { + let expected = "wasm trap: wasm `unreachable` instruction executed"; + assert_eq!(error.message, expected); + } + error => panic!("unexpected error: {:?}", error), + } +} + +test_wasm_execution!(test_max_memory_pages_imported_memory_without_precompilation); +fn test_max_memory_pages_imported_memory_without_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, true, false); +} + +test_wasm_execution!(test_max_memory_pages_exported_memory_without_precompilation); +fn test_max_memory_pages_exported_memory_without_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, false, false); +} + +test_wasm_execution!(test_max_memory_pages_imported_memory_with_precompilation); +fn test_max_memory_pages_imported_memory_with_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, true, true); +} + +test_wasm_execution!(test_max_memory_pages_exported_memory_with_precompilation); +fn test_max_memory_pages_exported_memory_with_precompilation( + instantiation_strategy: InstantiationStrategy, +) { + test_max_memory_pages(instantiation_strategy, false, true); +} + +fn test_max_memory_pages( + instantiation_strategy: InstantiationStrategy, + import_memory: bool, + precompile_runtime: bool, +) { + fn call( + heap_alloc_strategy: HeapAllocStrategy, + wat: String, + instantiation_strategy: InstantiationStrategy, + precompile_runtime: bool, + ) -> Result<(), Box> { + let mut builder = RuntimeBuilder::new(instantiation_strategy) + .use_wat(wat) + .heap_alloc_strategy(heap_alloc_strategy) + .precompile_runtime(precompile_runtime); + + let runtime = builder.build(); + let mut instance = runtime.new_instance().unwrap(); + let _ = instance.call_export("main", &[])?; + Ok(()) + } + + fn memory(initial: u32, maximum: u32, import: bool) -> String { + let memory = format!("(memory $0 {} {})", initial, maximum); + + if import { + format!("(import \"env\" \"memory\" {})", memory) + } else { + format!("{}\n(export \"memory\" (memory $0))", memory) + } + } + + let assert_grow_ok = |alloc_strategy: HeapAllocStrategy, initial_pages: u32, max_pages: u32| { + eprintln!("assert_grow_ok({alloc_strategy:?}, {initial_pages}, {max_pages})"); + + call( + alloc_strategy, + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + + ;; assert(memory.grow returns != -1) + (if + (i32.eq + (memory.grow + (i32.const 1) + ) + (i32.const -1) + ) + (then + (unreachable) + ) + ) + + (i64.const 0) + ) + ) + "#, + memory(initial_pages, max_pages, import_memory) + ), + instantiation_strategy, + precompile_runtime, + ) + .unwrap() + }; + + let assert_grow_fail = + |alloc_strategy: HeapAllocStrategy, initial_pages: u32, max_pages: u32| { + eprintln!("assert_grow_fail({alloc_strategy:?}, {initial_pages}, {max_pages})"); + + call( + alloc_strategy, + format!( + r#" + (module + {} + (global (export "__heap_base") i32 (i32.const 0)) + (func (export "main") + (param i32 i32) (result i64) + + ;; assert(memory.grow returns == -1) + (if + (i32.ne + (memory.grow + (i32.const 1) + ) + (i32.const -1) + ) + (then + (unreachable) + ) + ) + + (i64.const 0) + ) + ) + "#, + memory(initial_pages, max_pages, import_memory) + ), + instantiation_strategy, + precompile_runtime, + ) + .unwrap() + }; + + assert_grow_ok( + HeapAllocStrategy::Dynamic { + maximum_pages: Some(10), + }, + 1, + 10, + ); + assert_grow_ok( + HeapAllocStrategy::Dynamic { + maximum_pages: Some(10), + }, + 9, + 10, + ); + assert_grow_fail( + HeapAllocStrategy::Dynamic { + maximum_pages: Some(10), + }, + 10, + 10, + ); + + assert_grow_ok( + HeapAllocStrategy::Dynamic { + maximum_pages: None, + }, + 1, + 10, + ); + assert_grow_ok( + HeapAllocStrategy::Dynamic { + maximum_pages: None, + }, + 9, + 10, + ); + assert_grow_ok( + HeapAllocStrategy::Dynamic { + maximum_pages: None, + }, + 10, + 10, + ); + + assert_grow_fail(HeapAllocStrategy::Static { extra_pages: 10 }, 1, 10); + assert_grow_fail(HeapAllocStrategy::Static { extra_pages: 10 }, 9, 10); + assert_grow_fail(HeapAllocStrategy::Static { extra_pages: 10 }, 10, 10); +} + +// This test takes quite a while to execute in a debug build (over 6 minutes on a TR 3970x) +// so it's ignored by default unless it was compiled with `--release`. +#[cfg_attr(build_type = "debug", ignore)] +#[test] +fn test_instances_without_reuse_are_not_leaked() { + let runtime = crate::create_runtime::( + RuntimeBlob::uncompress_if_needed(wasm_binary_unwrap()).unwrap(), + crate::Config { + allow_missing_func_imports: true, + cache_path: None, + semantics: crate::Semantics { + instantiation_strategy: InstantiationStrategy::RecreateInstance, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + heap_alloc_strategy: DEFAULT_HEAP_ALLOC_STRATEGY, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, + }, + }, + ) + .unwrap(); + + // As long as the `wasmtime`'s `Store` lives the instances spawned through it + // will live indefinitely. Currently it has a maximum limit of 10k instances, + // so let's spawn 10k + 1 of them to make sure our code doesn't keep the `Store` + // alive longer than it is necessary. (And since we disabled instance reuse + // a new instance will be spawned on each call.) + let mut instance = runtime.new_instance().unwrap(); + for _ in 0..10001 { + instance.call_export("test_empty_return", &[0]).unwrap(); + } +} + +#[test] +fn test_rustix_version_matches_with_wasmtime() { + let metadata = cargo_metadata::MetadataCommand::new().exec().unwrap(); + + let wasmtime_rustix = metadata + .packages + .iter() + .find(|pkg| pkg.name.as_ref() == "wasmtime") + .unwrap() + .dependencies + .iter() + .find(|dep| dep.name == "rustix") + .unwrap(); + let our_rustix = metadata + .packages + .iter() + .find(|pkg| pkg.name.as_ref() == "sc-executor-wasmtime") + .unwrap() + .dependencies + .iter() + .find(|dep| dep.name == "rustix") + .unwrap(); + + if wasmtime_rustix.req != our_rustix.req { + panic!( + "our version of rustix ({0}) doesn't match wasmtime's ({1}); \ + bump the version in `sc-executor-wasmtime`'s `Cargo.toml' to '{1}' and try again", + our_rustix.req, wasmtime_rustix.req, + ); + } +} diff --git a/substrate/runtime-executor/wasmtime/src/util.rs b/substrate/runtime-executor/wasmtime/src/util.rs new file mode 100644 index 00000000000..b2f08ac7db9 --- /dev/null +++ b/substrate/runtime-executor/wasmtime/src/util.rs @@ -0,0 +1,220 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use crate::{InstantiationStrategy, memory_wrapper::MemoryWrapper, store_data::StoreData}; +use sc_executor_common::error::{Error, Result}; +use sp_wasm_interface::{Pointer, Value, WordSize}; +use std::ops::Range; +use wasmtime::{AsContext, AsContextMut}; + +/// Converts a [`wasmtime::Val`] into a substrate runtime interface [`Value`]. +/// +/// Panics if the given value doesn't have a corresponding variant in `Value`. +pub fn from_wasmtime_val(val: wasmtime::Val) -> Value { + match val { + wasmtime::Val::I32(v) => Value::I32(v), + wasmtime::Val::I64(v) => Value::I64(v), + wasmtime::Val::F32(f_bits) => Value::F32(f_bits), + wasmtime::Val::F64(f_bits) => Value::F64(f_bits), + v => panic!("Given value type is unsupported by Substrate: {:?}", v), + } +} + +/// Converts a sp_wasm_interface's [`Value`] into the corresponding variant in wasmtime's +/// [`wasmtime::Val`]. +pub fn into_wasmtime_val(value: Value) -> wasmtime::Val { + match value { + Value::I32(v) => wasmtime::Val::I32(v), + Value::I64(v) => wasmtime::Val::I64(v), + Value::F32(f_bits) => wasmtime::Val::F32(f_bits), + Value::F64(f_bits) => wasmtime::Val::F64(f_bits), + } +} + +pub(crate) fn checked_range(offset: usize, len: usize, max: usize) -> Option> { + let end = offset.checked_add(len)?; + (end <= max).then_some(offset..end) +} + +/// Read data from the instance memory into a slice. +/// +/// Returns an error if the read would go out of the memory bounds. +pub fn read_memory_into( + ctx: impl AsContext, + address: Pointer, + dest: &mut [u8], +) -> Result<()> { + let memory = ctx.as_context().data().memory().data(&ctx); + + let range = checked_range(address.into(), dest.len(), memory.len()) + .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?; + dest.copy_from_slice(&memory[range]); + Ok(()) +} + +/// Write data to the instance memory from a slice. +/// +/// Returns an error if the write would go out of the memory bounds. +pub fn write_memory_from( + mut ctx: impl AsContextMut, + address: Pointer, + data: &[u8], +) -> Result<()> { + let memory = ctx.as_context().data().memory(); + let memory = memory.data_mut(&mut ctx); + + let range = checked_range(address.into(), data.len(), memory.len()) + .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?; + memory[range].copy_from_slice(data); + Ok(()) +} + +pub fn allocate_memory( + caller: &mut wasmtime::Caller<'_, StoreData>, + size: WordSize, +) -> Result> { + let mut allocator = caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .allocator + .take() + .expect("allocator is not empty when calling a function in wasm; qed"); + + let memory = caller.data().memory(); + let result = allocator + .allocate( + &mut MemoryWrapper::from((&memory, &mut caller.as_context_mut())), + size, + ) + .map_err(|error: sp_allocator::Error| Error::Other(error.to_string())); + + caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .allocator = Some(allocator); + + result +} + +pub fn deallocate_memory( + caller: &mut wasmtime::Caller<'_, StoreData>, + ptr: Pointer, +) -> Result<()> { + let mut allocator = caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .allocator + .take() + .expect("allocator is not empty when calling a function in wasm; qed"); + + let memory = caller.data().memory(); + let result = allocator + .deallocate( + &mut MemoryWrapper::from((&memory, &mut caller.as_context_mut())), + ptr, + ) + .map_err(|error: sp_allocator::Error| Error::Other(error.to_string())); + + caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") + .allocator = Some(allocator); + + result +} + +/// Checks whether the `madvise(MADV_DONTNEED)` works as expected. +/// +/// In certain environments (e.g. when running under the QEMU user-mode emulator) +/// this syscall is broken. +#[cfg(target_os = "linux")] +fn is_madvise_working() -> std::result::Result { + let page_size = rustix::param::page_size(); + + unsafe { + // Allocate two memory pages. + let pointer = rustix::mm::mmap_anonymous( + std::ptr::null_mut(), + 2 * page_size, + rustix::mm::ProtFlags::READ | rustix::mm::ProtFlags::WRITE, + rustix::mm::MapFlags::PRIVATE, + ) + .map_err(|error| format!("mmap failed: {}", error))?; + + // Dirty them both. + std::ptr::write_volatile(pointer.cast::(), b'A'); + std::ptr::write_volatile(pointer.cast::().add(page_size), b'B'); + + // Clear the first page. + let result_madvise = + rustix::mm::madvise(pointer, page_size, rustix::mm::Advice::LinuxDontNeed) + .map_err(|error| format!("madvise failed: {}", error)); + + // Fetch the values. + let value_1 = std::ptr::read_volatile(pointer.cast::()); + let value_2 = std::ptr::read_volatile(pointer.cast::().add(page_size)); + + let result_munmap = rustix::mm::munmap(pointer, 2 * page_size) + .map_err(|error| format!("munmap failed: {}", error)); + + result_madvise?; + result_munmap?; + + // Verify that the first page was cleared, while the second one was not. + Ok(value_1 == 0 && value_2 == b'B') + } +} + +#[cfg(test)] +#[cfg(target_os = "linux")] +#[test] +fn test_is_madvise_working_check_does_not_fail() { + assert!(is_madvise_working().is_ok()); +} + +/// Checks whether a given instantiation strategy can be safely used, and replaces +/// it with a slower (but sound) alternative if it isn't. +#[cfg(target_os = "linux")] +pub(crate) fn replace_strategy_if_broken(strategy: &mut InstantiationStrategy) { + let replacement_strategy = match *strategy { + // These strategies don't need working `madvise`. + InstantiationStrategy::Pooling | InstantiationStrategy::RecreateInstance => return, + + // These strategies require a working `madvise` to be sound. + InstantiationStrategy::PoolingCopyOnWrite => InstantiationStrategy::Pooling, + InstantiationStrategy::RecreateInstanceCopyOnWrite => { + InstantiationStrategy::RecreateInstance + } + }; + + use std::sync::OnceLock; + static IS_OK: OnceLock = OnceLock::new(); + + let is_ok = IS_OK.get_or_init(|| { + let is_ok = match is_madvise_working() { + Ok(is_ok) => is_ok, + Err(error) => { + // This should never happen. + log::warn!("Failed to check whether `madvise(MADV_DONTNEED)` works: {}", error); + false + } + }; + + if !is_ok { + log::warn!("You're running on a system with a broken `madvise(MADV_DONTNEED)` implementation. This will result in lower performance."); + } + + is_ok + }); + + if !is_ok { + *strategy = replacement_strategy; + } +} + +#[cfg(not(target_os = "linux"))] +pub(crate) fn replace_strategy_if_broken(_: &mut InstantiationStrategy) {} diff --git a/substrate/sc-mixnet/Cargo.toml b/substrate/sc-mixnet/Cargo.toml new file mode 100644 index 00000000000..7200e77de22 --- /dev/null +++ b/substrate/sc-mixnet/Cargo.toml @@ -0,0 +1,49 @@ +[package] +description = "Substrate mixnet service" +name = "sc-mixnet" +version = "0.15.0" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage.workspace = true +repository = "https://github.com/paritytech/substrate/" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +array-bytes = { workspace = true, default-features = true } +arrayvec = { workspace = true } +blake2 = { workspace = true, default-features = true } +bytes = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +log = { workspace = true, default-features = true } +mixnet = { workspace = true } +parking_lot = { workspace = true, default-features = true } +sc-client-api.workspace = true +sc-client-api.default-features = true +sc-network.workspace = true +sc-network.default-features = true +sc-network-types.workspace = true +sc-network-types.default-features = true +sc-transaction-pool-api.workspace = true +sc-transaction-pool-api.default-features = true +sp-api.workspace = true +sp-api.default-features = true +sp-consensus.workspace = true +sp-consensus.default-features = true +sp-core.workspace = true +sp-core.default-features = true +sp-keystore.workspace = true +sp-keystore.default-features = true +sp-mixnet.workspace = true +sp-mixnet.default-features = true +sp-runtime.workspace = true +sp-runtime.default-features = true +thiserror = { workspace = true } diff --git a/substrate/sc-mixnet/README.md b/substrate/sc-mixnet/README.md new file mode 100644 index 00000000000..c43a0d7f17b --- /dev/null +++ b/substrate/sc-mixnet/README.md @@ -0,0 +1,8 @@ +Substrate mixnet service. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0 + + +## Release + +Polkadot SDK stable2409 diff --git a/substrate/sc-mixnet/src/api.rs b/substrate/sc-mixnet/src/api.rs new file mode 100644 index 00000000000..0bffe649ffb --- /dev/null +++ b/substrate/sc-mixnet/src/api.rs @@ -0,0 +1,61 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use super::{config::Config, error::Error, request::Request}; +use futures::{ + channel::{mpsc, oneshot}, + SinkExt, +}; +use sp_core::Bytes; +use std::future::Future; + +/// The other end of an [`Api`]. This should be passed to [`run`](super::run::run). +pub struct ApiBackend { + pub(super) request_receiver: mpsc::Receiver, +} + +/// Interface to the mixnet service. +#[derive(Clone)] +pub struct Api { + request_sender: mpsc::Sender, +} + +impl Api { + /// Create a new `Api`. The [`ApiBackend`] should be passed to [`run`](super::run::run). + pub fn new(config: &Config) -> (Self, ApiBackend) { + let (request_sender, request_receiver) = mpsc::channel(config.substrate.request_buffer); + (Self { request_sender }, ApiBackend { request_receiver }) + } + + /// Submit an extrinsic via the mixnet. + /// + /// Returns a [`Future`] which returns another `Future`. + /// + /// The first `Future` resolves as soon as there is space in the mixnet service queue. The + /// second `Future` resolves once a reply is received over the mixnet (or sooner if there is an + /// error). + /// + /// The first `Future` references `self`, but the second does not. This makes it possible to + /// submit concurrent mixnet requests using a single `Api` instance. + pub async fn submit_extrinsic( + &mut self, + extrinsic: Bytes, + ) -> impl Future> { + let (reply_sender, reply_receiver) = oneshot::channel(); + let res = self + .request_sender + .feed(Request::SubmitExtrinsic { + extrinsic, + reply_sender, + }) + .await; + async move { + res.map_err(|_| Error::ServiceUnavailable)?; + reply_receiver + .await + .map_err(|_| Error::ServiceUnavailable)? + } + } +} diff --git a/substrate/sc-mixnet/src/config.rs b/substrate/sc-mixnet/src/config.rs new file mode 100644 index 00000000000..5e2941dba1f --- /dev/null +++ b/substrate/sc-mixnet/src/config.rs @@ -0,0 +1,75 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +pub use mixnet::core::Config as CoreConfig; +use std::time::Duration; + +/// Substrate-specific mixnet configuration. +#[derive(Clone, Debug)] +pub struct SubstrateConfig { + /// Attempt to register the local node as a mixnode? + pub register: bool, + /// Maximum number of incoming mixnet connections to accept from non-mixnodes. If the local + /// node will never be a mixnode, this can be set to 0. + pub num_gateway_slots: u32, + + /// Number of requests to the mixnet service that can be buffered, in addition to the one per + /// [`Api`](super::api::Api) instance. Note that this does not include requests that are being + /// actively handled. + pub request_buffer: usize, + /// Used to determine the number of SURBs to include in request messages: the maximum number of + /// SURBs needed for a single reply is multiplied by this. This should not be set to 0. + pub surb_factor: usize, + + /// Maximum number of submit extrinsic requests waiting for their delay to elapse. When at the + /// limit, any submit extrinsic requests that arrive will simply be dropped. + pub extrinsic_queue_capacity: usize, + /// Mean delay between receiving a submit extrinsic request and actually submitting the + /// extrinsic. This should really be the same for all nodes! + pub mean_extrinsic_delay: Duration, + /// Maximum number of extrinsics being actively submitted. If a submit extrinsic request's + /// delay elapses and we are already at this limit, the request will simply be dropped. + pub max_pending_extrinsics: usize, +} + +impl Default for SubstrateConfig { + fn default() -> Self { + Self { + register: true, + num_gateway_slots: 150, + + request_buffer: 4, + surb_factor: 2, + + extrinsic_queue_capacity: 50, + mean_extrinsic_delay: Duration::from_secs(1), + max_pending_extrinsics: 20, + } + } +} + +/// Mixnet configuration. +#[derive(Clone, Debug)] +pub struct Config { + /// Core configuration. + pub core: CoreConfig, + /// Request manager configuration. + pub request_manager: mixnet::request_manager::Config, + /// Reply manager configuration. + pub reply_manager: mixnet::reply_manager::Config, + /// Substrate-specific configuration. + pub substrate: SubstrateConfig, +} + +impl Default for Config { + fn default() -> Self { + Self { + core: Default::default(), + request_manager: Default::default(), + reply_manager: Default::default(), + substrate: Default::default(), + } + } +} diff --git a/substrate/sc-mixnet/src/error.rs b/substrate/sc-mixnet/src/error.rs new file mode 100644 index 00000000000..5c4d9ab7d5f --- /dev/null +++ b/substrate/sc-mixnet/src/error.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use codec::{Decode, Encode}; +use mixnet::core::PostErr; + +/// Error handling a request. Sent in replies over the mixnet. +#[derive(Debug, thiserror::Error, Decode, Encode)] +pub enum RemoteErr { + /// An error that doesn't map to any of the other variants. + #[error("{0}")] + Other(String), + /// Failed to decode the request. + #[error("Failed to decode the request: {0}")] + Decode(String), +} + +/// Mixnet error. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Failed to communicate with the mixnet service. Possibly it panicked. The node probably + /// needs to be restarted. + #[error( + "Failed to communicate with the mixnet service; the node probably needs to be restarted" + )] + ServiceUnavailable, + /// Did not receive a reply after the configured number of attempts. + #[error("Did not receive a reply from the mixnet after the configured number of attempts")] + NoReply, + /// Received a malformed reply. + #[error("Received a malformed reply from the mixnet")] + BadReply, + /// Failed to post the request to the mixnet. Note that some [`PostErr`] variants, eg + /// [`PostErr::NotEnoughSpaceInQueue`], are handled internally and will never be returned from + /// the top-level API. + #[error("Failed to post the request to the mixnet: {0}")] + Post(#[from] PostErr), + /// Error reported by destination mixnode. + #[error("Error reported by the destination mixnode: {0}")] + Remote(#[from] RemoteErr), +} diff --git a/substrate/sc-mixnet/src/extrinsic_queue.rs b/substrate/sc-mixnet/src/extrinsic_queue.rs new file mode 100644 index 00000000000..c39d8ca6d4f --- /dev/null +++ b/substrate/sc-mixnet/src/extrinsic_queue.rs @@ -0,0 +1,91 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! [`ExtrinsicQueue`] is a queue for extrinsics received from the mixnet. These extrinsics are +//! explicitly delayed by a random amount, to decorrelate the times at which they are received from +//! the times at which they are broadcast to peers. + +use mixnet::reply_manager::ReplyContext; +use std::{cmp::Ordering, collections::BinaryHeap, time::Instant}; + +/// An extrinsic that should be submitted to the transaction pool after `deadline`. `Eq` and `Ord` +/// are implemented for this to support use in `BinaryHeap`s. Only `deadline` is compared. +struct DelayedExtrinsic { + /// When the extrinsic should actually be submitted to the pool. + deadline: Instant, + extrinsic: E, + reply_context: ReplyContext, +} + +impl PartialEq for DelayedExtrinsic { + fn eq(&self, other: &Self) -> bool { + self.deadline == other.deadline + } +} + +impl Eq for DelayedExtrinsic {} + +impl PartialOrd for DelayedExtrinsic { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for DelayedExtrinsic { + fn cmp(&self, other: &Self) -> Ordering { + // Extrinsics with the earliest deadline considered greatest + self.deadline.cmp(&other.deadline).reverse() + } +} + +pub struct ExtrinsicQueue { + capacity: usize, + queue: BinaryHeap>, + next_deadline_changed: bool, +} + +impl ExtrinsicQueue { + pub fn new(capacity: usize) -> Self { + Self { + capacity, + queue: BinaryHeap::with_capacity(capacity), + next_deadline_changed: false, + } + } + + pub fn next_deadline(&self) -> Option { + self.queue.peek().map(|extrinsic| extrinsic.deadline) + } + + pub fn next_deadline_changed(&mut self) -> bool { + let changed = self.next_deadline_changed; + self.next_deadline_changed = false; + changed + } + + pub fn has_space(&self) -> bool { + self.queue.len() < self.capacity + } + + pub fn insert(&mut self, deadline: Instant, extrinsic: E, reply_context: ReplyContext) { + debug_assert!(self.has_space()); + let prev_deadline = self.next_deadline(); + self.queue.push(DelayedExtrinsic { + deadline, + extrinsic, + reply_context, + }); + if self.next_deadline() != prev_deadline { + self.next_deadline_changed = true; + } + } + + pub fn pop(&mut self) -> Option<(E, ReplyContext)> { + self.next_deadline_changed = true; + self.queue + .pop() + .map(|extrinsic| (extrinsic.extrinsic, extrinsic.reply_context)) + } +} diff --git a/substrate/sc-mixnet/src/lib.rs b/substrate/sc-mixnet/src/lib.rs new file mode 100644 index 00000000000..0edf40e1906 --- /dev/null +++ b/substrate/sc-mixnet/src/lib.rs @@ -0,0 +1,36 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Substrate mixnet service. This implements the [Substrate Mix Network +//! Specification](https://paritytech.github.io/mixnet-spec/). + +#![warn(missing_docs)] +#![forbid(unsafe_code)] +#![allow( + clippy::borrowed_box, + clippy::derivable_impls, + clippy::too_many_arguments +)] + +mod api; +mod config; +mod error; +mod extrinsic_queue; +mod maybe_inf_delay; +mod packet_dispatcher; +mod peer_id; +mod protocol; +mod request; +mod run; +mod sync_with_runtime; + +pub use self::{ + api::{Api, ApiBackend}, + config::{Config, CoreConfig, SubstrateConfig}, + error::{Error, RemoteErr}, + protocol::{peers_set_config, protocol_name}, + run::run, +}; +pub use mixnet::core::{KxSecret, PostErr, TopologyErr}; diff --git a/substrate/sc-mixnet/src/maybe_inf_delay.rs b/substrate/sc-mixnet/src/maybe_inf_delay.rs new file mode 100644 index 00000000000..895a713bba9 --- /dev/null +++ b/substrate/sc-mixnet/src/maybe_inf_delay.rs @@ -0,0 +1,108 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use futures::{future::FusedFuture, FutureExt}; +use futures_timer::Delay; +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll, Waker}, + time::Duration, +}; + +enum Inner { + Infinite { + /// Waker from the most recent `poll` call. If `None`, either `poll` has not been called + /// yet, we returned `Poll::Ready` from the last call, or the waker is attached to `delay`. + waker: Option, + delay: Option, + }, + Finite(Delay), +} + +/// Like [`Delay`] but the duration can be infinite (in which case the future will never fire). +/// Unlike [`Delay`], implements [`FusedFuture`], with [`is_terminated`](Self::is_terminated) +/// returning `true` when the delay is infinite. As with [`Delay`], once [`poll`](Self::poll) +/// returns [`Poll::Ready`], it will continue to do so until [`reset`](Self::reset) is called. +pub struct MaybeInfDelay(Inner); + +impl MaybeInfDelay { + /// Create a new `MaybeInfDelay` future. If `duration` is [`Some`], the future will fire after + /// the given duration has elapsed. If `duration` is [`None`], the future will "never" fire + /// (although see [`reset`](Self::reset)). + pub fn new(duration: Option) -> Self { + match duration { + Some(duration) => Self(Inner::Finite(Delay::new(duration))), + None => Self(Inner::Infinite { + waker: None, + delay: None, + }), + } + } + + /// Reset the timer. `duration` is handled just like in [`new`](Self::new). Note that while + /// this is similar to `std::mem::replace(&mut self, MaybeInfDelay::new(duration))`, with + /// `replace` you would have to manually ensure [`poll`](Self::poll) was called again; with + /// `reset` this is not necessary. + pub fn reset(&mut self, duration: Option) { + match duration { + Some(duration) => match &mut self.0 { + Inner::Infinite { waker, delay } => { + let mut delay = match delay.take() { + Some(mut delay) => { + delay.reset(duration); + delay + } + None => Delay::new(duration), + }; + if let Some(waker) = waker.take() { + let mut cx = Context::from_waker(&waker); + match delay.poll_unpin(&mut cx) { + Poll::Pending => (), // Waker attached to delay + Poll::Ready(_) => waker.wake(), + } + } + self.0 = Inner::Finite(delay); + } + Inner::Finite(delay) => delay.reset(duration), + }, + None => { + self.0 = match std::mem::replace( + &mut self.0, + Inner::Infinite { + waker: None, + delay: None, + }, + ) { + Inner::Finite(delay) => Inner::Infinite { + waker: None, + delay: Some(delay), + }, + infinite => infinite, + } + } + } + } +} + +impl Future for MaybeInfDelay { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match &mut self.0 { + Inner::Infinite { waker, .. } => { + *waker = Some(cx.waker().clone()); + Poll::Pending + } + Inner::Finite(delay) => delay.poll_unpin(cx), + } + } +} + +impl FusedFuture for MaybeInfDelay { + fn is_terminated(&self) -> bool { + matches!(self.0, Inner::Infinite { .. }) + } +} diff --git a/substrate/sc-mixnet/src/packet_dispatcher.rs b/substrate/sc-mixnet/src/packet_dispatcher.rs new file mode 100644 index 00000000000..3416e4dc2ee --- /dev/null +++ b/substrate/sc-mixnet/src/packet_dispatcher.rs @@ -0,0 +1,194 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! [`AddressedPacket`] dispatching. + +use super::peer_id::{from_core_peer_id, to_core_peer_id}; +use arrayvec::ArrayVec; +use log::{debug, warn}; +use mixnet::core::{AddressedPacket, NetworkStatus, Packet, PeerId as CorePeerId}; +use parking_lot::Mutex; +use sc_network::NotificationService; +use sc_network_types::PeerId; +use std::{collections::HashMap, future::Future, sync::Arc}; + +const LOG_TARGET: &str = "mixnet"; + +/// Packet queue for a peer. +/// +/// Ideally we would use `Rc>`, but that would prevent the top-level future from being +/// automatically marked `Send`. I believe it would be safe to manually mark it `Send`, but using +/// `Arc>` here is not really a big deal. +struct PeerQueue(Mutex, 2>>); + +impl PeerQueue { + fn new() -> Self { + Self(Mutex::new(ArrayVec::new())) + } + + /// Push `packet` onto the queue. Returns `true` if the queue was previously empty. Fails if + /// the queue is full. + fn push(&self, packet: Box) -> Result { + let mut queue = self.0.lock(); + if queue.is_full() { + Err(()) + } else { + let was_empty = queue.is_empty(); + queue.push(packet); + Ok(was_empty) + } + } + + /// Drop all packets from the queue. + fn clear(&self) { + let mut queue = self.0.lock(); + queue.clear(); + } + + /// Pop the packet at the head of the queue and return it, or, if the queue is empty, return + /// `None`. Also returns `true` if there are more packets in the queue. + fn pop(&self) -> (Option>, bool) { + let mut queue = self.0.lock(); + let packet = queue.pop(); + (packet, !queue.is_empty()) + } +} + +/// A peer which has packets ready to send but is not currently being serviced. +pub struct ReadyPeer { + id: PeerId, + /// The peer's packet queue. Not empty. + queue: Arc, +} + +impl ReadyPeer { + /// If a future is returned, and if that future returns `Some`, this function should be + /// called again to send the next packet queued for the peer; `self` is placed in the `Some` + /// to make this straightforward. Otherwise, we have either sent or dropped all packets + /// queued for the peer, and it can be forgotten about for the time being. + pub fn send_packet( + self, + notification_service: &Box, + ) -> Option>> { + match notification_service.message_sink(&self.id) { + None => { + debug!( + target: LOG_TARGET, + "Failed to get message sink for peer ID {}", self.id, + ); + self.queue.clear(); + None + } + Some(sink) => Some(async move { + let (packet, more_packets) = self.queue.pop(); + let packet = packet.expect("Should only be called if there is a packet to send"); + + match sink + .send_async_notification((packet as Box<[_]>).into()) + .await + { + Ok(_) => more_packets.then_some(self), + Err(err) => { + debug!( + target: LOG_TARGET, + "Failed to send packet to peer ID {}: {err}", self.id, + ); + self.queue.clear(); + None + } + } + }), + } + } +} + +pub struct PacketDispatcher { + /// Peer ID of the local node. Only used to implement [`NetworkStatus`]. + local_peer_id: CorePeerId, + /// Packet queue for each connected peer. These queues are very short and only exist to give + /// packets somewhere to sit while waiting for notification senders to be ready. + peer_queues: HashMap>, +} + +impl PacketDispatcher { + pub fn new(local_peer_id: &CorePeerId) -> Self { + Self { + local_peer_id: *local_peer_id, + peer_queues: HashMap::new(), + } + } + + pub fn add_peer(&mut self, id: &PeerId) { + let Some(core_id) = to_core_peer_id(id) else { + debug!(target: LOG_TARGET, + "Cannot add peer; failed to convert libp2p peer ID {id} to mixnet peer ID"); + return; + }; + if self + .peer_queues + .insert(core_id, Arc::new(PeerQueue::new())) + .is_some() + { + warn!(target: LOG_TARGET, "Two stream opened notifications for peer ID {id}"); + } + } + + pub fn remove_peer(&mut self, id: &PeerId) { + let Some(core_id) = to_core_peer_id(id) else { + debug!(target: LOG_TARGET, + "Cannot remove peer; failed to convert libp2p peer ID {id} to mixnet peer ID"); + return; + }; + if self.peer_queues.remove(&core_id).is_none() { + warn!(target: LOG_TARGET, "Stream closed notification for unknown peer ID {id}"); + } + } + + /// If the peer is not connected or the peer's packet queue is full, the packet is dropped. + /// Otherwise the packet is pushed onto the peer's queue, and if the queue was previously empty + /// a [`ReadyPeer`] is returned. + pub fn dispatch(&mut self, packet: AddressedPacket) -> Option { + let Some(queue) = self.peer_queues.get_mut(&packet.peer_id) else { + debug!(target: LOG_TARGET, "Dropped packet to mixnet peer ID {:x?}; not connected", + packet.peer_id); + return None; + }; + + match queue.push(packet.packet) { + Err(_) => { + debug!( + target: LOG_TARGET, + "Dropped packet to mixnet peer ID {:x?}; peer queue full", packet.peer_id + ); + None + } + Ok(true) => { + // Queue was empty. Construct and return a ReadyPeer. + let Some(id) = from_core_peer_id(&packet.peer_id) else { + debug!(target: LOG_TARGET, "Cannot send packet; \ + failed to convert mixnet peer ID {:x?} to libp2p peer ID", + packet.peer_id); + queue.clear(); + return None; + }; + Some(ReadyPeer { + id, + queue: queue.clone(), + }) + } + Ok(false) => None, // Queue was not empty + } + } +} + +impl NetworkStatus for PacketDispatcher { + fn local_peer_id(&self) -> CorePeerId { + self.local_peer_id + } + + fn is_connected(&self, peer_id: &CorePeerId) -> bool { + self.peer_queues.contains_key(peer_id) + } +} diff --git a/substrate/sc-mixnet/src/peer_id.rs b/substrate/sc-mixnet/src/peer_id.rs new file mode 100644 index 00000000000..dced375265f --- /dev/null +++ b/substrate/sc-mixnet/src/peer_id.rs @@ -0,0 +1,23 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use mixnet::core::PeerId as CorePeerId; +use sc_network_types::PeerId; + +/// Convert a libp2p [`PeerId`] into a mixnet core [`PeerId`](CorePeerId). +/// +/// This will succeed only if `peer_id` is an Ed25519 public key ("hashed" using the identity +/// hasher). Returns `None` on failure. +pub fn to_core_peer_id(peer_id: &PeerId) -> Option { + peer_id.into_ed25519() +} + +/// Convert a mixnet core [`PeerId`](CorePeerId) into a libp2p [`PeerId`]. +/// +/// This will succeed only if `peer_id` represents a point on the Ed25519 curve. Returns `None` on +/// failure. +pub fn from_core_peer_id(core_peer_id: &CorePeerId) -> Option { + PeerId::from_ed25519(core_peer_id) +} diff --git a/substrate/sc-mixnet/src/protocol.rs b/substrate/sc-mixnet/src/protocol.rs new file mode 100644 index 00000000000..7a425aaf07b --- /dev/null +++ b/substrate/sc-mixnet/src/protocol.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use super::config::Config; +use mixnet::core::PACKET_SIZE; +use sc_network::{ + config::{NonReservedPeerMode, SetConfig}, + peer_store::PeerStoreProvider, + service::NotificationMetrics, + NetworkBackend, NotificationService, ProtocolName, +}; +use sp_runtime::traits::Block as BlockT; + +/// Returns the protocol name to use for the mixnet controlled by the given chain. +pub fn protocol_name(genesis_hash: &[u8], fork_id: Option<&str>) -> ProtocolName { + let name = if let Some(fork_id) = fork_id { + format!( + "/{}/{}/mixnet/1", + array_bytes::bytes2hex("", genesis_hash), + fork_id + ) + } else { + format!("/{}/mixnet/1", array_bytes::bytes2hex("", genesis_hash)) + }; + name.into() +} + +/// Returns the peers set configuration for the mixnet protocol. +pub fn peers_set_config::Hash>>( + name: ProtocolName, + config: &Config, + metrics: NotificationMetrics, + peerstore_handle: std::sync::Arc, +) -> ( + Network::NotificationProtocolConfig, + Box, +) { + let set_config = if config.substrate.num_gateway_slots != 0 { + // out_peers is always 0; we are only interested in connecting to mixnodes, which we do by + // setting them as reserved nodes + SetConfig { + in_peers: config.substrate.num_gateway_slots, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Accept, + } + } else { + SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + } + }; + + Network::notification_config( + name, + Vec::new(), + PACKET_SIZE as u64, + None, + set_config, + metrics, + peerstore_handle, + ) +} diff --git a/substrate/sc-mixnet/src/request.rs b/substrate/sc-mixnet/src/request.rs new file mode 100644 index 00000000000..932b253022a --- /dev/null +++ b/substrate/sc-mixnet/src/request.rs @@ -0,0 +1,112 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Sender-side request logic. Some things from this module are also used on the receiver side, eg +//! [`extrinsic_delay`], but most of the receiver-side request logic lives elsewhere. + +use super::{config::SubstrateConfig, error::Error}; +use blake2::{ + digest::{consts::U16, Mac}, + Blake2bMac, +}; +use codec::{Decode, DecodeAll}; +use futures::channel::oneshot; +use log::debug; +use mixnet::core::{Delay, MessageId, PostErr, Scattered}; +use sp_core::Bytes; +use std::time::Duration; + +const LOG_TARGET: &str = "mixnet"; + +fn send_err(reply_sender: oneshot::Sender>, err: Error) { + if let Err(Err(err)) = reply_sender.send(Err(err)) { + debug!(target: LOG_TARGET, "Failed to inform requester of error: {err}"); + } +} + +fn send_reply(reply_sender: oneshot::Sender>, mut data: &[u8]) { + let res = match Result::decode_all(&mut data) { + Ok(res) => res.map_err(Error::Remote), + Err(_) => Err(Error::BadReply), + }; + match reply_sender.send(res) { + Ok(_) => (), + Err(Ok(_)) => debug!(target: LOG_TARGET, "Failed to send reply to requester"), + Err(Err(err)) => debug!(target: LOG_TARGET, "Failed to inform requester of error: {err}"), + } +} + +/// First byte of a submit extrinsic request, identifying it as such. +pub const SUBMIT_EXTRINSIC: u8 = 1; + +const EXTRINSIC_DELAY_PERSONA: &[u8; 16] = b"submit-extrn-dly"; + +/// Returns the artificial delay that should be inserted between receipt of a submit extrinsic +/// request with the given message ID and import of the extrinsic into the local transaction pool. +pub fn extrinsic_delay(message_id: &MessageId, config: &SubstrateConfig) -> Duration { + let h = Blake2bMac::::new_with_salt_and_personal(message_id, b"", EXTRINSIC_DELAY_PERSONA) + .expect("Key, salt, and persona sizes are fixed and small enough"); + let delay = Delay::exp(h.finalize().into_bytes().as_ref()); + delay.to_duration(config.mean_extrinsic_delay) +} + +/// Request parameters and local reply channel. Stored by the +/// [`RequestManager`](mixnet::request_manager::RequestManager). +pub enum Request { + SubmitExtrinsic { + extrinsic: Bytes, + reply_sender: oneshot::Sender>, + }, +} + +impl Request { + /// Forward an error to the user of the mixnet service. + fn send_err(self, err: Error) { + match self { + Request::SubmitExtrinsic { reply_sender, .. } => send_err(reply_sender, err), + } + } + + /// Forward a reply to the user of the mixnet service. + pub fn send_reply(self, data: &[u8]) { + match self { + Request::SubmitExtrinsic { reply_sender, .. } => send_reply(reply_sender, data), + } + } +} + +impl mixnet::request_manager::Request for Request { + type Context = SubstrateConfig; + + fn with_data(&self, f: impl FnOnce(Scattered) -> T, _context: &Self::Context) -> T { + match self { + Request::SubmitExtrinsic { extrinsic, .. } => { + f([&[SUBMIT_EXTRINSIC][..], extrinsic.as_ref()] + .as_slice() + .into()) + } + } + } + + fn num_surbs(&self, context: &Self::Context) -> usize { + match self { + Request::SubmitExtrinsic { .. } => context.surb_factor, + } + } + + fn handling_delay(&self, message_id: &MessageId, context: &Self::Context) -> Duration { + match self { + Request::SubmitExtrinsic { .. } => extrinsic_delay(message_id, context), + } + } + + fn handle_post_err(self, err: PostErr, _context: &Self::Context) { + self.send_err(err.into()); + } + + fn handle_retry_limit_reached(self, _context: &Self::Context) { + self.send_err(Error::NoReply); + } +} diff --git a/substrate/sc-mixnet/src/run.rs b/substrate/sc-mixnet/src/run.rs new file mode 100644 index 00000000000..12ce17b9c2e --- /dev/null +++ b/substrate/sc-mixnet/src/run.rs @@ -0,0 +1,380 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Top-level mixnet service function. + +use super::{ + api::ApiBackend, + config::{Config, SubstrateConfig}, + error::RemoteErr, + extrinsic_queue::ExtrinsicQueue, + maybe_inf_delay::MaybeInfDelay, + packet_dispatcher::PacketDispatcher, + peer_id::to_core_peer_id, + request::{extrinsic_delay, Request, SUBMIT_EXTRINSIC}, + sync_with_runtime::sync_with_runtime, +}; +use bytes::Bytes; +use codec::{Decode, DecodeAll, Encode}; +use futures::{ + future::{pending, Either}, + stream::FuturesUnordered, + FutureExt, StreamExt, +}; +use log::{debug, error, trace, warn}; +use mixnet::{ + core::{Events, Message, Mixnet, Packet}, + reply_manager::{ReplyContext, ReplyManager}, + request_manager::RequestManager, +}; +use sc_client_api::{BlockchainEvents, HeaderBackend}; +use sc_network::{ + service::traits::{NetworkService, NotificationEvent, ValidationResult}, + NetworkPeers, NetworkStateInfo, NotificationService, ProtocolName, +}; +use sc_transaction_pool_api::{ + LocalTransactionPool, OffchainTransactionPoolFactory, TransactionPool, +}; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_consensus::SyncOracle; +use sp_keystore::{KeystoreExt, KeystorePtr}; +use sp_mixnet::{runtime_api::MixnetApi, types::Mixnode}; +use sp_runtime::{ + traits::{Block, Header}, + transaction_validity::TransactionSource, + Saturating, +}; +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; + +const LOG_TARGET: &str = "mixnet"; + +const MIN_BLOCKS_BETWEEN_REGISTRATION_ATTEMPTS: u32 = 3; + +fn complete_submit_extrinsic( + reply_manager: &mut ReplyManager, + reply_context: ReplyContext, + data: Result<(), RemoteErr>, + mixnet: &mut Mixnet, +) { + reply_manager.complete(reply_context, data.encode(), mixnet); +} + +fn handle_packet( + packet: &Packet, + mixnet: &mut Mixnet, + request_manager: &mut RequestManager, + reply_manager: &mut ReplyManager, + extrinsic_queue: &mut ExtrinsicQueue, + config: &SubstrateConfig, +) { + match mixnet.handle_packet(packet) { + Some(Message::Request(message)) => { + let Some((reply_context, data)) = reply_manager.insert(message, mixnet) else { + return; + }; + + match data.as_slice() { + [SUBMIT_EXTRINSIC, encoded_extrinsic @ ..] => { + if !extrinsic_queue.has_space() { + debug!(target: LOG_TARGET, "No space in extrinsic queue; dropping request"); + // We don't send a reply in this case; we want the requester to retry + reply_manager.abandon(reply_context); + return; + } + + // Decode the extrinsic + let mut encoded_extrinsic = encoded_extrinsic; + let extrinsic = match E::decode_all(&mut encoded_extrinsic) { + Ok(extrinsic) => extrinsic, + Err(err) => { + complete_submit_extrinsic( + reply_manager, + reply_context, + Err(RemoteErr::Decode(format!("Bad extrinsic: {}", err))), + mixnet, + ); + return; + } + }; + + let deadline = + Instant::now() + extrinsic_delay(reply_context.message_id(), config); + extrinsic_queue.insert(deadline, extrinsic, reply_context); + } + _ => { + debug!(target: LOG_TARGET, "Unrecognised request; discarding"); + // To keep things simple we don't bother sending a reply in this case. The + // requester will give up and try another mixnode eventually. + reply_manager.abandon(reply_context); + } + } + } + Some(Message::Reply(message)) => { + let Some(request) = request_manager.remove(&message.request_id) else { + trace!( + target: LOG_TARGET, + "Received reply to already-completed request with message ID {:x?}", + message.request_id + ); + return; + }; + request.send_reply(&message.data); + } + None => (), + } +} + +fn time_until(instant: Instant) -> Duration { + instant.saturating_duration_since(Instant::now()) +} + +/// Run the mixnet service. If `keystore` is `None`, the service will not attempt to register the +/// local node as a mixnode, even if `config.register` is `true`. +pub async fn run( + config: Config, + mut api_backend: ApiBackend, + client: Arc, + sync: Arc, + network: Arc, + protocol_name: ProtocolName, + transaction_pool: Arc

, + keystore: Option, + mut notification_service: Box, +) where + B: Block, + C: BlockchainEvents + ProvideRuntimeApi + HeaderBackend, + C::Api: MixnetApi, + S: SyncOracle, + P: TransactionPool + LocalTransactionPool + 'static, +{ + let local_peer_id = network.local_peer_id(); + let Some(local_peer_id) = to_core_peer_id(&local_peer_id) else { + error!(target: LOG_TARGET, + "Failed to convert libp2p local peer ID {local_peer_id} to mixnet peer ID; \ + mixnet not running"); + return; + }; + + let offchain_transaction_pool_factory = + OffchainTransactionPoolFactory::new(transaction_pool.clone()); + + let mut mixnet = Mixnet::new(config.core); + // It would make sense to reset this to 0 when the session changes, but registrations aren't + // allowed at the start of a session anyway, so it doesn't really matter + let mut min_register_block = 0u32.into(); + let mut packet_dispatcher = PacketDispatcher::new(&local_peer_id); + let mut request_manager = RequestManager::new(config.request_manager); + let mut reply_manager = ReplyManager::new(config.reply_manager); + let mut extrinsic_queue = ExtrinsicQueue::new(config.substrate.extrinsic_queue_capacity); + + let mut finality_notifications = client.finality_notification_stream(); + // Import notifications only used for triggering registration attempts + let mut import_notifications = if config.substrate.register && keystore.is_some() { + Some(client.import_notification_stream()) + } else { + None + }; + let mut next_forward_packet_delay = MaybeInfDelay::new(None); + let mut next_authored_packet_delay = MaybeInfDelay::new(None); + let mut ready_peers = FuturesUnordered::new(); + let mut next_retry_delay = MaybeInfDelay::new(None); + let mut next_extrinsic_delay = MaybeInfDelay::new(None); + let mut submit_extrinsic_results = FuturesUnordered::new(); + + loop { + let mut next_request = if request_manager.has_space() { + Either::Left(api_backend.request_receiver.select_next_some()) + } else { + Either::Right(pending()) + }; + + let mut next_import_notification = import_notifications.as_mut().map_or_else( + || Either::Right(pending()), + |notifications| Either::Left(notifications.select_next_some()), + ); + + futures::select! { + request = next_request => + request_manager.insert(request, &mut mixnet, &packet_dispatcher, &config.substrate), + + notification = finality_notifications.select_next_some() => { + // To avoid trying to connect to old mixnodes, ignore finality notifications while + // offline or major syncing. This is a bit racy but should be good enough. + if !sync.is_offline() && !sync.is_major_syncing() { + let api = client.runtime_api(); + sync_with_runtime(&mut mixnet, api, notification.hash); + request_manager.update_session_status( + &mut mixnet, &packet_dispatcher, &config.substrate); + } + } + + notification = next_import_notification => { + if notification.is_new_best && (*notification.header.number() >= min_register_block) { + let mut api = client.runtime_api(); + api.register_extension(KeystoreExt(keystore.clone().expect( + "Import notification stream only setup if we have a keystore"))); + api.register_extension(offchain_transaction_pool_factory + .offchain_transaction_pool(notification.hash)); + let session_index = mixnet.session_status().current_index; + let mixnode = Mixnode { + kx_public: *mixnet.next_kx_public(), + peer_id: local_peer_id, + external_addresses: network.external_addresses().into_iter() + .map(|addr| addr.to_string().into_bytes()).collect(), + }; + match api.maybe_register(notification.hash, session_index, mixnode) { + Ok(true) => min_register_block = notification.header.number().saturating_add( + MIN_BLOCKS_BETWEEN_REGISTRATION_ATTEMPTS.into()), + Ok(false) => (), + Err(err) => debug!(target: LOG_TARGET, + "Error trying to register for the next session: {err}"), + } + } + } + + event = notification_service.next_event().fuse() => match event { + None => todo!(), + Some(NotificationEvent::ValidateInboundSubstream { result_tx, .. }) => { + let _ = result_tx.send(ValidationResult::Accept); + }, + Some(NotificationEvent::NotificationStreamOpened { peer, .. }) => { + packet_dispatcher.add_peer(&peer); + }, + Some(NotificationEvent::NotificationStreamClosed { peer }) => { + packet_dispatcher.remove_peer(&peer); + }, + Some(NotificationEvent::NotificationReceived { peer, notification }) => { + let notification: Bytes = notification.into(); + + match notification.as_ref().try_into() { + Ok(packet) => handle_packet(packet, + &mut mixnet, &mut request_manager, &mut reply_manager, + &mut extrinsic_queue, &config.substrate), + Err(_) => debug!(target: LOG_TARGET, + "Dropped incorrectly sized packet ({} bytes) from {peer}", + notification.len(), + ), + } + }, + }, + + _ = next_forward_packet_delay => { + if let Some(packet) = mixnet.pop_next_forward_packet() { + if let Some(ready_peer) = packet_dispatcher.dispatch(packet) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { + ready_peers.push(fut); + } + } + } else { + warn!(target: LOG_TARGET, + "Next forward packet deadline reached, but no packet in queue; \ + this is a bug"); + } + } + + _ = next_authored_packet_delay => { + if let Some(packet) = mixnet.pop_next_authored_packet(&packet_dispatcher) { + if let Some(ready_peer) = packet_dispatcher.dispatch(packet) { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { + ready_peers.push(fut); + } + } + } + } + + ready_peer = ready_peers.select_next_some() => { + if let Some(ready_peer) = ready_peer { + if let Some(fut) = ready_peer.send_packet(¬ification_service) { + ready_peers.push(fut); + } + } + } + + _ = next_retry_delay => { + if !request_manager.pop_next_retry(&mut mixnet, &packet_dispatcher, &config.substrate) { + warn!(target: LOG_TARGET, + "Next retry deadline reached, but no request in retry queue; \ + this is a bug"); + } + } + + _ = next_extrinsic_delay => { + if let Some((extrinsic, reply_context)) = extrinsic_queue.pop() { + if submit_extrinsic_results.len() < config.substrate.max_pending_extrinsics { + let fut = transaction_pool.submit_one( + client.info().best_hash, + TransactionSource::External, + extrinsic); + submit_extrinsic_results.push(async move { + (fut.await, reply_context) + }); + } else { + // There are already too many pending extrinsics, just drop this one. We + // don't send a reply; we want the requester to retry. + debug!(target: LOG_TARGET, + "Too many pending extrinsics; dropped submit extrinsic request"); + reply_manager.abandon(reply_context); + } + } else { + warn!(target: LOG_TARGET, + "Next extrinsic deadline reached, but no extrinsic in queue; \ + this is a bug"); + } + } + + res_reply_context = submit_extrinsic_results.select_next_some() => { + let (res, reply_context) = res_reply_context; + let res = match res { + Ok(_) => Ok(()), + Err(err) => Err(RemoteErr::Other(err.to_string())), + }; + complete_submit_extrinsic(&mut reply_manager, reply_context, res, &mut mixnet); + } + } + + let events = mixnet.take_events(); + if !events.is_empty() { + if events.contains(Events::RESERVED_PEERS_CHANGED) { + let reserved_peer_addrs = mixnet + .reserved_peers() + .flat_map(|mixnode| mixnode.extra.iter()) // External addresses + .cloned() + .collect(); + if let Err(err) = + network.set_reserved_peers(protocol_name.clone(), reserved_peer_addrs) + { + debug!(target: LOG_TARGET, "Setting reserved peers failed: {err}"); + } + } + if events.contains(Events::NEXT_FORWARD_PACKET_DEADLINE_CHANGED) { + next_forward_packet_delay + .reset(mixnet.next_forward_packet_deadline().map(time_until)); + } + if events.contains(Events::NEXT_AUTHORED_PACKET_DEADLINE_CHANGED) { + next_authored_packet_delay.reset(mixnet.next_authored_packet_delay()); + } + if events.contains(Events::SPACE_IN_AUTHORED_PACKET_QUEUE) { + // Note this may cause the next retry deadline to change, but should not trigger + // any mixnet events + request_manager.process_post_queues( + &mut mixnet, + &packet_dispatcher, + &config.substrate, + ); + } + } + + if request_manager.next_retry_deadline_changed() { + next_retry_delay.reset(request_manager.next_retry_deadline().map(time_until)); + } + + if extrinsic_queue.next_deadline_changed() { + next_extrinsic_delay.reset(extrinsic_queue.next_deadline().map(time_until)); + } + } +} diff --git a/substrate/sc-mixnet/src/sync_with_runtime.rs b/substrate/sc-mixnet/src/sync_with_runtime.rs new file mode 100644 index 00000000000..fbcea458ff5 --- /dev/null +++ b/substrate/sc-mixnet/src/sync_with_runtime.rs @@ -0,0 +1,219 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! [`sync_with_runtime`] synchronises the session status and mixnode sets from the blockchain +//! runtime to the core mixnet state. It is called every time a block is finalised. + +use super::peer_id::from_core_peer_id; +use log::{debug, info}; +use mixnet::core::{ + Mixnet, Mixnode as CoreMixnode, MixnodesErr as CoreMixnodesErr, RelSessionIndex, + SessionPhase as CoreSessionPhase, SessionStatus as CoreSessionStatus, +}; +use sc_network_types::{ + multiaddr::{multiaddr, Multiaddr, Protocol}, + PeerId, +}; +use sp_api::{ApiError, ApiRef}; +use sp_mixnet::{ + runtime_api::MixnetApi, + types::{ + Mixnode as RuntimeMixnode, MixnodesErr as RuntimeMixnodesErr, + SessionPhase as RuntimeSessionPhase, SessionStatus as RuntimeSessionStatus, + }, +}; +use sp_runtime::traits::Block; + +const LOG_TARGET: &str = "mixnet"; + +/// Convert a [`RuntimeSessionStatus`] to a [`CoreSessionStatus`]. +/// +/// The [`RuntimeSessionStatus`] and [`CoreSessionStatus`] types are effectively the same. +/// [`RuntimeSessionStatus`] is used in the runtime to avoid depending on the [`mixnet`] crate +/// there. +fn to_core_session_status(status: RuntimeSessionStatus) -> CoreSessionStatus { + CoreSessionStatus { + current_index: status.current_index, + phase: match status.phase { + RuntimeSessionPhase::CoverToCurrent => CoreSessionPhase::CoverToCurrent, + RuntimeSessionPhase::RequestsToCurrent => CoreSessionPhase::RequestsToCurrent, + RuntimeSessionPhase::CoverToPrev => CoreSessionPhase::CoverToPrev, + RuntimeSessionPhase::DisconnectFromPrev => CoreSessionPhase::DisconnectFromPrev, + }, + } +} + +fn parse_external_addresses(external_addresses: Vec>) -> Vec { + external_addresses + .into_iter() + .flat_map(|addr| { + let addr = match String::from_utf8(addr) { + Ok(addr) => addr, + Err(addr) => { + debug!( + target: LOG_TARGET, + "Mixnode external address {:x?} is not valid UTF-8", + addr.into_bytes(), + ); + return None; + } + }; + match addr.parse() { + Ok(addr) => Some(addr), + Err(err) => { + debug!( + target: LOG_TARGET, + "Could not parse mixnode address {addr}: {err}", + ); + None + } + } + }) + .collect() +} + +/// Modify `external_addresses` such that there is at least one address and the final component of +/// each address matches `peer_id`. +fn fixup_external_addresses(external_addresses: &mut Vec, peer_id: &PeerId) { + // Ensure the final component of each address matches peer_id + external_addresses.retain_mut(|addr| match PeerId::try_from_multiaddr(addr) { + Some(addr_peer_id) if addr_peer_id == *peer_id => true, + Some(_) => { + debug!( + target: LOG_TARGET, + "Mixnode address {} does not match mixnode peer ID {}, ignoring", + addr, + peer_id + ); + false + } + None if matches!(addr.iter().last(), Some(Protocol::P2p(_))) => { + debug!( + target: LOG_TARGET, + "Mixnode address {} has unrecognised P2P protocol, ignoring", + addr + ); + false + } + None => { + addr.push(Protocol::P2p(*peer_id.as_ref())); + true + } + }); + + // If there are no addresses, insert one consisting of just the peer ID + if external_addresses.is_empty() { + external_addresses.push(multiaddr!(P2p(*peer_id.as_ref()))); + } +} + +/// Convert a [`RuntimeMixnode`] to a [`CoreMixnode`]. If the conversion fails, an error message is +/// logged, but a [`CoreMixnode`] is still returned. +/// +/// It would be possible to handle conversion failure in a better way, but this would complicate +/// things for what should be a rare case. Note that even if the conversion here succeeds, there is +/// no guarantee that we will be able to connect to the mixnode or send packets to it. The most +/// common failure case is expected to be that a mixnode is simply unreachable over the network. +fn into_core_mixnode(mixnode: RuntimeMixnode) -> CoreMixnode> { + let external_addresses = if let Some(peer_id) = from_core_peer_id(&mixnode.peer_id) { + let mut external_addresses = parse_external_addresses(mixnode.external_addresses); + fixup_external_addresses(&mut external_addresses, &peer_id); + external_addresses + } else { + debug!( + target: LOG_TARGET, + "Failed to convert mixnet peer ID {:x?} to libp2p peer ID", + mixnode.peer_id, + ); + Vec::new() + }; + + CoreMixnode { + kx_public: mixnode.kx_public, + peer_id: mixnode.peer_id, + extra: external_addresses, + } +} + +fn maybe_set_mixnodes( + mixnet: &mut Mixnet>, + rel_session_index: RelSessionIndex, + mixnodes: &dyn Fn() -> Result, RuntimeMixnodesErr>, ApiError>, +) { + let current_session_index = mixnet.session_status().current_index; + mixnet.maybe_set_mixnodes(rel_session_index, &mut || { + // Note that RelSessionIndex::Prev + 0 would panic, but this closure will not get called in + // that case so we are fine. Do not move this out of the closure! + let session_index = rel_session_index + current_session_index; + match mixnodes() { + Ok(Ok(mixnodes)) => Ok(mixnodes.into_iter().map(into_core_mixnode).collect()), + Ok(Err(err)) => { + info!(target: LOG_TARGET, "Session {session_index}: Mixnet disabled: {err}"); + Err(CoreMixnodesErr::Permanent) // Disable the session slot + } + Err(err) => { + debug!( + target: LOG_TARGET, + "Session {session_index}: Error getting mixnodes from runtime: {err}" + ); + Err(CoreMixnodesErr::Transient) // Just leave the session slot empty; try again next block + } + } + }); +} + +pub fn sync_with_runtime(mixnet: &mut Mixnet>, api: ApiRef, hash: B::Hash) +where + B: Block, + A: MixnetApi, +{ + let session_status = match api.session_status(hash) { + Ok(session_status) => session_status, + Err(err) => { + debug!(target: LOG_TARGET, "Error getting session status from runtime: {err}"); + return; + } + }; + mixnet.set_session_status(to_core_session_status(session_status)); + + maybe_set_mixnodes(mixnet, RelSessionIndex::Prev, &|| api.prev_mixnodes(hash)); + maybe_set_mixnodes(mixnet, RelSessionIndex::Current, &|| { + api.current_mixnodes(hash) + }); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fixup_empty_external_addresses() { + let peer_id = PeerId::random(); + let mut external_addresses = Vec::new(); + fixup_external_addresses(&mut external_addresses, &peer_id); + assert_eq!(external_addresses, vec![multiaddr!(P2p(peer_id))]); + } + + #[test] + fn fixup_misc_external_addresses() { + let peer_id = PeerId::random(); + let other_peer_id = PeerId::random(); + let mut external_addresses = vec![ + multiaddr!(Tcp(0u16), P2p(peer_id)), + multiaddr!(Tcp(1u16), P2p(other_peer_id)), + multiaddr!(Tcp(2u16)), + Multiaddr::empty(), + ]; + fixup_external_addresses(&mut external_addresses, &peer_id); + assert_eq!( + external_addresses, + vec![ + multiaddr!(Tcp(0u16), P2p(peer_id)), + multiaddr!(Tcp(2u16), P2p(peer_id)), + multiaddr!(P2p(peer_id)), + ] + ); + } +} diff --git a/substrate/sp-allocator/Cargo.toml b/substrate/sp-allocator/Cargo.toml new file mode 100644 index 00000000000..7b0601948f8 --- /dev/null +++ b/substrate/sp-allocator/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "sp-allocator" +version = "29.0.0" +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "Collection of allocator implementations." +documentation = "https://docs.rs/sp-allocator" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { features = ["derive"], workspace = true } +log = { workspace = true, default-features = false } +thiserror = { workspace = true, optional = true } +sp-wasm-interface-common = { workspace = true, default-features = false } + +[features] +default = [ "std" ] +std = [ "codec/std", "log/std", "sp-wasm-interface-common/std", "thiserror" ] diff --git a/substrate/sp-allocator/README.md b/substrate/sp-allocator/README.md new file mode 100644 index 00000000000..4db5a810aab --- /dev/null +++ b/substrate/sp-allocator/README.md @@ -0,0 +1,14 @@ +# sp-allocator + +Collection of allocator implementations, including `FreeingBumpHeapAllocator`. + +Local Cargo package name: `sp-allocator`. +Gear publish name: `gsp-allocator`. + +License: Apache-2.0. + +Source: Gear Polkadot SDK fork `gear-polkadot-stable2409-wasm32v1-none` at `1d1b394647eb26c094cf50c759b900dc5faa3b80`, derived from `sc-allocator` in Parity Polkadot SDK `stable2409` at `298f676c91d64f15f38ea7fd78f125c5889ab09c`. + +Copied source files retain the upstream SPDX headers and Parity Technologies copyright notices. Gear maintains this forked crate and publishes it under the `gsp-allocator` package name for Gear ecosystem crates. + +Apache-2.0 license text: . diff --git a/substrate/sp-allocator/src/error.rs b/substrate/sp-allocator/src/error.rs new file mode 100644 index 00000000000..9e0ca417b40 --- /dev/null +++ b/substrate/sp-allocator/src/error.rs @@ -0,0 +1,21 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +/// The error type used by the allocators. +#[derive(thiserror::Error, Debug, PartialEq)] +pub enum Error { + /// Someone tried to allocate more memory than the allowed maximum per allocation. + #[error("Requested allocation size is too large")] + RequestedAllocationTooLarge, + /// Allocator run out of space. + #[error("Allocator ran out of space")] + AllocatorOutOfSpace, + /// The client passed a memory instance which is smaller than previously observed. + #[error("Shrinking of the underlying memory is observed")] + MemoryShrunk, + /// Some other error occurred. + #[error("Other: {0}")] + Other(&'static str), +} diff --git a/substrate/sp-allocator/src/freeing_bump.rs b/substrate/sp-allocator/src/freeing_bump.rs new file mode 100644 index 00000000000..71e7175d3c4 --- /dev/null +++ b/substrate/sp-allocator/src/freeing_bump.rs @@ -0,0 +1,1190 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +//! This module implements a freeing-bump allocator. +//! +//! The heap is a continuous linear memory and chunks are allocated using a bump allocator. +//! +//! ```ignore +//! +-------------+-------------------------------------------------+ +//! | | | +//! +-------------+-------------------------------------------------+ +//! ^ +//! |_ bumper +//! ``` +//! +//! Only allocations with sizes of power of two can be allocated. If the incoming request has a non +//! power of two size it is increased to the nearest power of two. The power of two of size is +//! referred as **an order**. +//! +//! Each allocation has a header immediately preceding to it. The header is always 8 bytes and can +//! be of two types: free and occupied. +//! +//! For implementing freeing we maintain a linked lists for each order. The maximum supported +//! allocation size is capped, therefore the number of orders and thus the linked lists is as well +//! limited. Currently, the maximum size of an allocation is 32 MiB. +//! +//! When the allocator serves an allocation request it first checks the linked list for the +//! respective order. If it doesn't have any free chunks, the allocator requests memory from the +//! bump allocator. In any case the order is stored in the header of the allocation. +//! +//! Upon deallocation we get the order of the allocation from its header and then add that +//! allocation to the linked list for the respective order. +//! +//! # Caveats +//! +//! This is a fast allocator but it is also dumb. There are specifically two main shortcomings +//! that the user should keep in mind: +//! +//! - Once the bump allocator space is exhausted, there is no way to reclaim the memory. This means +//! that it's possible to end up in a situation where there are no live allocations yet a new +//! allocation will fail. +//! +//! Let's look into an example. Given a heap of 32 MiB. The user makes a 32 MiB allocation that we +//! call `X` . Now the heap is full. Then user deallocates `X`. Since all the space in the bump +//! allocator was consumed by the 32 MiB allocation, allocations of all sizes except 32 MiB will +//! fail. +//! +//! - Sizes of allocations are rounded up to the nearest order. That is, an allocation of 2,00001 +//! MiB will be put into the bucket of 4 MiB. Therefore, any allocation of size `(N, 2N]` will +//! take up to `2N`, thus assuming a uniform distribution of allocation sizes, the average amount +//! in use of a `2N` space on the heap will be `(3N + ε) / 2`. So average utilization is going to +//! be around 75% (`(3N + ε) / 2 / 2N`) meaning that around 25% of the space in allocation will be +//! wasted. This is more pronounced (in terms of absolute heap amounts) with larger allocation +//! sizes. + +use crate::{Error, MAX_POSSIBLE_ALLOCATION, MAX_WASM_PAGES, Memory, PAGE_SIZE}; +use sp_wasm_interface_common::{Pointer, WordSize}; +use std::{ + cmp::{max, min}, + mem, + ops::{Index, IndexMut, Range}, +}; + +/// The minimal alignment guaranteed by this allocator. +/// +/// The alignment of 8 is chosen because it is the maximum size of a primitive type supported by the +/// target version of wasm32: i64's natural alignment is 8. +const ALIGNMENT: u32 = 8; + +// Each pointer is prefixed with 8 bytes, which identify the list index +// to which it belongs. +const HEADER_SIZE: u32 = 8; + +/// Create an allocator error. +fn error(msg: &'static str) -> Error { + Error::Other(msg) +} + +const LOG_TARGET: &str = "wasm-heap"; + +// The minimum possible allocation size is chosen to be 8 bytes because in that case we would have +// easier time to provide the guaranteed alignment of 8. +// +// The maximum possible allocation size is set in the primitives to 32MiB. +// +// N_ORDERS - represents the number of orders supported. +// +// This number corresponds to the number of powers between the minimum possible allocation and +// maximum possible allocation, or: 2^3...2^25 (both ends inclusive, hence 23). +const N_ORDERS: usize = 23; +const MIN_POSSIBLE_ALLOCATION: u32 = 8; // 2^3 bytes, 8 bytes + +/// The exponent for the power of two sized block adjusted to the minimum size. +/// +/// This way, if `MIN_POSSIBLE_ALLOCATION == 8`, we would get: +/// +/// power_of_two_size | order +/// 8 | 0 +/// 16 | 1 +/// 32 | 2 +/// 64 | 3 +/// ... +/// 16777216 | 21 +/// 33554432 | 22 +/// +/// and so on. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct Order(u32); + +impl Order { + /// Create `Order` object from a raw order. + /// + /// Returns `Err` if it is greater than the maximum supported order. + fn from_raw(order: u32) -> Result { + if order < N_ORDERS as u32 { + Ok(Self(order)) + } else { + Err(error("invalid order")) + } + } + + /// Compute the order by the given size + /// + /// The size is clamped, so that the following holds: + /// + /// `MIN_POSSIBLE_ALLOCATION <= size <= MAX_POSSIBLE_ALLOCATION` + fn from_size(size: u32) -> Result { + let clamped_size = if size > MAX_POSSIBLE_ALLOCATION { + log::warn!(target: LOG_TARGET, "going to fail due to allocating {:?}", size); + return Err(Error::RequestedAllocationTooLarge); + } else if size < MIN_POSSIBLE_ALLOCATION { + MIN_POSSIBLE_ALLOCATION + } else { + size + }; + + // Round the clamped size to the next power of two. + // + // It returns the unchanged value if the value is already a power of two. + let power_of_two_size = clamped_size.next_power_of_two(); + + // Compute the number of trailing zeroes to get the order. We adjust it by the number of + // trailing zeroes in the minimum possible allocation. + let order = power_of_two_size.trailing_zeros() - MIN_POSSIBLE_ALLOCATION.trailing_zeros(); + + Ok(Self(order)) + } + + /// Returns the corresponding size in bytes for this order. + /// + /// Note that it is always a power of two. + fn size(&self) -> u32 { + MIN_POSSIBLE_ALLOCATION << self.0 + } + + /// Extract the order as `u32`. + fn into_raw(self) -> u32 { + self.0 + } +} + +/// A special magic value for a pointer in a link that denotes the end of the linked list. +const NIL_MARKER: u32 = u32::MAX; + +/// A link between headers in the free list. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum Link { + /// Nil, denotes that there is no next element. + Nil, + /// Link to the next element represented as a pointer to the a header. + Ptr(u32), +} + +impl Link { + /// Creates a link from raw value. + fn from_raw(raw: u32) -> Self { + if raw != NIL_MARKER { + Self::Ptr(raw) + } else { + Self::Nil + } + } + + /// Converts this link into a raw u32. + fn into_raw(self) -> u32 { + match self { + Self::Nil => NIL_MARKER, + Self::Ptr(ptr) => ptr, + } + } +} + +/// A header of an allocation. +/// +/// The header is encoded in memory as follows. +/// +/// ## Free header +/// +/// ```ignore +/// 64 32 0 +// +--------------+-------------------+ +/// | 0 | next element link | +/// +--------------+-------------------+ +/// ``` +/// ## Occupied header +/// ```ignore +/// 64 32 0 +// +--------------+-------------------+ +/// | 1 | order | +/// +--------------+-------------------+ +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +enum Header { + /// A free header contains a link to the next element to form a free linked list. + Free(Link), + /// An occupied header has attached order to know in which free list we should put the + /// allocation upon deallocation. + Occupied(Order), +} + +impl Header { + /// Reads a header from memory. + /// + /// Returns an error if the `header_ptr` is out of bounds of the linear memory or if the read + /// header is corrupted (e.g. the order is incorrect). + fn read_from(memory: &impl Memory, header_ptr: u32) -> Result { + let raw_header = memory.read_le_u64(header_ptr)?; + + // Check if the header represents an occupied or free allocation and extract the header data + // by trimming (and discarding) the high bits. + let occupied = raw_header & 0x00000001_00000000 != 0; + let header_data = raw_header as u32; + + Ok(if occupied { + Self::Occupied(Order::from_raw(header_data)?) + } else { + Self::Free(Link::from_raw(header_data)) + }) + } + + /// Write out this header to memory. + /// + /// Returns an error if the `header_ptr` is out of bounds of the linear memory. + fn write_into(&self, memory: &mut impl Memory, header_ptr: u32) -> Result<(), Error> { + let (header_data, occupied_mask) = match *self { + Self::Occupied(order) => (order.into_raw(), 0x00000001_00000000), + Self::Free(link) => (link.into_raw(), 0x00000000_00000000), + }; + let raw_header = header_data as u64 | occupied_mask; + memory.write_le_u64(header_ptr, raw_header)?; + Ok(()) + } + + /// Returns the order of the allocation if this is an occupied header. + fn into_occupied(self) -> Option { + match self { + Self::Occupied(order) => Some(order), + _ => None, + } + } + + /// Returns the link to the next element in the free list if this is a free header. + fn into_free(self) -> Option { + match self { + Self::Free(link) => Some(link), + _ => None, + } + } +} + +/// This struct represents a collection of intrusive linked lists for each order. +struct FreeLists { + heads: [Link; N_ORDERS], +} + +impl FreeLists { + /// Creates the free empty lists. + fn new() -> Self { + Self { + heads: [Link::Nil; N_ORDERS], + } + } + + /// Replaces a given link for the specified order and returns the old one. + fn replace(&mut self, order: Order, new: Link) -> Link { + let prev = self[order]; + self[order] = new; + prev + } +} + +impl Index for FreeLists { + type Output = Link; + fn index(&self, index: Order) -> &Link { + &self.heads[index.0 as usize] + } +} + +impl IndexMut for FreeLists { + fn index_mut(&mut self, index: Order) -> &mut Link { + &mut self.heads[index.0 as usize] + } +} + +/// Memory allocation stats gathered during the lifetime of the allocator. +#[derive(Clone, Debug, Default)] +#[non_exhaustive] +pub struct AllocationStats { + /// The current number of bytes allocated. + /// + /// This represents how many bytes are allocated *right now*. + pub bytes_allocated: u32, + + /// The peak number of bytes ever allocated. + /// + /// This is the maximum the `bytes_allocated` ever reached. + pub bytes_allocated_peak: u32, + + /// The sum of every allocation ever made. + /// + /// This increases every time a new allocation is made. + pub bytes_allocated_sum: u128, + + /// The amount of address space (in bytes) used by the allocator. + /// + /// This is calculated as the difference between the allocator's bumper + /// and the heap base. + /// + /// Currently the bumper's only ever incremented, so this is simultaneously + /// the current value as well as the peak value. + pub address_space_used: u32, +} + +/// Convert the given `size` in bytes into the number of pages. +/// +/// The returned number of pages is ensured to be big enough to hold memory with the given `size`. +/// +/// Returns `None` if the number of pages to not fit into `u32`. +fn pages_from_size(size: u64) -> Option { + u32::try_from(size.div_ceil(PAGE_SIZE as u64)).ok() +} + +/// An implementation of freeing bump allocator. +/// +/// Refer to the module-level documentation for further details. +pub struct FreeingBumpHeapAllocator { + original_heap_base: u32, + bumper: u32, + free_lists: FreeLists, + poisoned: bool, + last_observed_memory_size: u64, + stats: AllocationStats, +} + +impl Drop for FreeingBumpHeapAllocator { + fn drop(&mut self) { + log::debug!(target: LOG_TARGET, "allocator dropped: {:?}", self.stats) + } +} + +impl FreeingBumpHeapAllocator { + /// Creates a new allocation heap which follows a freeing-bump strategy. + /// + /// # Arguments + /// + /// - `heap_base` - the offset from the beginning of the linear memory where the heap starts. + pub fn new(heap_base: u32) -> Self { + let aligned_heap_base = heap_base.div_ceil(ALIGNMENT) * ALIGNMENT; + + FreeingBumpHeapAllocator { + original_heap_base: aligned_heap_base, + bumper: aligned_heap_base, + free_lists: FreeLists::new(), + poisoned: false, + last_observed_memory_size: 0, + stats: AllocationStats::default(), + } + } + + /// Gets requested number of bytes to allocate and returns a pointer. + /// The maximum size which can be allocated at once is 32 MiB. + /// There is no minimum size, but whatever size is passed into + /// this function is rounded to the next power of two. If the requested + /// size is below 8 bytes it will be rounded up to 8 bytes. + /// + /// The identity or the type of the passed memory object does not matter. However, the size of + /// memory cannot shrink compared to the memory passed in previous invocations. + /// + /// NOTE: Once the allocator has returned an error all subsequent requests will return an error. + /// + /// # Arguments + /// + /// - `mem` - a slice representing the linear memory on which this allocator operates. + /// - `size` - size in bytes of the allocation request + pub fn allocate( + &mut self, + mem: &mut impl Memory, + size: WordSize, + ) -> Result, Error> { + if self.poisoned { + return Err(error("the allocator has been poisoned")); + } + + let bomb = PoisonBomb { + poisoned: &mut self.poisoned, + }; + + Self::observe_memory_size(&mut self.last_observed_memory_size, mem)?; + let order = Order::from_size(size)?; + + let header_ptr: u32 = match self.free_lists[order] { + Link::Ptr(header_ptr) => { + if (u64::from(header_ptr) + u64::from(order.size()) + u64::from(HEADER_SIZE)) + > mem.size() + { + return Err(error("Invalid header pointer detected")); + } + + // Remove this header from the free list. + let next_free = Header::read_from(mem, header_ptr)? + .into_free() + .ok_or_else(|| error("free list points to a occupied header"))?; + self.free_lists[order] = next_free; + + header_ptr + } + Link::Nil => { + // Corresponding free list is empty. Allocate a new item. + Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem)? + } + }; + + // Write the order in the occupied header. + Header::Occupied(order).write_into(mem, header_ptr)?; + + self.stats.bytes_allocated += order.size() + HEADER_SIZE; + self.stats.bytes_allocated_sum += u128::from(order.size() + HEADER_SIZE); + self.stats.bytes_allocated_peak = + max(self.stats.bytes_allocated_peak, self.stats.bytes_allocated); + self.stats.address_space_used = self.bumper - self.original_heap_base; + + log::trace!(target: LOG_TARGET, "after allocation: {:?}", self.stats); + + bomb.disarm(); + Ok(Pointer::new(header_ptr + HEADER_SIZE)) + } + + /// Deallocates the space which was allocated for a pointer. + /// + /// The identity or the type of the passed memory object does not matter. However, the size of + /// memory cannot shrink compared to the memory passed in previous invocations. + /// + /// NOTE: Once the allocator has returned an error all subsequent requests will return an error. + /// + /// # Arguments + /// + /// - `mem` - a slice representing the linear memory on which this allocator operates. + /// - `ptr` - pointer to the allocated chunk + pub fn deallocate(&mut self, mem: &mut impl Memory, ptr: Pointer) -> Result<(), Error> { + if self.poisoned { + return Err(error("the allocator has been poisoned")); + } + + let bomb = PoisonBomb { + poisoned: &mut self.poisoned, + }; + + Self::observe_memory_size(&mut self.last_observed_memory_size, mem)?; + + let header_ptr = u32::from(ptr) + .checked_sub(HEADER_SIZE) + .ok_or_else(|| error("Invalid pointer for deallocation"))?; + + let order = Header::read_from(mem, header_ptr)? + .into_occupied() + .ok_or_else(|| error("the allocation points to an empty header"))?; + + // Update the just freed header and knit it back to the free list. + let prev_head = self.free_lists.replace(order, Link::Ptr(header_ptr)); + Header::Free(prev_head).write_into(mem, header_ptr)?; + + self.stats.bytes_allocated = self + .stats + .bytes_allocated + .checked_sub(order.size() + HEADER_SIZE) + .ok_or_else(|| error("underflow of the currently allocated bytes count"))?; + + log::trace!("after deallocation: {:?}", self.stats); + + bomb.disarm(); + Ok(()) + } + + /// Returns the allocation stats for this allocator. + pub fn stats(&self) -> AllocationStats { + self.stats.clone() + } + + /// Increases the `bumper` by `size`. + /// + /// Returns the `bumper` from before the increase. Returns an `Error::AllocatorOutOfSpace` if + /// the operation would exhaust the heap. + fn bump(bumper: &mut u32, size: u32, memory: &mut impl Memory) -> Result { + let required_size = u64::from(*bumper) + u64::from(size); + if required_size > u64::from(u32::MAX) { + return Err(Error::AllocatorOutOfSpace); + } + + if required_size > memory.size() { + let required_pages = + pages_from_size(required_size).ok_or(Error::AllocatorOutOfSpace)?; + + let current_pages = memory.pages(); + let max_pages = memory.max_pages().unwrap_or(MAX_WASM_PAGES); + debug_assert!( + current_pages < required_pages, + "current pages {current_pages} < required pages {required_pages}" + ); + + if current_pages >= max_pages { + log::debug!( + target: LOG_TARGET, + "Wasm pages ({current_pages}) are already at the maximum.", + ); + + return Err(Error::AllocatorOutOfSpace); + } else if required_pages > max_pages { + log::debug!( + target: LOG_TARGET, + "Failed to grow memory from {current_pages} pages to at least {required_pages}\ + pages due to the maximum limit of {max_pages} pages", + ); + return Err(Error::AllocatorOutOfSpace); + } + + // Ideally we want to double our current number of pages, + // as long as it's less than the absolute maximum we can have. + let next_pages = min(current_pages * 2, max_pages); + // ...but if even more pages are required then try to allocate that many. + let next_pages = max(next_pages, required_pages); + + if memory.grow(next_pages - current_pages).is_err() { + log::error!( + target: LOG_TARGET, + "Failed to grow memory from {current_pages} pages to {next_pages} pages", + ); + + return Err(Error::AllocatorOutOfSpace); + } + + debug_assert_eq!( + memory.pages(), + next_pages, + "Number of pages should have increased!" + ); + } + + let res = *bumper; + *bumper += size; + Ok(res) + } + + fn observe_memory_size( + last_observed_memory_size: &mut u64, + mem: &mut impl Memory, + ) -> Result<(), Error> { + if mem.size() < *last_observed_memory_size { + return Err(Error::MemoryShrunk); + } + *last_observed_memory_size = mem.size(); + Ok(()) + } +} + +/// A trait for abstraction of accesses to a wasm linear memory. Used to read or modify the +/// allocation prefixes. +/// +/// A wasm linear memory behaves similarly to a vector. The address space doesn't have holes and is +/// accessible up to the reported size. +/// +/// The linear memory can grow in size with the wasm page granularity (64KiB), but it cannot shrink. +trait MemoryExt: Memory { + /// Read a u64 from the heap in LE form. Returns an error if any of the bytes read are out of + /// bounds. + fn read_le_u64(&self, ptr: u32) -> Result { + self.with_access(|memory| { + let range = + heap_range(ptr, 8, memory.len()).ok_or_else(|| error("read out of heap bounds"))?; + let bytes = memory[range] + .try_into() + .expect("[u8] slice of length 8 must be convertible to [u8; 8]"); + Ok(u64::from_le_bytes(bytes)) + }) + } + + /// Write a u64 to the heap in LE form. Returns an error if any of the bytes written are out of + /// bounds. + fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), Error> { + self.with_access_mut(|memory| { + let range = heap_range(ptr, 8, memory.len()) + .ok_or_else(|| error("write out of heap bounds"))?; + let bytes = val.to_le_bytes(); + memory[range].copy_from_slice(&bytes[..]); + Ok(()) + }) + } + + /// Returns the full size of the memory in bytes. + fn size(&self) -> u64 { + debug_assert!(self.pages() <= MAX_WASM_PAGES); + + self.pages() as u64 * PAGE_SIZE as u64 + } +} + +impl MemoryExt for T {} + +fn heap_range(offset: u32, length: u32, heap_len: usize) -> Option> { + let start = offset as usize; + let end = offset.checked_add(length)? as usize; + if end <= heap_len { + Some(start..end) + } else { + None + } +} + +/// A guard that will raise the poisoned flag on drop unless disarmed. +struct PoisonBomb<'a> { + poisoned: &'a mut bool, +} + +impl<'a> PoisonBomb<'a> { + fn disarm(self) { + mem::forget(self) + } +} + +impl<'a> Drop for PoisonBomb<'a> { + fn drop(&mut self) { + *self.poisoned = true; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Makes a pointer out of the given address. + fn to_pointer(address: u32) -> Pointer { + Pointer::new(address) + } + + #[derive(Debug)] + struct MemoryInstance { + data: Vec, + max_wasm_pages: u32, + } + + impl MemoryInstance { + fn with_pages(pages: u32) -> Self { + Self { + data: vec![0; (pages * PAGE_SIZE) as usize], + max_wasm_pages: MAX_WASM_PAGES, + } + } + + fn set_max_wasm_pages(&mut self, max_pages: u32) { + self.max_wasm_pages = max_pages; + } + } + + impl Memory for MemoryInstance { + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(&self.data) + } + + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + run(&mut self.data) + } + + fn pages(&self) -> u32 { + pages_from_size(self.data.len() as u64).unwrap() + } + + fn max_pages(&self) -> Option { + Some(self.max_wasm_pages) + } + + fn grow(&mut self, pages: u32) -> Result<(), ()> { + if self.pages() + pages > self.max_wasm_pages { + Err(()) + } else { + self.data + .resize(((self.pages() + pages) * PAGE_SIZE) as usize, 0); + Ok(()) + } + } + } + + #[test] + fn test_pages_from_size() { + assert_eq!(pages_from_size(0).unwrap(), 0); + assert_eq!(pages_from_size(1).unwrap(), 1); + assert_eq!(pages_from_size(65536).unwrap(), 1); + assert_eq!(pages_from_size(65536 + 1).unwrap(), 2); + assert_eq!(pages_from_size(2 * 65536).unwrap(), 2); + assert_eq!(pages_from_size(2 * 65536 + 1).unwrap(), 3); + } + + #[test] + fn should_allocate_properly() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + // when + let ptr = heap.allocate(&mut mem, 1).unwrap(); + + // then + // returned pointer must start right after `HEADER_SIZE` + assert_eq!(ptr, to_pointer(HEADER_SIZE)); + } + + #[test] + fn should_always_align_pointers_to_multiples_of_8() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(13); + + // when + let ptr = heap.allocate(&mut mem, 1).unwrap(); + + // then + // the pointer must start at the next multiple of 8 from 13 + // + the prefix of 8 bytes. + assert_eq!(ptr, to_pointer(24)); + } + + #[test] + fn should_increment_pointers_properly() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + // when + let ptr1 = heap.allocate(&mut mem, 1).unwrap(); + let ptr2 = heap.allocate(&mut mem, 9).unwrap(); + let ptr3 = heap.allocate(&mut mem, 1).unwrap(); + + // then + // a prefix of 8 bytes is prepended to each pointer + assert_eq!(ptr1, to_pointer(HEADER_SIZE)); + + // the prefix of 8 bytes + the content of ptr1 padded to the lowest possible + // item size of 8 bytes + the prefix of ptr1 + assert_eq!(ptr2, to_pointer(24)); + + // ptr2 + its content of 16 bytes + the prefix of 8 bytes + assert_eq!(ptr3, to_pointer(24 + 16 + HEADER_SIZE)); + } + + #[test] + fn should_free_properly() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + let ptr1 = heap.allocate(&mut mem, 1).unwrap(); + // the prefix of 8 bytes is prepended to the pointer + assert_eq!(ptr1, to_pointer(HEADER_SIZE)); + + let ptr2 = heap.allocate(&mut mem, 1).unwrap(); + // the prefix of 8 bytes + the content of ptr 1 is prepended to the pointer + assert_eq!(ptr2, to_pointer(24)); + + // when + heap.deallocate(&mut mem, ptr2).unwrap(); + + // then + // then the heads table should contain a pointer to the + // prefix of ptr2 in the leftmost entry + assert_eq!( + heap.free_lists.heads[0], + Link::Ptr(u32::from(ptr2) - HEADER_SIZE) + ); + } + + #[test] + fn should_deallocate_and_reallocate_properly() { + // given + let mut mem = MemoryInstance::with_pages(1); + let padded_offset = 16; + let mut heap = FreeingBumpHeapAllocator::new(13); + + let ptr1 = heap.allocate(&mut mem, 1).unwrap(); + // the prefix of 8 bytes is prepended to the pointer + assert_eq!(ptr1, to_pointer(padded_offset + HEADER_SIZE)); + + let ptr2 = heap.allocate(&mut mem, 9).unwrap(); + // the padded_offset + the previously allocated ptr (8 bytes prefix + + // 8 bytes content) + the prefix of 8 bytes which is prepended to the + // current pointer + assert_eq!(ptr2, to_pointer(padded_offset + 16 + HEADER_SIZE)); + + // when + heap.deallocate(&mut mem, ptr2).unwrap(); + let ptr3 = heap.allocate(&mut mem, 9).unwrap(); + + // then + // should have re-allocated + assert_eq!(ptr3, to_pointer(padded_offset + 16 + HEADER_SIZE)); + assert_eq!(heap.free_lists.heads, [Link::Nil; N_ORDERS]); + } + + #[test] + fn should_build_linked_list_of_free_areas_properly() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + let ptr1 = heap.allocate(&mut mem, 8).unwrap(); + let ptr2 = heap.allocate(&mut mem, 8).unwrap(); + let ptr3 = heap.allocate(&mut mem, 8).unwrap(); + + // when + heap.deallocate(&mut mem, ptr1).unwrap(); + heap.deallocate(&mut mem, ptr2).unwrap(); + heap.deallocate(&mut mem, ptr3).unwrap(); + + // then + assert_eq!( + heap.free_lists.heads[0], + Link::Ptr(u32::from(ptr3) - HEADER_SIZE) + ); + + let ptr4 = heap.allocate(&mut mem, 8).unwrap(); + assert_eq!(ptr4, ptr3); + + assert_eq!( + heap.free_lists.heads[0], + Link::Ptr(u32::from(ptr2) - HEADER_SIZE) + ); + } + + #[test] + fn should_not_allocate_if_too_large() { + // given + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(13); + + // when + let ptr = heap.allocate(&mut mem, PAGE_SIZE - 13); + + // then + assert_eq!(Error::AllocatorOutOfSpace, ptr.unwrap_err()); + } + + #[test] + fn should_not_allocate_if_full() { + // given + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + let ptr1 = heap + .allocate(&mut mem, (PAGE_SIZE / 2) - HEADER_SIZE) + .unwrap(); + assert_eq!(ptr1, to_pointer(HEADER_SIZE)); + + // when + let ptr2 = heap.allocate(&mut mem, PAGE_SIZE / 2); + + // then + // there is no room for another half page incl. its 8 byte prefix + match ptr2.unwrap_err() { + Error::AllocatorOutOfSpace => {} + e => panic!("Expected allocator out of space error, got: {:?}", e), + } + } + + #[test] + fn should_allocate_max_possible_allocation_size() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + // when + let ptr = heap.allocate(&mut mem, MAX_POSSIBLE_ALLOCATION).unwrap(); + + // then + assert_eq!(ptr, to_pointer(HEADER_SIZE)); + } + + #[test] + fn should_not_allocate_if_requested_size_too_large() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + // when + let ptr = heap.allocate(&mut mem, MAX_POSSIBLE_ALLOCATION + 1); + + // then + assert_eq!(Error::RequestedAllocationTooLarge, ptr.unwrap_err()); + } + + #[test] + fn should_return_error_when_bumper_greater_than_heap_size() { + // given + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + let mut ptrs = Vec::new(); + for _ in 0..(PAGE_SIZE as usize / 40) { + ptrs.push(heap.allocate(&mut mem, 32).expect("Allocate 32 byte")); + } + + assert_eq!(heap.stats.bytes_allocated, PAGE_SIZE - 16); + assert_eq!(heap.bumper, PAGE_SIZE - 16); + + ptrs.into_iter() + .for_each(|ptr| heap.deallocate(&mut mem, ptr).expect("Deallocate 32 byte")); + + assert_eq!(heap.stats.bytes_allocated, 0); + assert_eq!(heap.stats.bytes_allocated_peak, PAGE_SIZE - 16); + assert_eq!(heap.bumper, PAGE_SIZE - 16); + + // Allocate another 8 byte to use the full heap. + heap.allocate(&mut mem, 8).expect("Allocate 8 byte"); + + // when + // the `bumper` value is equal to `size` here and any + // further allocation which would increment the bumper must fail. + // we try to allocate 8 bytes here, which will increment the + // bumper since no 8 byte item has been freed before. + assert_eq!(heap.bumper as u64, mem.size()); + let ptr = heap.allocate(&mut mem, 8); + + // then + assert_eq!(Error::AllocatorOutOfSpace, ptr.unwrap_err()); + } + + #[test] + fn should_not_overflow_when_bump_reaches_wasm_address_limit() { + struct MaxPagesMemory; + + impl Memory for MaxPagesMemory { + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(&[]) + } + + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + run(&mut []) + } + + fn pages(&self) -> u32 { + MAX_WASM_PAGES + } + + fn max_pages(&self) -> Option { + Some(MAX_WASM_PAGES) + } + + fn grow(&mut self, _: u32) -> Result<(), ()> { + unreachable!("memory is already at the wasm address limit") + } + } + + let mut mem = MaxPagesMemory; + let mut bumper = u32::MAX - 7; + + let ptr = FreeingBumpHeapAllocator::bump(&mut bumper, 8, &mut mem); + + assert_eq!(Error::AllocatorOutOfSpace, ptr.unwrap_err()); + assert_eq!(bumper, u32::MAX - 7); + } + + #[test] + fn should_include_prefixes_in_total_heap_size() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(1); + + // when + // an item size of 16 must be used then + heap.allocate(&mut mem, 9).unwrap(); + + // then + assert_eq!(heap.stats.bytes_allocated, HEADER_SIZE + 16); + } + + #[test] + fn should_calculate_total_heap_size_to_zero() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(13); + + // when + let ptr = heap.allocate(&mut mem, 42).unwrap(); + assert_eq!(ptr, to_pointer(16 + HEADER_SIZE)); + heap.deallocate(&mut mem, ptr).unwrap(); + + // then + assert_eq!(heap.stats.bytes_allocated, 0); + } + + #[test] + fn should_calculate_total_size_of_zero() { + // given + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(19); + + // when + for _ in 1..10 { + let ptr = heap.allocate(&mut mem, 42).unwrap(); + heap.deallocate(&mut mem, ptr).unwrap(); + } + + // then + assert_eq!(heap.stats.bytes_allocated, 0); + } + + #[test] + fn should_read_and_write_u64_correctly() { + // given + let mut mem = MemoryInstance::with_pages(1); + + // when + mem.write_le_u64(40, 4480113).unwrap(); + + // then + let value = MemoryExt::read_le_u64(&mem, 40).unwrap(); + assert_eq!(value, 4480113); + } + + #[test] + fn should_get_item_size_from_order() { + // given + let raw_order = 0; + + // when + let item_size = Order::from_raw(raw_order).unwrap().size(); + + // then + assert_eq!(item_size, 8); + } + + #[test] + fn should_get_max_item_size_from_index() { + // given + let raw_order = 22; + + // when + let item_size = Order::from_raw(raw_order).unwrap().size(); + + // then + assert_eq!(item_size, MAX_POSSIBLE_ALLOCATION); + } + + #[test] + fn deallocate_needs_to_maintain_linked_list() { + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + // Allocate and free some pointers + let ptrs = (0..4) + .map(|_| heap.allocate(&mut mem, 8).unwrap()) + .collect::>(); + ptrs.iter() + .rev() + .for_each(|ptr| heap.deallocate(&mut mem, *ptr).unwrap()); + + // Second time we should be able to allocate all of them again and get the same pointers! + let new_ptrs = (0..4) + .map(|_| heap.allocate(&mut mem, 8).unwrap()) + .collect::>(); + assert_eq!(ptrs, new_ptrs); + } + + #[test] + fn header_read_write() { + let roundtrip = |header: Header| { + let mut memory = MemoryInstance::with_pages(1); + header.write_into(&mut memory, 0).unwrap(); + + let read_header = Header::read_from(&memory, 0).unwrap(); + assert_eq!(header, read_header); + }; + + roundtrip(Header::Occupied(Order(0))); + roundtrip(Header::Occupied(Order(1))); + roundtrip(Header::Free(Link::Nil)); + roundtrip(Header::Free(Link::Ptr(0))); + roundtrip(Header::Free(Link::Ptr(4))); + } + + #[test] + fn poison_oom() { + // given + let mut mem = MemoryInstance::with_pages(1); + mem.set_max_wasm_pages(1); + + let mut heap = FreeingBumpHeapAllocator::new(0); + + // when + let alloc_ptr = heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + assert_eq!( + Error::AllocatorOutOfSpace, + heap.allocate(&mut mem, PAGE_SIZE).unwrap_err() + ); + + // then + assert!(heap.poisoned); + assert!(heap.deallocate(&mut mem, alloc_ptr).is_err()); + } + + #[test] + fn test_n_orders() { + // Test that N_ORDERS is consistent with min and max possible allocation. + assert_eq!( + MIN_POSSIBLE_ALLOCATION * 2u32.pow(N_ORDERS as u32 - 1), + MAX_POSSIBLE_ALLOCATION + ); + } + + #[test] + fn accepts_growing_memory() { + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + + mem.grow(1).unwrap(); + + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + } + + #[test] + fn doesnt_accept_shrinking_memory() { + let mut mem = MemoryInstance::with_pages(2); + let mut heap = FreeingBumpHeapAllocator::new(0); + + heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap(); + + mem.data.truncate(PAGE_SIZE as usize); + + match heap.allocate(&mut mem, PAGE_SIZE / 2).unwrap_err() { + Error::MemoryShrunk => (), + _ => panic!(), + } + } + + #[test] + fn should_grow_memory_when_running_out_of_memory() { + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + assert_eq!(1, mem.pages()); + + heap.allocate(&mut mem, PAGE_SIZE * 2).unwrap(); + + assert_eq!(3, mem.pages()); + } + + #[test] + fn modifying_the_header_leads_to_an_error() { + let mut mem = MemoryInstance::with_pages(1); + let mut heap = FreeingBumpHeapAllocator::new(0); + + let ptr = heap.allocate(&mut mem, 5).unwrap(); + + heap.deallocate(&mut mem, ptr).unwrap(); + + Header::Free(Link::Ptr(u32::MAX - 1)) + .write_into(&mut mem, u32::from(ptr) - HEADER_SIZE) + .unwrap(); + + heap.allocate(&mut mem, 5).unwrap(); + assert!( + heap.allocate(&mut mem, 5) + .unwrap_err() + .to_string() + .contains("Invalid header pointer") + ); + } +} diff --git a/substrate/sp-allocator/src/lib.rs b/substrate/sp-allocator/src/lib.rs new file mode 100644 index 00000000000..a9acd310cd2 --- /dev/null +++ b/substrate/sp-allocator/src/lib.rs @@ -0,0 +1,63 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +//! Collection of allocator implementations. +//! +//! This crate provides the following allocator implementations: +//! - A freeing-bump allocator: [`FreeingBumpHeapAllocator`] + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +#[cfg(feature = "std")] +mod error; +#[cfg(feature = "std")] +mod freeing_bump; + +#[cfg(feature = "std")] +pub use error::Error; +#[cfg(feature = "std")] +pub use freeing_bump::{AllocationStats, FreeingBumpHeapAllocator}; + +/// The size of one wasm page in bytes. +/// +/// The wasm memory is divided into pages, meaning the minimum size of a memory is one page. +#[cfg(feature = "std")] +const PAGE_SIZE: u32 = 65536; + +/// The maximum number of wasm pages that can be allocated. +/// +/// 4GiB / [`PAGE_SIZE`]. +#[cfg(feature = "std")] +const MAX_WASM_PAGES: u32 = (4u64 * 1024 * 1024 * 1024 / PAGE_SIZE as u64) as u32; + +/// Grants access to the memory for the allocator. +/// +/// Memory of wasm is allocated in pages. A page has a constant size of 64KiB. The maximum allowed +/// memory size as defined in the wasm specification is 4GiB (65536 pages). +pub trait Memory { + /// Run the given closure `run` and grant it write access to the raw memory. + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R; + /// Run the given closure `run` and grant it read access to the raw memory. + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R; + /// Grow the memory by `additional` pages. + #[allow(clippy::result_unit_err)] + fn grow(&mut self, additional: u32) -> Result<(), ()>; + /// Returns the current number of pages this memory has allocated. + fn pages(&self) -> u32; + /// Returns the maximum number of pages this memory is allowed to allocate. + /// + /// The returned number needs to be smaller or equal to `65536`. The returned number needs to be + /// bigger or equal to [`Self::pages`]. + /// + /// If `None` is returned, there is no maximum (besides the maximum defined in the wasm spec). + fn max_pages(&self) -> Option; +} + +/// The maximum number of bytes that can be allocated at one time. +// The maximum possible allocation size was chosen rather arbitrary, 32 MiB should be enough for +// everybody. +// 2^25 bytes, 32 MiB +pub const MAX_POSSIBLE_ALLOCATION: u32 = 33_554_432; diff --git a/substrate/sp-runtime-interface-proc-macro/Cargo.toml b/substrate/sp-runtime-interface-proc-macro/Cargo.toml new file mode 100644 index 00000000000..c5e92dd081d --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "sp-runtime-interface-proc-macro" +version = "18.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "This crate provides procedural macros for usage within the context of the Substrate runtime interface." +documentation = "https://docs.rs/sp-runtime-interface-proc-macro" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true + +[dependencies] +Inflector = { workspace = true } +proc-macro-crate = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +expander = { workspace = true } +syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } diff --git a/substrate/sp-runtime-interface-proc-macro/README.md b/substrate/sp-runtime-interface-proc-macro/README.md new file mode 100644 index 00000000000..96e931ea4da --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/README.md @@ -0,0 +1,5 @@ + + +## Release + +Polkadot SDK stable2409 diff --git a/substrate/sp-runtime-interface-proc-macro/src/lib.rs b/substrate/sp-runtime-interface-proc-macro/src/lib.rs new file mode 100644 index 00000000000..ed825e97df1 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/lib.rs @@ -0,0 +1,117 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This crate provides procedural macros for usage within the context of the Substrate runtime +//! interface. +//! +//! The following macros are provided: +//! +//! 1. The [`#[runtime_interface]`](attr.runtime_interface.html) attribute macro for generating the +//! runtime interfaces. +//! 2. The [`PassByCodec`](derive.PassByCodec.html) derive macro for implementing `PassBy` with +//! `Codec`. +//! 3. The [`PassByEnum`](derive.PassByInner.html) derive macro for implementing `PassBy` with +//! `Enum`. +//! 4. The [`PassByInner`](derive.PassByInner.html) derive macro for implementing `PassBy` with +//! `Inner`. + +use syn::{ + DeriveInput, ItemTrait, Result, Token, + parse::{Parse, ParseStream}, + parse_macro_input, +}; + +mod pass_by; +mod runtime_interface; +mod utils; + +struct Options { + wasm_only: bool, + tracing: bool, +} + +impl Options { + fn unpack(self) -> (bool, bool) { + (self.wasm_only, self.tracing) + } +} +impl Default for Options { + fn default() -> Self { + Options { + wasm_only: false, + tracing: true, + } + } +} + +impl Parse for Options { + fn parse(input: ParseStream) -> Result { + let mut res = Self::default(); + while !input.is_empty() { + let lookahead = input.lookahead1(); + if lookahead.peek(runtime_interface::keywords::wasm_only) { + let _ = input.parse::(); + res.wasm_only = true; + } else if lookahead.peek(runtime_interface::keywords::no_tracing) { + let _ = input.parse::(); + res.tracing = false; + } else if lookahead.peek(Token![,]) { + let _ = input.parse::(); + } else { + return Err(lookahead.error()); + } + } + Ok(res) + } +} + +#[proc_macro_attribute] +pub fn runtime_interface( + attrs: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + let trait_def = parse_macro_input!(input as ItemTrait); + let (wasm_only, tracing) = parse_macro_input!(attrs as Options).unpack(); + + runtime_interface::runtime_interface_impl(trait_def, wasm_only, tracing) + .unwrap_or_else(|e| e.to_compile_error()) + .into() +} + +#[proc_macro_derive(PassByCodec)] +pub fn pass_by_codec(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + pass_by::codec_derive_impl(input) + .unwrap_or_else(|e| e.to_compile_error()) + .into() +} + +#[proc_macro_derive(PassByInner)] +pub fn pass_by_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + pass_by::inner_derive_impl(input) + .unwrap_or_else(|e| e.to_compile_error()) + .into() +} + +#[proc_macro_derive(PassByEnum)] +pub fn pass_by_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + pass_by::enum_derive_impl(input) + .unwrap_or_else(|e| e.to_compile_error()) + .into() +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/pass_by/codec.rs b/substrate/sp-runtime-interface-proc-macro/src/pass_by/codec.rs new file mode 100644 index 00000000000..984f8f121ec --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/pass_by/codec.rs @@ -0,0 +1,59 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Derive macro implementation of `PassBy` with the associated type set to `Codec`. +//! +//! It is required that the type implements `Encode` and `Decode` from the `parity-scale-codec` +//! crate. + +use crate::utils::{generate_crate_access, generate_runtime_interface_include}; + +use syn::{DeriveInput, Generics, Result, parse_quote}; + +use quote::quote; + +use proc_macro2::TokenStream; + +/// The derive implementation for `PassBy` with `Codec`. +pub fn derive_impl(mut input: DeriveInput) -> Result { + add_trait_bounds(&mut input.generics); + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let crate_include = generate_runtime_interface_include(); + let crate_ = generate_crate_access(); + let ident = input.ident; + + let res = quote! { + const _: () = { + #crate_include + + impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause { + type PassBy = #crate_::pass_by::Codec<#ident>; + } + }; + }; + + Ok(res) +} + +/// Add the `codec::Codec` trait bound to every type parameter. +fn add_trait_bounds(generics: &mut Generics) { + let crate_ = generate_crate_access(); + + generics + .type_params_mut() + .for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::codec::Codec))); +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/pass_by/enum_.rs b/substrate/sp-runtime-interface-proc-macro/src/pass_by/enum_.rs new file mode 100644 index 00000000000..7667a651946 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/pass_by/enum_.rs @@ -0,0 +1,108 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Derive macro implementation of `PassBy` with the associated type set to `Enum`. +//! +//! Besides `PassBy`, `TryFrom` and `From for u8` are implemented for the type. + +use crate::utils::{generate_crate_access, generate_runtime_interface_include}; + +use syn::{Data, DeriveInput, Error, Fields, Ident, Result}; + +use quote::quote; + +use proc_macro2::{Span, TokenStream}; + +/// The derive implementation for `PassBy` with `Enum`. +pub fn derive_impl(input: DeriveInput) -> Result { + let crate_include = generate_runtime_interface_include(); + let crate_ = generate_crate_access(); + let ident = input.ident; + let enum_fields = get_enum_field_idents(&input.data)? + .enumerate() + .map(|(i, v)| { + let i = i as u8; + + v.map(|v| (quote!(#i => Ok(#ident::#v)), quote!(#ident::#v => #i))) + }) + .collect::>>()?; + let try_from_variants = enum_fields.iter().map(|i| &i.0); + let into_variants = enum_fields.iter().map(|i| &i.1); + + let res = quote! { + const _: () = { + #crate_include + + impl #crate_::pass_by::PassBy for #ident { + type PassBy = #crate_::pass_by::Enum<#ident>; + } + + impl TryFrom for #ident { + type Error = (); + + fn try_from(inner: u8) -> core::result::Result { + match inner { + #( #try_from_variants, )* + _ => Err(()), + } + } + } + + impl From<#ident> for u8 { + fn from(var: #ident) -> u8 { + match var { + #( #into_variants ),* + } + } + } + }; + }; + + Ok(res) +} + +/// Get the enum fields idents of the given `data` object as iterator. +/// +/// Returns an error if the number of variants is greater than `256`, the given `data` is not an +/// enum or a variant is not an unit. +fn get_enum_field_idents(data: &Data) -> Result>> { + match data { + Data::Enum(d) => { + if d.variants.len() <= 256 { + Ok(d.variants.iter().map(|v| { + if let Fields::Unit = v.fields { + Ok(&v.ident) + } else { + Err(Error::new( + Span::call_site(), + "`PassByEnum` only supports unit variants.", + )) + } + })) + } else { + Err(Error::new( + Span::call_site(), + "`PassByEnum` only supports `256` variants.", + )) + } + } + _ => Err(Error::new( + Span::call_site(), + "`PassByEnum` only supports enums as input type.", + )), + } +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/pass_by/inner.rs b/substrate/sp-runtime-interface-proc-macro/src/pass_by/inner.rs new file mode 100644 index 00000000000..2afdd3deab5 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/pass_by/inner.rs @@ -0,0 +1,110 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Derive macro implementation of `PassBy` with the associated type set to `Inner` and of the +//! helper trait `PassByInner`. +//! +//! It is required that the type is a newtype struct, otherwise an error is generated. + +use crate::utils::{generate_crate_access, generate_runtime_interface_include}; + +use syn::{Data, DeriveInput, Error, Fields, Generics, Ident, Result, Type, parse_quote}; + +use quote::quote; + +use proc_macro2::{Span, TokenStream}; + +/// The derive implementation for `PassBy` with `Inner` and `PassByInner`. +pub fn derive_impl(mut input: DeriveInput) -> Result { + add_trait_bounds(&mut input.generics); + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let crate_include = generate_runtime_interface_include(); + let crate_ = generate_crate_access(); + let ident = input.ident; + let (inner_ty, inner_name) = extract_inner_ty_and_name(&input.data)?; + + let access_inner = match inner_name { + Some(ref name) => quote!(self.#name), + None => quote!(self.0), + }; + + let from_inner = match inner_name { + Some(name) => quote!(Self { #name: inner }), + None => quote!(Self(inner)), + }; + + let res = quote! { + const _: () = { + #crate_include + + impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause { + type PassBy = #crate_::pass_by::Inner; + } + + impl #impl_generics #crate_::pass_by::PassByInner for #ident #ty_generics #where_clause { + type Inner = #inner_ty; + + fn into_inner(self) -> Self::Inner { + #access_inner + } + + fn inner(&self) -> &Self::Inner { + &#access_inner + } + + fn from_inner(inner: Self::Inner) -> Self { + #from_inner + } + } + }; + }; + + Ok(res) +} + +/// Add the `RIType` trait bound to every type parameter. +fn add_trait_bounds(generics: &mut Generics) { + let crate_ = generate_crate_access(); + + generics + .type_params_mut() + .for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::RIType))); +} + +/// Extract the inner type and optional name from given input data. +/// +/// It also checks that the input data is a newtype struct. +fn extract_inner_ty_and_name(data: &Data) -> Result<(Type, Option)> { + if let Data::Struct(struct_data) = data { + match &struct_data.fields { + Fields::Named(named) if named.named.len() == 1 => { + let field = &named.named[0]; + return Ok((field.ty.clone(), field.ident.clone())); + } + Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => { + let field = &unnamed.unnamed[0]; + return Ok((field.ty.clone(), field.ident.clone())); + } + _ => {} + } + } + + Err(Error::new( + Span::call_site(), + "Only newtype/one field structs are supported by `PassByInner`!", + )) +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/pass_by/mod.rs b/substrate/sp-runtime-interface-proc-macro/src/pass_by/mod.rs new file mode 100644 index 00000000000..f3d51d36248 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/pass_by/mod.rs @@ -0,0 +1,26 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! All the `PassBy*` derive implementations. + +mod codec; +mod enum_; +mod inner; + +pub use self::codec::derive_impl as codec_derive_impl; +pub use enum_::derive_impl as enum_derive_impl; +pub use inner::derive_impl as inner_derive_impl; diff --git a/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/bare_function_interface.rs b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/bare_function_interface.rs new file mode 100644 index 00000000000..d206c3f2497 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/bare_function_interface.rs @@ -0,0 +1,287 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Generates the bare function interface for a given trait definition. +//! +//! The bare functions are the ones that will be called by the user. On the native/host side, these +//! functions directly execute the provided implementation. On the wasm side, these +//! functions will prepare the parameters for the FFI boundary, call the external host function +//! exported into wasm and convert back the result. +//! +//! [`generate`] is the entry point for generating for each +//! trait method one bare function. +//! +//! [`function_for_method`] generates the bare +//! function per trait method. Each bare function contains both implementations. The implementations +//! are feature-gated, so that one is compiled for the native and the other for the wasm side. + +use crate::utils::{ + RuntimeInterfaceFunction, create_exchangeable_host_function_ident, + create_function_ident_with_version, generate_crate_access, get_function_argument_names, + get_function_arguments, get_runtime_interface, +}; + +use syn::{ + FnArg, Ident, ItemTrait, Result, Signature, Token, TraitItemFn, parse_quote, spanned::Spanned, +}; + +use proc_macro2::{Span, TokenStream}; + +use quote::{quote, quote_spanned}; + +use std::iter; + +/// Generate one bare function per trait method. The name of the bare function is equal to the name +/// of the trait method. +pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool, tracing: bool) -> Result { + let trait_name = &trait_def.ident; + let runtime_interface = get_runtime_interface(trait_def)?; + + // latest version dispatch + let token_stream: Result = runtime_interface.latest_versions_to_call().try_fold( + TokenStream::new(), + |mut t, (latest_version, method)| { + t.extend(function_for_method(method, latest_version, is_wasm_only)?); + Ok(t) + }, + ); + + // earlier versions compatibility dispatch (only std variant) + let result: Result = + runtime_interface + .all_versions() + .try_fold(token_stream?, |mut t, (version, method)| { + t.extend(function_std_impl( + trait_name, + method, + version, + is_wasm_only, + tracing, + )?); + Ok(t) + }); + + result +} + +/// Generates the bare function implementation for the given method for the host and wasm side. +fn function_for_method( + method: &RuntimeInterfaceFunction, + latest_version: u32, + is_wasm_only: bool, +) -> Result { + let std_impl = if !is_wasm_only { + function_std_latest_impl(method, latest_version)? + } else { + quote!() + }; + + let no_std_impl = function_no_std_impl(method, is_wasm_only)?; + + Ok(quote! { + #std_impl + + #no_std_impl + }) +} + +/// Generates the bare function implementation for `cfg(not(feature = "std"))`. +fn function_no_std_impl( + method: &RuntimeInterfaceFunction, + is_wasm_only: bool, +) -> Result { + let function_name = &method.sig.ident; + let host_function_name = create_exchangeable_host_function_ident(&method.sig.ident); + let args = get_function_arguments(&method.sig); + let arg_names = get_function_argument_names(&method.sig); + let return_value = if method.should_trap_on_return() { + syn::ReturnType::Type( + ]>::default(), + Box::new( + syn::TypeNever { + bang_token: ::default(), + } + .into(), + ), + ) + } else { + method.sig.output.clone() + }; + let maybe_unreachable = if method.should_trap_on_return() { + quote! { + ; + #[cfg(target_family = "wasm")] + { core::arch::wasm32::unreachable(); } + + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + unsafe { core::arch::asm!("unimp", options(noreturn)); } + } + } else { + quote! {} + }; + + let attrs = method + .attrs + .iter() + .filter(|a| !a.path().is_ident("version")); + + let cfg_wasm_only = if is_wasm_only { + quote! { #[cfg(substrate_runtime)] } + } else { + quote! {} + }; + + Ok(quote! { + #cfg_wasm_only + #[cfg(not(feature = "std"))] + #( #attrs )* + pub fn #function_name( #( #args, )* ) #return_value { + // Call the host function + #host_function_name.get()( #( #arg_names, )* ) + #maybe_unreachable + } + }) +} + +/// Generate call to latest function version for `cfg((feature = "std")` +/// +/// This should generate simple `fn func(..) { func_version_(..) }`. +fn function_std_latest_impl(method: &TraitItemFn, latest_version: u32) -> Result { + let function_name = &method.sig.ident; + let args = get_function_arguments(&method.sig).map(FnArg::Typed); + let arg_names = get_function_argument_names(&method.sig).collect::>(); + let return_value = &method.sig.output; + let attrs = method + .attrs + .iter() + .filter(|a| !a.path().is_ident("version")); + let latest_function_name = + create_function_ident_with_version(&method.sig.ident, latest_version); + + Ok(quote_spanned! { method.span() => + #[cfg(feature = "std")] + #( #attrs )* + pub fn #function_name( #( #args, )* ) #return_value { + #latest_function_name( + #( #arg_names, )* + ) + } + }) +} + +/// Generates the bare function implementation for `cfg(feature = "std")`. +fn function_std_impl( + trait_name: &Ident, + method: &TraitItemFn, + version: u32, + is_wasm_only: bool, + tracing: bool, +) -> Result { + let function_name = create_function_ident_with_version(&method.sig.ident, version); + let function_name_str = function_name.to_string(); + + let crate_ = generate_crate_access(); + let args = get_function_arguments(&method.sig).map(FnArg::Typed).chain( + // Add the function context as last parameter when this is a wasm only interface. + iter::from_fn(|| { + if is_wasm_only { + Some(parse_quote!( + mut __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext + )) + } else { + None + } + }) + .take(1), + ); + let return_value = &method.sig.output; + let attrs = method + .attrs + .iter() + .filter(|a| !a.path().is_ident("version")); + // Don't make the function public accessible when this is a wasm only interface. + let call_to_trait = generate_call_to_trait(trait_name, method, version, is_wasm_only); + let call_to_trait = if !tracing { + call_to_trait + } else { + parse_quote!( + #crate_::sp_tracing::within_span! { #crate_::sp_tracing::trace_span!(#function_name_str); + #call_to_trait + } + ) + }; + + Ok(quote_spanned! { method.span() => + #[cfg(feature = "std")] + #( #attrs )* + fn #function_name( #( #args, )* ) #return_value { + #call_to_trait + } + }) +} + +/// Generate the call to the interface trait. +fn generate_call_to_trait( + trait_name: &Ident, + method: &TraitItemFn, + version: u32, + is_wasm_only: bool, +) -> TokenStream { + let crate_ = generate_crate_access(); + let method_name = create_function_ident_with_version(&method.sig.ident, version); + let expect_msg = format!( + "`{}` called outside of an Externalities-provided environment.", + method_name + ); + let arg_names = get_function_argument_names(&method.sig); + + if takes_self_argument(&method.sig) { + let instance = if is_wasm_only { + Ident::new("__function_context__", Span::call_site()) + } else { + Ident::new("__externalities__", Span::call_site()) + }; + + let impl_ = quote!( #trait_name::#method_name(&mut #instance, #( #arg_names, )*) ); + + if is_wasm_only { + quote_spanned! { method.span() => #impl_ } + } else { + quote_spanned! { method.span() => + #crate_::with_externalities(|mut #instance| #impl_).expect(#expect_msg) + } + } + } else { + // The name of the trait the interface trait is implemented for + let impl_trait_name = if is_wasm_only { + quote!( #crate_::sp_wasm_interface::FunctionContext ) + } else { + quote!( #crate_::Externalities ) + }; + + quote_spanned! { method.span() => + <&mut dyn #impl_trait_name as #trait_name>::#method_name( + #( #arg_names, )* + ) + } + } +} + +/// Returns if the given `Signature` takes a `self` argument. +fn takes_self_argument(sig: &Signature) -> bool { + matches!(sig.inputs.first(), Some(FnArg::Receiver(_))) +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/host_function_interface.rs b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/host_function_interface.rs new file mode 100644 index 00000000000..48fb11aefdf --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/host_function_interface.rs @@ -0,0 +1,483 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Generates the extern host functions and the implementation for these host functions. +//! +//! The extern host functions will be called by the bare function interface from the Wasm side. +//! The implementation of these host functions will be called on the host side from the Wasm +//! executor. These implementations call the bare function interface. + +use crate::utils::{ + RuntimeInterface, RuntimeInterfaceFunction, create_exchangeable_host_function_ident, + create_function_ident_with_version, create_host_function_ident, generate_crate_access, + get_function_argument_names, get_function_argument_names_and_types_without_ref, + get_function_argument_types, get_function_argument_types_ref_and_mut, + get_function_argument_types_without_ref, get_function_arguments, get_runtime_interface, +}; + +use syn::{ + Error, Ident, ItemTrait, Pat, Result, ReturnType, Signature, TraitItemFn, spanned::Spanned, +}; + +use proc_macro2::{Span, TokenStream}; + +use quote::quote; + +use inflector::Inflector; + +use std::iter::Iterator; + +/// Generate the extern host functions for wasm and the `HostFunctions` struct that provides the +/// implementations for the host functions on the host. +pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool) -> Result { + let trait_name = &trait_def.ident; + let interface = get_runtime_interface(trait_def)?; + let extern_host_function_impls = interface.latest_versions_to_call().try_fold( + TokenStream::new(), + |mut t, (version, method)| { + t.extend(generate_extern_host_function(method, version, trait_name)?); + Ok::<_, Error>(t) + }, + )?; + let exchangeable_host_functions = + interface + .latest_versions_to_call() + .try_fold(TokenStream::new(), |mut t, (_, m)| { + t.extend(generate_exchangeable_host_function(m)?); + Ok::<_, Error>(t) + })?; + let host_functions_struct = + generate_host_functions_struct(trait_def, &interface, is_wasm_only)?; + + Ok(quote! { + /// The implementations of the extern host functions. This special implementation module + /// is required to change the extern host functions signature to + /// `unsafe fn name(args) -> ret` to make the function implementations exchangeable. + #[cfg(not(feature = "std"))] + mod extern_host_function_impls { + use super::*; + + #extern_host_function_impls + } + + #exchangeable_host_functions + + #host_functions_struct + }) +} + +/// Generate the extern host function for the given method. +fn generate_extern_host_function( + method: &TraitItemFn, + version: u32, + trait_name: &Ident, +) -> Result { + let crate_ = generate_crate_access(); + let args = get_function_arguments(&method.sig); + let arg_types = get_function_argument_types_without_ref(&method.sig); + let arg_types2 = get_function_argument_types_without_ref(&method.sig); + let arg_names = get_function_argument_names(&method.sig); + let arg_names2 = get_function_argument_names(&method.sig); + let arg_names3 = get_function_argument_names(&method.sig); + let function = &method.sig.ident; + let ext_function = create_host_function_ident(&method.sig.ident, version, trait_name); + let doc_string = format!( + " Default extern host function implementation for [`super::{}`].", + method.sig.ident, + ); + let return_value = &method.sig.output; + let cfg_attrs = method.attrs.iter().filter(|a| a.path().is_ident("cfg")); + + let ffi_return_value = match &method.sig.output { + ReturnType::Default => quote!(), + ReturnType::Type(_, ty) => quote! { + -> <#ty as #crate_::RIType>::FFIType + }, + }; + + let convert_return_value = match return_value { + ReturnType::Default => quote!(), + ReturnType::Type(_, ty) => quote! { + <#ty as #crate_::wasm::FromFFIValue>::from_ffi_value(result) + }, + }; + + Ok(quote! { + #(#cfg_attrs)* + #[doc = #doc_string] + pub fn #function ( #( #args ),* ) #return_value { + #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #crate_::polkavm::polkavm_import(abi = #crate_::polkavm::polkavm_abi))] + unsafe extern "C" { + pub fn #ext_function ( + #( #arg_names: <#arg_types as #crate_::RIType>::FFIType ),* + ) #ffi_return_value; + } + + // Generate all wrapped ffi values. + #( + let #arg_names2 = <#arg_types2 as #crate_::wasm::IntoFFIValue>::into_ffi_value( + &#arg_names2, + ); + )* + + let result = unsafe { #ext_function( #( #arg_names3.get() ),* ) }; + + #convert_return_value + } + }) +} + +/// Generate the host exchangeable function for the given method. +fn generate_exchangeable_host_function(method: &TraitItemFn) -> Result { + let crate_ = generate_crate_access(); + let arg_types = get_function_argument_types(&method.sig); + let function = &method.sig.ident; + let exchangeable_function = create_exchangeable_host_function_ident(&method.sig.ident); + let doc_string = format!( + " Exchangeable host function used by [`{}`].", + method.sig.ident + ); + let output = &method.sig.output; + let cfg_attrs = method.attrs.iter().filter(|a| a.path().is_ident("cfg")); + + Ok(quote! { + #(#cfg_attrs)* + #[cfg(not(feature = "std"))] + #[allow(non_upper_case_globals)] + #[doc = #doc_string] + pub static #exchangeable_function : #crate_::wasm::ExchangeableFunction< + fn ( #( #arg_types ),* ) #output + > = #crate_::wasm::ExchangeableFunction::new(extern_host_function_impls::#function); + }) +} + +/// Generate the `HostFunctions` struct that implements `wasm-interface::HostFunctions` to provide +/// implementations for the extern host functions. +fn generate_host_functions_struct( + trait_def: &ItemTrait, + interface: &RuntimeInterface, + is_wasm_only: bool, +) -> Result { + let crate_ = generate_crate_access(); + + let mut host_function_impls = Vec::new(); + let mut register_bodies = Vec::new(); + let mut append_hf_bodies = Vec::new(); + + for (version, method) in interface.all_versions() { + let (implementation, register_body, append_hf_body) = + generate_host_function_implementation(&trait_def.ident, method, version, is_wasm_only)?; + host_function_impls.push(implementation); + register_bodies.push(register_body); + append_hf_bodies.push(append_hf_body); + } + + Ok(quote! { + #(#host_function_impls)* + + /// Provides implementations for the extern host functions. + #[cfg(feature = "std")] + pub struct HostFunctions; + + #[cfg(feature = "std")] + impl #crate_::sp_wasm_interface::HostFunctions for HostFunctions { + fn host_functions() -> Vec<&'static dyn #crate_::sp_wasm_interface::Function> { + let mut host_functions_list = Vec::new(); + #(#append_hf_bodies)* + host_functions_list + } + + #crate_::sp_wasm_interface::if_wasmtime_is_enabled! { + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where T: #crate_::sp_wasm_interface::HostFunctionRegistry + { + #(#register_bodies)* + Ok(()) + } + } + } + }) +} + +/// Generates the host function struct that implements `wasm_interface::Function` and returns a +/// static reference to this struct. +/// +/// When calling from wasm into the host, we will call the `execute` function that calls the native +/// implementation of the function. +fn generate_host_function_implementation( + trait_name: &Ident, + method: &RuntimeInterfaceFunction, + version: u32, + is_wasm_only: bool, +) -> Result<(TokenStream, TokenStream, TokenStream)> { + let name = create_host_function_ident(&method.sig.ident, version, trait_name).to_string(); + let struct_name = Ident::new(&name.to_pascal_case(), Span::call_site()); + let crate_ = generate_crate_access(); + let signature = generate_wasm_interface_signature_for_host_function(&method.sig)?; + + let fn_name = create_function_ident_with_version(&method.sig.ident, version); + let ref_and_mut = get_function_argument_types_ref_and_mut(&method.sig); + + // List of variable names containing WASM FFI-compatible arguments. + let mut ffi_names = Vec::new(); + + // List of `$name: $ty` tokens containing WASM FFI-compatible arguments. + let mut ffi_args_prototype = Vec::new(); + + // List of variable names containing arguments already converted into native Rust types. + // Also includes the preceding `&` or `&mut`. To be used to call the actual implementation of + // the host function. + let mut host_names_with_ref = Vec::new(); + + // List of code snippets to copy over the results returned from a host function through + // any `&mut` arguments back into WASM's linear memory. + let mut copy_data_into_ref_mut_args = Vec::new(); + + // List of code snippets to convert dynamic FFI args (`Value` enum) into concrete static FFI + // types (`u32`, etc.). + let mut convert_args_dynamic_ffi_to_static_ffi = Vec::new(); + + // List of code snippets to convert static FFI args (`u32`, etc.) into native Rust types. + let mut convert_args_static_ffi_to_host = Vec::new(); + + for ((host_name, host_ty), ref_and_mut) in + get_function_argument_names_and_types_without_ref(&method.sig).zip(ref_and_mut) + { + let ffi_name = generate_ffi_value_var_name(&host_name)?; + let host_name_ident = match *host_name { + Pat::Ident(ref pat_ident) => pat_ident.ident.clone(), + _ => unreachable!( + "`generate_ffi_value_var_name` above would return an error on `Pat` != `Ident`; qed" + ), + }; + + let ffi_ty = quote! { <#host_ty as #crate_::RIType>::FFIType }; + ffi_args_prototype.push(quote! { #ffi_name: #ffi_ty }); + ffi_names.push(quote! { #ffi_name }); + + let convert_arg_error = format!( + "could not marshal the '{}' argument through the WASM FFI boundary while executing '{}' from interface '{}'", + host_name_ident, method.sig.ident, trait_name + ); + convert_args_static_ffi_to_host.push(quote! { + let mut #host_name = <#host_ty as #crate_::host::FromFFIValue>::from_ffi_value(__function_context__, #ffi_name) + .map_err(|err| format!("{}: {}", err, #convert_arg_error))?; + }); + + let ref_and_mut_tokens = + ref_and_mut.map(|(token_ref, token_mut)| quote!(#token_ref #token_mut)); + + host_names_with_ref.push(quote! { #ref_and_mut_tokens #host_name }); + + if ref_and_mut + .map(|(_, token_mut)| token_mut.is_some()) + .unwrap_or(false) + { + copy_data_into_ref_mut_args.push(quote! { + <#host_ty as #crate_::host::IntoPreallocatedFFIValue>::into_preallocated_ffi_value( + #host_name, + __function_context__, + #ffi_name, + )?; + }); + } + + let arg_count_mismatch_error = format!( + "missing argument '{}': number of arguments given to '{}' from interface '{}' does not match the expected number of arguments", + host_name_ident, method.sig.ident, trait_name + ); + convert_args_dynamic_ffi_to_static_ffi.push(quote! { + let #ffi_name = args.next().ok_or_else(|| #arg_count_mismatch_error.to_owned())?; + let #ffi_name: #ffi_ty = #crate_::sp_wasm_interface::TryFromValue::try_from_value(#ffi_name) + .ok_or_else(|| #convert_arg_error.to_owned())?; + }); + } + + let ffi_return_ty = match &method.sig.output { + ReturnType::Type(_, ty) => quote! { <#ty as #crate_::RIType>::FFIType }, + ReturnType::Default => quote! { () }, + }; + + let convert_return_value_host_to_static_ffi = match &method.sig.output { + ReturnType::Type(_, ty) => quote! { + let __result__ = <#ty as #crate_::host::IntoFFIValue>::into_ffi_value( + __result__, + __function_context__ + ); + }, + ReturnType::Default => quote! { + let __result__ = Ok(__result__); + }, + }; + + let convert_return_value_static_ffi_to_dynamic_ffi = match &method.sig.output { + ReturnType::Type(_, _) => quote! { + let __result__ = Ok(Some(#crate_::sp_wasm_interface::IntoValue::into_value(__result__))); + }, + ReturnType::Default => quote! { + let __result__ = Ok(None); + }, + }; + + if is_wasm_only { + host_names_with_ref.push(quote! { + __function_context__ + }); + } + + let cfg_attrs: Vec<_> = method + .attrs + .iter() + .filter(|a| a.path().is_ident("cfg")) + .cloned() + .collect(); + if version > 1 && !cfg_attrs.is_empty() { + return Err(Error::new( + method.span(), + "Conditional compilation is not supported for versioned functions", + )); + } + + let implementation = quote! { + #(#cfg_attrs)* + #[cfg(feature = "std")] + struct #struct_name; + + #(#cfg_attrs)* + #[cfg(feature = "std")] + impl #struct_name { + fn call( + __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, + #(#ffi_args_prototype),* + ) -> std::result::Result<#ffi_return_ty, String> { + #(#convert_args_static_ffi_to_host)* + let __result__ = #fn_name(#(#host_names_with_ref),*); + #(#copy_data_into_ref_mut_args)* + #convert_return_value_host_to_static_ffi + __result__ + } + } + + #(#cfg_attrs)* + #[cfg(feature = "std")] + impl #crate_::sp_wasm_interface::Function for #struct_name { + fn name(&self) -> &str { + #name + } + + fn signature(&self) -> #crate_::sp_wasm_interface::Signature { + #signature + } + + fn execute( + &self, + __function_context__: &mut dyn #crate_::sp_wasm_interface::FunctionContext, + args: &mut dyn Iterator, + ) -> std::result::Result, String> { + #(#convert_args_dynamic_ffi_to_static_ffi)* + let __result__ = Self::call( + __function_context__, + #(#ffi_names),* + )?; + #convert_return_value_static_ffi_to_dynamic_ffi + __result__ + } + } + }; + + let register_body = quote! { + #(#cfg_attrs)* + registry.register_static( + #crate_::sp_wasm_interface::Function::name(&#struct_name), + |mut caller: #crate_::sp_wasm_interface::wasmtime::Caller, #(#ffi_args_prototype),*| + -> std::result::Result<#ffi_return_ty, #crate_::sp_wasm_interface::wasmtime::Error> + { + T::with_function_context(caller, move |__function_context__| { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + #struct_name::call( + __function_context__, + #(#ffi_names,)* + ).map_err(#crate_::sp_wasm_interface::wasmtime::Error::msg) + })); + match result { + Ok(result) => result, + Err(panic) => { + let message = + if let Some(message) = panic.downcast_ref::() { + format!("host code panicked while being called by the runtime: {}", message) + } else if let Some(message) = panic.downcast_ref::<&'static str>() { + format!("host code panicked while being called by the runtime: {}", message) + } else { + "host code panicked while being called by the runtime".to_owned() + }; + return Err(#crate_::sp_wasm_interface::wasmtime::Error::msg(message)); + } + } + }) + } + )?; + }; + + let append_hf_body = quote! { + #(#cfg_attrs)* + host_functions_list.push(&#struct_name as &dyn #crate_::sp_wasm_interface::Function); + }; + + Ok((implementation, register_body, append_hf_body)) +} + +/// Generate the `wasm_interface::Signature` for the given host function `sig`. +fn generate_wasm_interface_signature_for_host_function(sig: &Signature) -> Result { + let crate_ = generate_crate_access(); + let return_value = match &sig.output { + ReturnType::Type(_, ty) => quote! { + Some( <<#ty as #crate_::RIType>::FFIType as #crate_::sp_wasm_interface::IntoValue>::VALUE_TYPE ) + }, + ReturnType::Default => quote!(None), + }; + let arg_types = get_function_argument_types_without_ref(sig).map(|ty| { + quote! { + <<#ty as #crate_::RIType>::FFIType as #crate_::sp_wasm_interface::IntoValue>::VALUE_TYPE + } + }); + + Ok(quote! { + #crate_::sp_wasm_interface::Signature { + args: std::borrow::Cow::Borrowed(&[ #( #arg_types ),* ][..]), + return_value: #return_value, + } + }) +} + +/// Generate the variable name that stores the FFI value. +fn generate_ffi_value_var_name(pat: &Pat) -> Result { + match pat { + Pat::Ident(pat_ident) => { + if let Some(by_ref) = pat_ident.by_ref { + Err(Error::new(by_ref.span(), "`ref` not supported!")) + } else if let Some(sub_pattern) = &pat_ident.subpat { + Err(Error::new(sub_pattern.0.span(), "Not supported!")) + } else { + Ok(Ident::new( + &format!("{}_ffi_value", pat_ident.ident), + Span::call_site(), + )) + } + } + _ => Err(Error::new(pat.span(), "Not supported as variable name!")), + } +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/mod.rs b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/mod.rs new file mode 100644 index 00000000000..ded55af592c --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/mod.rs @@ -0,0 +1,81 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::utils::generate_runtime_interface_include; + +use proc_macro2::{Span, TokenStream}; + +use syn::{Ident, ItemTrait, Result}; + +use inflector::Inflector; + +use quote::quote; + +mod bare_function_interface; +mod host_function_interface; +mod trait_decl_impl; + +/// Custom keywords supported by the `runtime_interface` attribute. +pub mod keywords { + // Custom keyword `wasm_only` that can be given as attribute to [`runtime_interface`]. + syn::custom_keyword!(wasm_only); + // Disable tracing-macros added to the [`runtime_interface`] by specifying this optional entry + syn::custom_keyword!(no_tracing); +} + +/// Implementation of the `runtime_interface` attribute. +/// +/// It expects the trait definition the attribute was put above and if this should be an wasm only +/// interface. +pub fn runtime_interface_impl( + trait_def: ItemTrait, + is_wasm_only: bool, + tracing: bool, +) -> Result { + let bare_functions = bare_function_interface::generate(&trait_def, is_wasm_only, tracing)?; + let crate_include = generate_runtime_interface_include(); + let mod_name = Ident::new( + &trait_def.ident.to_string().to_snake_case(), + Span::call_site(), + ); + let trait_decl_impl = trait_decl_impl::process(&trait_def, is_wasm_only)?; + let host_functions = host_function_interface::generate(&trait_def, is_wasm_only)?; + let vis = trait_def.vis; + let attrs = &trait_def.attrs; + + let res = quote! { + #( #attrs )* + #vis mod #mod_name { + use super::*; + #crate_include + + #bare_functions + + #trait_decl_impl + + #host_functions + } + }; + + let res = expander::Expander::new("runtime_interface") + .dry(std::env::var("EXPAND_MACROS").is_err()) + .verbose(true) + .write_to_out_dir(res) + .expect("Does not fail because of IO in OUT_DIR; qed"); + + Ok(res) +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/trait_decl_impl.rs b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/trait_decl_impl.rs new file mode 100644 index 00000000000..a6ca530c675 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/runtime_interface/trait_decl_impl.rs @@ -0,0 +1,186 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Checks the trait declaration, makes the trait declaration module local, removes all method +//! default implementations and implements the trait for `&mut dyn Externalities`. + +use crate::utils::{ + RuntimeInterface, create_function_ident_with_version, generate_crate_access, + get_function_argument_types_without_ref, get_runtime_interface, +}; + +use syn::{ + Error, Generics, ItemTrait, Receiver, Result, TraitItemFn, Type, Visibility, + fold::{self, Fold}, + spanned::Spanned, +}; + +use proc_macro2::TokenStream; + +use quote::quote; + +/// Process the given trait definition, by checking that the definition is valid, fold it to the +/// essential definition and implement this essential definition for `dyn Externalities`. +pub fn process(trait_def: &ItemTrait, is_wasm_only: bool) -> Result { + let interface = get_runtime_interface(trait_def)?; + let impl_trait = impl_trait_for_externalities(trait_def, &interface, is_wasm_only)?; + let essential_trait_def = declare_essential_trait(trait_def, &interface)?; + + Ok(quote! { + #impl_trait + + #essential_trait_def + }) +} + +/// Converts the given trait definition into the essential trait definition without method +/// default implementations and visibility set to inherited. +struct ToEssentialTraitDef { + /// All errors found while doing the conversion. + errors: Vec, + methods: Vec, +} + +impl ToEssentialTraitDef { + fn new() -> Self { + ToEssentialTraitDef { + errors: vec![], + methods: vec![], + } + } + + fn into_methods(self) -> Result> { + let mut errors = self.errors; + let methods = self.methods; + if let Some(first_error) = errors.pop() { + Err(errors.into_iter().fold(first_error, |mut o, n| { + o.combine(n); + o + })) + } else { + Ok(methods) + } + } + + fn process(&mut self, method: &TraitItemFn, version: u32) { + let mut folded = self.fold_trait_item_fn(method.clone()); + folded.sig.ident = create_function_ident_with_version(&folded.sig.ident, version); + self.methods.push(folded); + } + + fn push_error(&mut self, span: &S, msg: &str) { + self.errors.push(Error::new(span.span(), msg)); + } + + fn error_on_generic_parameters(&mut self, generics: &Generics) { + if let Some(param) = generics.params.first() { + self.push_error(param, "Generic parameters not supported."); + } + } +} + +impl Fold for ToEssentialTraitDef { + fn fold_trait_item_fn(&mut self, mut method: TraitItemFn) -> TraitItemFn { + if method.default.take().is_none() { + self.push_error(&method, "Methods need to have an implementation."); + } + + let arg_types = get_function_argument_types_without_ref(&method.sig); + arg_types + .filter_map(|ty| match *ty { + Type::ImplTrait(impl_trait) => Some(impl_trait), + _ => None, + }) + .for_each(|invalid| self.push_error(&invalid, "`impl Trait` syntax not supported.")); + + self.error_on_generic_parameters(&method.sig.generics); + + method.attrs.retain(|a| !a.path().is_ident("version")); + + fold::fold_trait_item_fn(self, method) + } + + fn fold_item_trait(&mut self, mut trait_def: ItemTrait) -> ItemTrait { + self.error_on_generic_parameters(&trait_def.generics); + + trait_def.vis = Visibility::Inherited; + fold::fold_item_trait(self, trait_def) + } + + fn fold_receiver(&mut self, receiver: Receiver) -> Receiver { + if receiver.reference.is_none() { + self.push_error(&receiver, "Taking `Self` by value is not allowed."); + } + + fold::fold_receiver(self, receiver) + } +} + +fn declare_essential_trait( + trait_def: &ItemTrait, + interface: &RuntimeInterface, +) -> Result { + let trait_ = &trait_def.ident; + + if let Some(param) = trait_def.generics.params.first() { + return Err(Error::new( + param.span(), + "Generic parameters not supported.", + )); + } + + let mut folder = ToEssentialTraitDef::new(); + for (version, interface_method) in interface.all_versions() { + folder.process(interface_method, version); + } + let methods = folder.into_methods()?; + + Ok(quote! { + trait #trait_ { + #( #methods )* + } + }) +} + +/// Implements the given trait definition for `dyn Externalities`. +fn impl_trait_for_externalities( + trait_def: &ItemTrait, + interface: &RuntimeInterface, + is_wasm_only: bool, +) -> Result { + let trait_ = &trait_def.ident; + let crate_ = generate_crate_access(); + let methods = interface.all_versions().map(|(version, method)| { + let mut cloned = (*method).clone(); + cloned.attrs.retain(|a| !a.path().is_ident("version")); + cloned.sig.ident = create_function_ident_with_version(&cloned.sig.ident, version); + cloned + }); + + let impl_type = if is_wasm_only { + quote!( &mut dyn #crate_::sp_wasm_interface::FunctionContext ) + } else { + quote!( &mut dyn #crate_::Externalities ) + }; + + Ok(quote! { + #[cfg(feature = "std")] + impl #trait_ for #impl_type { + #( #methods )* + } + }) +} diff --git a/substrate/sp-runtime-interface-proc-macro/src/utils.rs b/substrate/sp-runtime-interface-proc-macro/src/utils.rs new file mode 100644 index 00000000000..9eb685939b7 --- /dev/null +++ b/substrate/sp-runtime-interface-proc-macro/src/utils.rs @@ -0,0 +1,396 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Util function used by this crate. + +use proc_macro2::{Span, TokenStream}; + +use syn::{ + Error, FnArg, Ident, ItemTrait, LitInt, Pat, PatType, Result, Signature, TraitItem, + TraitItemFn, Type, parse::Parse, parse_quote, spanned::Spanned, token, +}; + +use proc_macro_crate::{FoundCrate, crate_name}; + +use std::{ + collections::{BTreeMap, btree_map::Entry}, + env, +}; + +use quote::quote; + +use inflector::Inflector; + +mod attributes { + syn::custom_keyword!(register_only); +} + +/// A concrete, specific version of a runtime interface function. +pub struct RuntimeInterfaceFunction { + item: TraitItemFn, + should_trap_on_return: bool, +} + +impl std::ops::Deref for RuntimeInterfaceFunction { + type Target = TraitItemFn; + fn deref(&self) -> &Self::Target { + &self.item + } +} + +impl RuntimeInterfaceFunction { + fn new(item: &TraitItemFn) -> Result { + let mut item = item.clone(); + let mut should_trap_on_return = false; + item.attrs.retain(|attr| { + if attr.path().is_ident("trap_on_return") { + should_trap_on_return = true; + false + } else { + true + } + }); + + if should_trap_on_return && !matches!(item.sig.output, syn::ReturnType::Default) { + return Err(Error::new( + item.sig.ident.span(), + "Methods marked as #[trap_on_return] cannot return anything", + )); + } + + Ok(Self { + item, + should_trap_on_return, + }) + } + + pub fn should_trap_on_return(&self) -> bool { + self.should_trap_on_return + } +} + +/// Runtime interface function with all associated versions of this function. +struct RuntimeInterfaceFunctionSet { + latest_version_to_call: Option, + versions: BTreeMap, +} + +impl RuntimeInterfaceFunctionSet { + fn new(version: VersionAttribute, trait_item: &TraitItemFn) -> Result { + Ok(Self { + latest_version_to_call: version.is_callable().then_some(version.version), + versions: BTreeMap::from([( + version.version, + RuntimeInterfaceFunction::new(trait_item)?, + )]), + }) + } + + /// Returns the latest version of this runtime interface function plus the actual function + /// implementation. + /// + /// This isn't required to be the latest version, because a runtime interface function can be + /// annotated with `register_only` to ensure that the host exposes the host function but it + /// isn't used when compiling the runtime. + pub fn latest_version_to_call(&self) -> Option<(u32, &RuntimeInterfaceFunction)> { + self.latest_version_to_call.map(|v| { + ( + v, + self.versions.get(&v).expect( + "If latest_version_to_call has a value, the key with this value is in the versions; qed", + ), + ) + }) + } + + /// Add a different version of the function. + fn add_version(&mut self, version: VersionAttribute, trait_item: &TraitItemFn) -> Result<()> { + if let Some(existing_item) = self.versions.get(&version.version) { + let mut err = Error::new(trait_item.span(), "Duplicated version attribute"); + err.combine(Error::new( + existing_item.span(), + "Previous version with the same number defined here", + )); + + return Err(err); + } + + self.versions + .insert(version.version, RuntimeInterfaceFunction::new(trait_item)?); + if self + .latest_version_to_call + .is_none_or(|v| v < version.version) + && version.is_callable() + { + self.latest_version_to_call = Some(version.version); + } + + Ok(()) + } +} + +/// All functions of a runtime interface grouped by the function names. +pub struct RuntimeInterface { + items: BTreeMap, +} + +impl RuntimeInterface { + /// Returns an iterator over all runtime interface function + /// [`latest_version_to_call`](RuntimeInterfaceFunctionSet::latest_version). + pub fn latest_versions_to_call( + &self, + ) -> impl Iterator { + self.items + .iter() + .filter_map(|(_, item)| item.latest_version_to_call()) + } + + pub fn all_versions(&self) -> impl Iterator { + self.items + .iter() + .flat_map(|(_, item)| item.versions.iter()) + .map(|(v, i)| (*v, i)) + } +} + +/// Generates the include for the runtime-interface crate. +pub fn generate_runtime_interface_include() -> TokenStream { + match crate_name("sp-runtime-interface") { + Ok(FoundCrate::Itself) => quote!(), + Ok(FoundCrate::Name(crate_name)) => { + let crate_name = Ident::new(&crate_name, Span::call_site()); + quote!( + #[doc(hidden)] + extern crate #crate_name as proc_macro_runtime_interface; + ) + } + Err(e) => { + let err = Error::new(Span::call_site(), e).to_compile_error(); + quote!( #err ) + } + } +} + +/// Generates the access to the `sp-runtime-interface` crate. +pub fn generate_crate_access() -> TokenStream { + if env::var("CARGO_PKG_NAME").unwrap() == "sp-runtime-interface" { + quote!(sp_runtime_interface) + } else { + quote!(proc_macro_runtime_interface) + } +} + +/// Create the exchangeable host function identifier for the given function name. +pub fn create_exchangeable_host_function_ident(name: &Ident) -> Ident { + Ident::new(&format!("host_{}", name), Span::call_site()) +} + +/// Create the host function identifier for the given function name. +pub fn create_host_function_ident(name: &Ident, version: u32, trait_name: &Ident) -> Ident { + Ident::new( + &format!( + "ext_{}_{}_version_{}", + trait_name.to_string().to_snake_case(), + name, + version + ), + Span::call_site(), + ) +} + +/// Create the host function identifier for the given function name. +pub fn create_function_ident_with_version(name: &Ident, version: u32) -> Ident { + Ident::new(&format!("{}_version_{}", name, version), Span::call_site()) +} + +/// Returns the function arguments of the given `Signature`, minus any `self` arguments. +pub fn get_function_arguments(sig: &Signature) -> impl Iterator + '_ { + sig.inputs + .iter() + .filter_map(|a| match a { + FnArg::Receiver(_) => None, + FnArg::Typed(pat_type) => Some(pat_type), + }) + .enumerate() + .map(|(i, arg)| { + let mut res = arg.clone(); + if let Pat::Wild(wild) = &*arg.pat { + let ident = Ident::new( + &format!("__runtime_interface_generated_{}_", i), + wild.span(), + ); + + *res.pat = parse_quote!( #ident ); + } + + res + }) +} + +/// Returns the function argument names of the given `Signature`, minus any `self`. +pub fn get_function_argument_names(sig: &Signature) -> impl Iterator> + '_ { + get_function_arguments(sig).map(|pt| pt.pat) +} + +/// Returns the function argument types of the given `Signature`, minus any `Self` type. +pub fn get_function_argument_types(sig: &Signature) -> impl Iterator> + '_ { + get_function_arguments(sig).map(|pt| pt.ty) +} + +/// Returns the function argument types, minus any `Self` type. If any of the arguments +/// is a reference, the underlying type without the ref is returned. +pub fn get_function_argument_types_without_ref( + sig: &Signature, +) -> impl Iterator> + '_ { + get_function_arguments(sig) + .map(|pt| pt.ty) + .map(|ty| match *ty { + Type::Reference(type_ref) => type_ref.elem, + _ => ty, + }) +} + +/// Returns the function argument names and types, minus any `self`. If any of the arguments +/// is a reference, the underlying type without the ref is returned. +pub fn get_function_argument_names_and_types_without_ref( + sig: &Signature, +) -> impl Iterator, Box)> + '_ { + get_function_arguments(sig).map(|pt| match *pt.ty { + Type::Reference(type_ref) => (pt.pat, type_ref.elem), + _ => (pt.pat, pt.ty), + }) +} + +/// Returns the `&`/`&mut` for all function argument types, minus the `self` arg. If a function +/// argument is not a reference, `None` is returned. +pub fn get_function_argument_types_ref_and_mut( + sig: &Signature, +) -> impl Iterator)>> + '_ { + get_function_arguments(sig) + .map(|pt| pt.ty) + .map(|ty| match *ty { + Type::Reference(type_ref) => Some((type_ref.and_token, type_ref.mutability)), + _ => None, + }) +} + +/// Returns an iterator over all trait methods for the given trait definition. +fn get_trait_methods(trait_def: &ItemTrait) -> impl Iterator { + trait_def.items.iter().filter_map(|i| match i { + TraitItem::Fn(method) => Some(method), + _ => None, + }) +} + +/// The version attribute that can be found above a runtime interface function. +/// +/// Supports the following formats: +/// - `#[version(1)]` +/// - `#[version(1, register_only)]` +/// +/// While this struct is only for parsing the inner parts inside the `()`. +struct VersionAttribute { + version: u32, + register_only: Option, +} + +impl VersionAttribute { + /// Is this function version callable? + fn is_callable(&self) -> bool { + self.register_only.is_none() + } +} + +impl Default for VersionAttribute { + fn default() -> Self { + Self { + version: 1, + register_only: None, + } + } +} + +impl Parse for VersionAttribute { + fn parse(input: syn::parse::ParseStream) -> Result { + let version: LitInt = input.parse()?; + let register_only = if input.peek(token::Comma) { + let _ = input.parse::(); + Some(input.parse()?) + } else { + if !input.is_empty() { + return Err(Error::new(input.span(), "Unexpected token, expected `,`.")); + } + + None + }; + + Ok(Self { + version: version.base10_parse()?, + register_only, + }) + } +} + +/// Return [`VersionAttribute`], if present. +fn get_item_version(item: &TraitItemFn) -> Result> { + item.attrs + .iter() + .find(|attr| attr.path().is_ident("version")) + .map(|attr| attr.parse_args()) + .transpose() +} + +/// Returns all runtime interface members, with versions. +pub fn get_runtime_interface(trait_def: &ItemTrait) -> Result { + let mut functions: BTreeMap = BTreeMap::new(); + + for item in get_trait_methods(trait_def) { + let name = item.sig.ident.clone(); + let version = get_item_version(item)?.unwrap_or_default(); + + if version.version < 1 { + return Err(Error::new(item.span(), "Version needs to be at least `1`.")); + } + + match functions.entry(name.clone()) { + Entry::Vacant(entry) => { + entry.insert(RuntimeInterfaceFunctionSet::new(version, item)?); + } + Entry::Occupied(mut entry) => { + entry.get_mut().add_version(version, item)?; + } + } + } + + for function in functions.values() { + let mut next_expected = 1; + for (version, item) in function.versions.iter() { + if next_expected != *version { + return Err(Error::new( + item.span(), + format!( + "Unexpected version attribute: missing version '{}' for this function", + next_expected + ), + )); + } + next_expected += 1; + } + } + + Ok(RuntimeInterface { items: functions }) +} diff --git a/substrate/sp-wasm-interface-common/Cargo.toml b/substrate/sp-wasm-interface-common/Cargo.toml new file mode 100644 index 00000000000..7776b991c8f --- /dev/null +++ b/substrate/sp-wasm-interface-common/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "sp-wasm-interface-common" +version = "7.0.0" +authors = ["Parity Technologies "] +edition = "2021" +rust-version.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Types and traits for interfacing between the host and the wasm runtime." +documentation = "https://docs.rs/sp-wasm-interface" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { features = ["derive"], workspace = true } +wasmi = { version = "0.13.2", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", default-features = false, optional = true } +sp-std = { workspace = true, default-features = false } + +[features] +default = [ "std" ] +std = [ "codec/std", "sp-std/std", "wasmi/std" ] diff --git a/substrate/sp-wasm-interface-common/README.md b/substrate/sp-wasm-interface-common/README.md new file mode 100644 index 00000000000..7e6c46581ae --- /dev/null +++ b/substrate/sp-wasm-interface-common/README.md @@ -0,0 +1,3 @@ +Types and traits for interfacing between the host and the wasm runtime. + +License: Apache-2.0 \ No newline at end of file diff --git a/substrate/sp-wasm-interface-common/src/lib.rs b/substrate/sp-wasm-interface-common/src/lib.rs new file mode 100644 index 00000000000..7fc46bf0632 --- /dev/null +++ b/substrate/sp-wasm-interface-common/src/lib.rs @@ -0,0 +1,357 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types and traits for interfacing between the host and the wasm runtime. + +#![cfg_attr(not(feature = "std"), no_std)] + +use core::{marker::PhantomData, mem}; +use sp_std::borrow::Cow; + +pub mod util; + +#[cfg(feature = "wasmi")] +pub use wasmi; + +#[cfg(feature = "wasmi")] +pub mod wasmi_impl; + +/// Value types supported by Substrate on the boundary between host/Wasm. +#[derive(Copy, Clone, PartialEq, Debug, Eq)] +pub enum ValueType { + /// An `i32` value type. + I32, + /// An `i64` value type. + I64, + /// An `f32` value type. + F32, + /// An `f64` value type. + F64, +} + +impl From for u8 { + fn from(val: ValueType) -> u8 { + match val { + ValueType::I32 => 0, + ValueType::I64 => 1, + ValueType::F32 => 2, + ValueType::F64 => 3, + } + } +} + +impl TryFrom for ValueType { + type Error = (); + + fn try_from(val: u8) -> core::result::Result { + match val { + 0 => Ok(Self::I32), + 1 => Ok(Self::I64), + 2 => Ok(Self::F32), + 3 => Ok(Self::F64), + _ => Err(()), + } + } +} + +/// Values supported by Substrate on the boundary between host/Wasm. +#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)] +pub enum Value { + /// A 32-bit integer. + I32(i32), + /// A 64-bit integer. + I64(i64), + /// A 32-bit floating-point number stored as raw bit pattern. + /// + /// You can materialize this value using `f32::from_bits`. + F32(u32), + /// A 64-bit floating-point number stored as raw bit pattern. + /// + /// You can materialize this value using `f64::from_bits`. + F64(u64), +} + +impl Value { + /// Returns the type of this value. + pub fn value_type(&self) -> ValueType { + match self { + Value::I32(_) => ValueType::I32, + Value::I64(_) => ValueType::I64, + Value::F32(_) => ValueType::F32, + Value::F64(_) => ValueType::F64, + } + } + + /// Return `Self` as `i32`. + pub fn as_i32(&self) -> Option { + match self { + Self::I32(val) => Some(*val), + _ => None, + } + } +} + +/// Something that can be converted into a wasm compatible `Value`. +pub trait IntoValue { + /// The type of the value in wasm. + const VALUE_TYPE: ValueType; + + /// Convert `self` into a wasm `Value`. + fn into_value(self) -> Value; +} + +/// Something that can be created from a wasm `Value`. +pub trait TryFromValue: Sized { + /// Try to convert the given `Value` into `Self`. + fn try_from_value(val: Value) -> Option; +} + +macro_rules! impl_into_and_from_value { + ( + $( + $type:ty, $( < $gen:ident >, )? $value_variant:ident, + )* + ) => { + $( + impl $( <$gen> )? IntoValue for $type { + const VALUE_TYPE: ValueType = ValueType::$value_variant; + fn into_value(self) -> Value { Value::$value_variant(self as _) } + } + + impl $( <$gen> )? TryFromValue for $type { + fn try_from_value(val: Value) -> Option { + match val { + Value::$value_variant(val) => Some(val as _), + _ => None, + } + } + } + )* + } +} + +impl_into_and_from_value! { + u8, I32, + u16, I32, + u32, I32, + u64, I64, + i8, I32, + i16, I32, + i32, I32, + i64, I64, +} + +/// Provides `Sealed` trait to prevent implementing trait `PointerType` and `WasmTy` outside of this +/// crate. +mod private { + pub trait Sealed {} + + impl Sealed for u8 {} + impl Sealed for u16 {} + impl Sealed for u32 {} + impl Sealed for u64 {} + + impl Sealed for i32 {} + impl Sealed for i64 {} +} + +/// Something that can be wrapped in a wasm `Pointer`. +/// +/// This trait is sealed. +pub trait PointerType: Sized + private::Sealed { + /// The size of the type in wasm. + const SIZE: u32 = mem::size_of::() as u32; +} + +impl PointerType for u8 {} +impl PointerType for u16 {} +impl PointerType for u32 {} +impl PointerType for u64 {} + +/// Type to represent a pointer in wasm at the host. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct Pointer { + ptr: u32, + _marker: PhantomData, +} + +impl Pointer { + /// Create a new instance of `Self`. + pub fn new(ptr: u32) -> Self { + Self { + ptr, + _marker: Default::default(), + } + } + + /// Calculate the offset from this pointer. + /// + /// `offset` is in units of `T`. So, `3` means `3 * mem::size_of::()` as offset to the + /// pointer. + /// + /// Returns an `Option` to respect that the pointer could probably overflow. + pub fn offset(self, offset: u32) -> Option { + offset + .checked_mul(T::SIZE) + .and_then(|o| self.ptr.checked_add(o)) + .map(|ptr| Self { + ptr, + _marker: Default::default(), + }) + } + + /// Create a null pointer. + pub fn null() -> Self { + Self::new(0) + } + + /// Cast this pointer of type `T` to a pointer of type `R`. + pub fn cast(self) -> Pointer { + Pointer::new(self.ptr) + } +} + +impl From for Pointer { + fn from(ptr: u32) -> Self { + Pointer::new(ptr) + } +} + +impl From> for u32 { + fn from(ptr: Pointer) -> Self { + ptr.ptr + } +} + +impl From> for u64 { + fn from(ptr: Pointer) -> Self { + u64::from(ptr.ptr) + } +} + +impl From> for usize { + fn from(ptr: Pointer) -> Self { + ptr.ptr as _ + } +} + +impl IntoValue for Pointer { + const VALUE_TYPE: ValueType = ValueType::I32; + fn into_value(self) -> Value { + Value::I32(self.ptr as _) + } +} + +impl TryFromValue for Pointer { + fn try_from_value(val: Value) -> Option { + match val { + Value::I32(val) => Some(Self::new(val as _)), + _ => None, + } + } +} + +/// The signature of a function. +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct Signature { + /// The arguments of a function. + pub args: Cow<'static, [ValueType]>, + /// The optional return value of a function. + pub return_value: Option, +} + +impl Signature { + /// Create a new instance of `Signature`. + pub fn new>>( + args: T, + return_value: Option, + ) -> Self { + Self { + args: args.into(), + return_value, + } + } + + /// Create a new instance of `Signature` with the given `args` and without any return value. + pub fn new_with_args>>(args: T) -> Self { + Self { + args: args.into(), + return_value: None, + } + } +} + +/// The word size used in wasm. Normally known as `usize` in Rust. +pub type WordSize = u32; + +/// Sandbox memory identifier. +pub type MemoryId = u32; + +/// Host pointer sized for both 32-bit and 64-bit architectures. +pub type HostPointer = u64; + +/// Typed value that can be returned from a function. +/// +/// Basically a `TypedValue` plus `Unit`, for functions which return nothing. +#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)] +pub enum ReturnValue { + /// For returning nothing. + Unit, + /// For returning some concrete value. + Value(Value), +} + +impl From for ReturnValue { + fn from(v: Value) -> ReturnValue { + ReturnValue::Value(v) + } +} + +impl ReturnValue { + /// Maximum number of bytes `ReturnValue` might occupy when serialized with `SCALE`. + /// + /// Breakdown: + /// 1 byte for encoding unit/value variant + /// 1 byte for encoding value type + /// 8 bytes for encoding the biggest value types available in wasm: f64, i64. + pub const ENCODED_MAX_SIZE: usize = 10; +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::Encode; + + #[test] + fn pointer_offset_works() { + let ptr = Pointer::::null(); + + assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40)); + assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128)); + + let ptr = Pointer::::null(); + + assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80)); + assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256)); + } + + #[test] + fn return_value_encoded_max_size() { + let encoded = ReturnValue::Value(Value::I64(-1)).encode(); + assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE); + } +} diff --git a/substrate/sp-wasm-interface-common/src/util.rs b/substrate/sp-wasm-interface-common/src/util.rs new file mode 100644 index 00000000000..241e1ae2449 --- /dev/null +++ b/substrate/sp-wasm-interface-common/src/util.rs @@ -0,0 +1,13 @@ +// This file is part of Gear. +// +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use core::ops::Range; + +/// Construct a range from an offset to a data length after the offset. +/// Returns None if the end of the range would exceed some maximum offset. +pub fn checked_range(offset: usize, len: usize, max: usize) -> Option> { + let end = offset.checked_add(len)?; + (end <= max).then(|| offset..end) +} diff --git a/substrate/sp-wasm-interface-common/src/wasmi_impl.rs b/substrate/sp-wasm-interface-common/src/wasmi_impl.rs new file mode 100644 index 00000000000..461c1353aa1 --- /dev/null +++ b/substrate/sp-wasm-interface-common/src/wasmi_impl.rs @@ -0,0 +1,84 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of conversions between Substrate and wasmi types. +use crate::{Signature, Value, ValueType}; +use sp_std::vec::Vec; + +impl From for wasmi::RuntimeValue { + fn from(value: Value) -> Self { + match value { + Value::I32(val) => Self::I32(val), + Value::I64(val) => Self::I64(val), + Value::F32(val) => Self::F32(val.into()), + Value::F64(val) => Self::F64(val.into()), + } + } +} + +impl From for Value { + fn from(value: wasmi::RuntimeValue) -> Self { + match value { + wasmi::RuntimeValue::I32(val) => Self::I32(val), + wasmi::RuntimeValue::I64(val) => Self::I64(val), + wasmi::RuntimeValue::F32(val) => Self::F32(val.into()), + wasmi::RuntimeValue::F64(val) => Self::F64(val.into()), + } + } +} + +impl From for wasmi::ValueType { + fn from(value: ValueType) -> Self { + match value { + ValueType::I32 => Self::I32, + ValueType::I64 => Self::I64, + ValueType::F32 => Self::F32, + ValueType::F64 => Self::F64, + } + } +} + +impl From for ValueType { + fn from(value: wasmi::ValueType) -> Self { + match value { + wasmi::ValueType::I32 => Self::I32, + wasmi::ValueType::I64 => Self::I64, + wasmi::ValueType::F32 => Self::F32, + wasmi::ValueType::F64 => Self::F64, + } + } +} + +impl From for wasmi::Signature { + fn from(sig: Signature) -> Self { + let args = sig.args.iter().map(|a| (*a).into()).collect::>(); + wasmi::Signature::new(args, sig.return_value.map(Into::into)) + } +} + +impl From<&wasmi::Signature> for Signature { + fn from(sig: &wasmi::Signature) -> Self { + Signature::new( + sig.params() + .iter() + .copied() + .map(Into::into) + .collect::>(), + sig.return_type().map(Into::into), + ) + } +} diff --git a/substrate/sp-wasm-interface/Cargo.toml b/substrate/sp-wasm-interface/Cargo.toml new file mode 100644 index 00000000000..244387b7a5a --- /dev/null +++ b/substrate/sp-wasm-interface/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "sp-wasm-interface" +version = "21.0.1" +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "Types and traits for interfacing between the host and the wasm runtime." +documentation = "https://docs.rs/sp-wasm-interface" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { features = ["derive"], workspace = true } +impl-trait-for-tuples = { workspace = true } +log = { optional = true, workspace = true, default-features = true } +wasmtime = { features = ["runtime"], optional = true, workspace = true } +anyhow = { optional = true, workspace = true } +sp-wasm-interface-common = { workspace = true, default-features = false } +sp-allocator = { workspace = true, default-features = false } + + +[features] +default = ["std"] +std = [ + "anyhow?/std", + "codec/std", + "log/std", + "sp-allocator/std", + "sp-wasm-interface-common/std", +] +wasmtime = ["anyhow", "dep:wasmtime"] +wasmi = [ "sp-wasm-interface-common/wasmi" ] diff --git a/substrate/sp-wasm-interface/README.md b/substrate/sp-wasm-interface/README.md new file mode 100644 index 00000000000..4c2380adc9f --- /dev/null +++ b/substrate/sp-wasm-interface/README.md @@ -0,0 +1,8 @@ +Types and traits for interfacing between the host and the wasm runtime. + +License: Apache-2.0 + + +## Release + +Polkadot SDK stable2409 diff --git a/substrate/sp-wasm-interface/src/host_state.rs b/substrate/sp-wasm-interface/src/host_state.rs new file mode 100644 index 00000000000..97833eedd77 --- /dev/null +++ b/substrate/sp-wasm-interface/src/host_state.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This module defines the `HostState` struct, which provides logic and state +//! required for host execution. + +use sp_allocator::{AllocationStats, FreeingBumpHeapAllocator}; + +/// The state required to construct a `HostContext`. The context only lasts for one host +/// call, whereas the state is maintained for the duration of a Wasm runtime call, which may make +/// many different host calls that must share state. +pub struct HostState { + /// The allocator instance to keep track of allocated memory. + /// + /// This is stored as an `Option` as we need to temporarily set this to `None` when we are + /// allocating/deallocating memory. The problem is that we can only mutably access `caller` + /// once. + pub allocator: Option, + pub panic_message: Option, +} + +impl HostState { + /// Constructs a new `HostState`. + pub fn new(allocator: FreeingBumpHeapAllocator) -> Self { + HostState { allocator: Some(allocator), panic_message: None } + } + + /// Takes the error message out of the host state, leaving a `None` in its place. + pub fn take_panic_message(&mut self) -> Option { + self.panic_message.take() + } + + pub fn allocation_stats(&self) -> AllocationStats { + self.allocator.as_ref() + .expect("Allocator is always set and only unavailable when doing an allocation/deallocation; qed") + .stats() + } +} diff --git a/substrate/sp-wasm-interface/src/lib.rs b/substrate/sp-wasm-interface/src/lib.rs new file mode 100644 index 00000000000..72183038359 --- /dev/null +++ b/substrate/sp-wasm-interface/src/lib.rs @@ -0,0 +1,361 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types and traits for interfacing between the host and the wasm runtime. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::{vec, vec::Vec}; +use core::{iter::Iterator, marker::PhantomData, result}; +pub use sp_wasm_interface_common::{ + self as common, HostPointer, IntoValue, MemoryId, Pointer, PointerType, ReturnValue, Signature, + TryFromValue, Value, ValueType, WordSize, +}; + +if_wasmtime_is_enabled! { + mod host_state; + pub use host_state::HostState; + + mod store_data; + pub use store_data::StoreData; + + mod memory_wrapper; + pub use memory_wrapper::MemoryWrapper; + + pub mod util; +} + +#[cfg(not(all(feature = "std", feature = "wasmtime")))] +pub struct StoreData; + +#[cfg(not(all(feature = "std", feature = "wasmtime")))] +#[macro_export] +macro_rules! if_wasmtime_is_enabled { + ($($token:tt)*) => {}; +} + +#[cfg(all(feature = "std", feature = "wasmtime"))] +#[macro_export] +macro_rules! if_wasmtime_is_enabled { + ($($token:tt)*) => { + $($token)* + } +} + +if_wasmtime_is_enabled! { + // Reexport wasmtime so that its types are accessible from the procedural macro. + pub use wasmtime; + + // Wasmtime uses anyhow types but doesn't reexport them. + pub use anyhow; +} + +/// Result type used by traits in this crate. +#[cfg(feature = "std")] +pub type Result = result::Result; +#[cfg(not(feature = "std"))] +pub type Result = result::Result; + +/// Provides `Sealed` trait to prevent implementing trait `PointerType` and `WasmTy` outside of this +/// crate. +mod private { + pub trait Sealed {} + + impl Sealed for u8 {} + impl Sealed for u16 {} + impl Sealed for u32 {} + impl Sealed for u64 {} + + impl Sealed for i32 {} + impl Sealed for i64 {} +} + +/// A trait that requires `RefUnwindSafe` when `feature = std`. +#[cfg(feature = "std")] +pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {} +#[cfg(feature = "std")] +impl MaybeRefUnwindSafe for T {} + +/// A trait that requires `RefUnwindSafe` when `feature = std`. +#[cfg(not(feature = "std"))] +pub trait MaybeRefUnwindSafe {} +#[cfg(not(feature = "std"))] +impl MaybeRefUnwindSafe for T {} + +/// Something that provides a function implementation on the host for a wasm function. +pub trait Function: MaybeRefUnwindSafe + Send + Sync { + /// Returns the name of this function. + fn name(&self) -> &str; + /// Returns the signature of this function. + fn signature(&self) -> Signature; + /// Execute this function with the given arguments. + fn execute( + &self, + context: &mut dyn FunctionContext, + args: &mut dyn Iterator, + ) -> Result>; +} + +impl PartialEq for dyn Function { + fn eq(&self, other: &Self) -> bool { + other.name() == self.name() && other.signature() == self.signature() + } +} + +#[cfg(not(all(feature = "std", feature = "wasmtime")))] +pub struct Caller<'a, T>(PhantomData<&'a T>); + +#[cfg(all(feature = "std", feature = "wasmtime"))] +pub use wasmtime::Caller; + +/// Context used by `Function` to interact with the allocator and the memory of the wasm instance. +pub trait FunctionContext { + /// Read memory from `address` into a vector. + fn read_memory(&self, address: Pointer, size: WordSize) -> Result> { + let mut vec = vec![0; size as usize]; + self.read_memory_into(address, &mut vec)?; + Ok(vec) + } + /// Read memory into the given `dest` buffer from `address`. + fn read_memory_into(&self, address: Pointer, dest: &mut [u8]) -> Result<()>; + /// Write the given data at `address` into the memory. + fn write_memory(&mut self, address: Pointer, data: &[u8]) -> Result<()>; + /// Allocate a memory instance of `size` bytes. + fn allocate_memory(&mut self, size: WordSize) -> Result>; + /// Deallocate a given memory instance. + fn deallocate_memory(&mut self, ptr: Pointer) -> Result<()>; + /// Registers a panic error message within the executor. + /// + /// This is meant to be used in situations where the runtime + /// encounters an unrecoverable error and intends to panic. + /// + /// Panicking in WASM is done through the [`unreachable`](https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-instr-control) + /// instruction which causes an unconditional trap and immediately aborts + /// the execution. It does not however allow for any diagnostics to be + /// passed through to the host, so while we do know that *something* went + /// wrong we don't have any direct indication of what *exactly* went wrong. + /// + /// As a workaround we use this method right before the execution is + /// actually aborted to pass an error message to the host so that it + /// can associate it with the next trap, and return that to the caller. + /// + /// A WASM trap should be triggered immediately after calling this method; + /// otherwise the error message might be associated with a completely + /// unrelated trap. + /// + /// It should only be called once, however calling it more than once + /// is harmless and will overwrite the previously set error message. + fn register_panic_error_message(&mut self, message: &str); +} + +if_wasmtime_is_enabled! { + /// A trait used to statically register host callbacks with the WASM executor, + /// so that they can be called from within the runtime with minimal overhead. + /// + /// This is used internally to interface the wasmtime-based executor with the + /// host functions' definitions generated through the runtime interface macro, + /// and is not meant to be used directly. + pub trait HostFunctionRegistry { + type State: 'static; + type Error; + type FunctionContext: FunctionContext; + + /// Wraps the given `caller` in a type which implements `FunctionContext` + /// and calls the given `callback`. + fn with_function_context( + caller: wasmtime::Caller, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, + ) -> R; + + /// Registers a given host function with the WASM executor. + /// + /// The function has to be statically callable, and all of its arguments + /// and its return value have to be compatible with WASM FFI. + fn register_static( + &mut self, + fn_name: &str, + func: impl wasmtime::IntoFunc + 'static, + ) -> core::result::Result<(), Self::Error>; + } +} + +/// Something that provides implementations for host functions. +pub trait HostFunctions: 'static + Send + Sync { + /// Returns the host functions `Self` provides. + fn host_functions() -> Vec<&'static dyn Function>; + + if_wasmtime_is_enabled! { + /// Statically registers the host functions. + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where + T: HostFunctionRegistry; + } +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl HostFunctions for Tuple { + #[allow(clippy::let_and_return)] + fn host_functions() -> Vec<&'static dyn Function> { + let mut host_functions = Vec::new(); + + for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* ); + + host_functions + } + + #[cfg(all(feature = "std", feature = "wasmtime"))] + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where + T: HostFunctionRegistry, + { + for_tuples!( + #( Tuple::register_static(registry)?; )* + ); + + Ok(()) + } +} + +/// A wrapper which merges two sets of host functions, and allows the second set to override +/// the host functions from the first set. +pub struct ExtendedHostFunctions { + phantom: PhantomData<(Base, Overlay)>, +} + +impl HostFunctions for ExtendedHostFunctions +where + Base: HostFunctions, + Overlay: HostFunctions, +{ + fn host_functions() -> Vec<&'static dyn Function> { + let mut base = Base::host_functions(); + let overlay = Overlay::host_functions(); + base.retain(|host_fn| { + !overlay + .iter() + .any(|ext_host_fn| host_fn.name() == ext_host_fn.name()) + }); + base.extend(overlay); + base + } + + if_wasmtime_is_enabled! { + fn register_static(registry: &mut T) -> core::result::Result<(), T::Error> + where + T: HostFunctionRegistry, + { + struct Proxy<'a, T> { + registry: &'a mut T, + seen_overlay: std::collections::HashSet, + seen_base: std::collections::HashSet, + overlay_registered: bool, + } + + impl<'a, T> HostFunctionRegistry for Proxy<'a, T> + where + T: HostFunctionRegistry, + { + type State = T::State; + type Error = T::Error; + type FunctionContext = T::FunctionContext; + + fn with_function_context( + caller: wasmtime::Caller, + callback: impl FnOnce(&mut dyn FunctionContext) -> R, + ) -> R { + T::with_function_context(caller, callback) + } + + fn register_static( + &mut self, + fn_name: &str, + func: impl wasmtime::IntoFunc + 'static, + ) -> core::result::Result<(), Self::Error> { + if self.overlay_registered { + if !self.seen_base.insert(fn_name.to_owned()) { + log::warn!( + target: "extended_host_functions", + "Duplicate base host function: '{}'", + fn_name, + ); + + // TODO: Return an error here? + return Ok(()) + } + + if self.seen_overlay.contains(fn_name) { + // Was already registered when we went through the overlay, so just ignore it. + log::debug!( + target: "extended_host_functions", + "Overriding base host function: '{}'", + fn_name, + ); + + return Ok(()) + } + } else if !self.seen_overlay.insert(fn_name.to_owned()) { + log::warn!( + target: "extended_host_functions", + "Duplicate overlay host function: '{}'", + fn_name, + ); + + // TODO: Return an error here? + return Ok(()) + } + + self.registry.register_static(fn_name, func) + } + } + + let mut proxy = Proxy { + registry, + seen_overlay: Default::default(), + seen_base: Default::default(), + overlay_registered: false, + }; + + // The functions from the `Overlay` can override those from the `Base`, + // so `Overlay` is registered first, and then we skip those functions + // in `Base` if they were already registered from the `Overlay`. + Overlay::register_static(&mut proxy)?; + proxy.overlay_registered = true; + Base::register_static(&mut proxy)?; + + Ok(()) + } + } +} + +/// A trait for types directly usable at the WASM FFI boundary without any conversion at all. +/// +/// This trait is sealed and should not be implemented downstream. +#[cfg(all(feature = "std", feature = "wasmtime"))] +pub trait WasmTy: wasmtime::WasmTy + private::Sealed {} + +/// A trait for types directly usable at the WASM FFI boundary without any conversion at all. +/// +/// This trait is sealed and should not be implemented downstream. +#[cfg(not(all(feature = "std", feature = "wasmtime")))] +pub trait WasmTy: private::Sealed {} + +impl WasmTy for i32 {} +impl WasmTy for u32 {} +impl WasmTy for i64 {} +impl WasmTy for u64 {} diff --git a/substrate/sp-wasm-interface/src/memory_wrapper.rs b/substrate/sp-wasm-interface/src/memory_wrapper.rs new file mode 100644 index 00000000000..1d868b92203 --- /dev/null +++ b/substrate/sp-wasm-interface/src/memory_wrapper.rs @@ -0,0 +1,56 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Wrapper around [`wasmtime::Memory`] that implements [`sp_allocator::Memory`]. +pub struct MemoryWrapper<'a, C>(&'a wasmtime::Memory, &'a mut C); + +impl<'a, C> From<(&'a wasmtime::Memory, &'a mut C)> for MemoryWrapper<'a, C> { + fn from((memory, caller): (&'a wasmtime::Memory, &'a mut C)) -> Self { + Self(memory, caller) + } +} + +impl sp_allocator::Memory for MemoryWrapper<'_, C> { + fn with_access(&self, run: impl FnOnce(&[u8]) -> R) -> R { + run(self.0.data(&self.1)) + } + + fn with_access_mut(&mut self, run: impl FnOnce(&mut [u8]) -> R) -> R { + run(self.0.data_mut(&mut self.1)) + } + + fn grow(&mut self, additional: u32) -> std::result::Result<(), ()> { + self.0 + .grow(&mut self.1, additional as u64) + .map_err(|e| { + log::error!( + "Failed to grow memory by {} pages: {}", + additional, + e, + ) + }) + .map(drop) + } + + fn pages(&self) -> u32 { + self.0.size(&self.1) as u32 + } + + fn max_pages(&self) -> Option { + self.0.ty(&self.1).maximum().map(|p| p as _) + } +} diff --git a/substrate/sp-wasm-interface/src/store_data.rs b/substrate/sp-wasm-interface/src/store_data.rs new file mode 100644 index 00000000000..13c3a6a784b --- /dev/null +++ b/substrate/sp-wasm-interface/src/store_data.rs @@ -0,0 +1,41 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::HostState; +use wasmtime::{Memory, Table}; + +#[derive(Default)] +pub struct StoreData { + /// This will only be set when we call into the runtime. + pub host_state: Option, + /// This will be always set once the store is initialized. + pub memory: Option, + /// This will be set only if the runtime actually contains a table. + pub table: Option

, +} + +impl StoreData { + /// Returns a mutable reference to the host state. + pub fn host_state_mut(&mut self) -> Option<&mut HostState> { + self.host_state.as_mut() + } + + /// Returns the host memory. + pub fn memory(&self) -> Memory { + self.memory.expect("memory is always set; qed") + } +} diff --git a/substrate/sp-wasm-interface/src/util.rs b/substrate/sp-wasm-interface/src/util.rs new file mode 100644 index 00000000000..72969b0c716 --- /dev/null +++ b/substrate/sp-wasm-interface/src/util.rs @@ -0,0 +1,100 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use wasmtime::{AsContext, AsContextMut}; +pub use sp_wasm_interface_common::util::checked_range; + +pub fn write_memory_from( + mut ctx: impl AsContextMut, + address: Pointer, + data: &[u8], +) -> Result<()> { + let memory = ctx.as_context().data().memory(); + let memory = memory.data_mut(&mut ctx); + + let range = checked_range(address.into(), data.len(), memory.len()) + .ok_or_else(|| String::from("memory write is out of bounds"))?; + memory[range].copy_from_slice(data); + Ok(()) +} + +pub fn read_memory_into( + ctx: impl AsContext, + address: Pointer, + dest: &mut [u8], +) -> Result<()> { + let memory = ctx.as_context().data().memory().data(&ctx); + + let range = checked_range(address.into(), dest.len(), memory.len()) + .ok_or_else(|| String::from("memory read is out of bounds"))?; + dest.copy_from_slice(&memory[range]); + Ok(()) +} + +pub fn read_memory( + ctx: impl AsContext, + address: Pointer, + size: WordSize, +) -> Result> { + let mut vec = vec![0; size as usize]; + read_memory_into(ctx, address, &mut vec)?; + Ok(vec) +} + +#[track_caller] +fn host_state_mut<'a>(caller: &'a mut Caller<'_, StoreData>) -> &'a mut HostState { + caller + .data_mut() + .host_state_mut() + .expect("host state is not empty when calling a function in wasm; qed") +} + +pub fn allocate_memory(caller: &mut Caller<'_, StoreData>, size: WordSize) -> Result> { + let mut allocator = host_state_mut(caller) + .allocator + .take() + .expect("allocator is not empty when calling a function in wasm; qed"); + + let memory = caller.data().memory(); + // We can not return on error early, as we need to store back allocator. + let res = allocator + .allocate(&mut MemoryWrapper::from((&memory, &mut caller.as_context_mut())), size) + .map_err(|e| e.to_string()); + + host_state_mut(caller).allocator = Some(allocator); + + res +} + +pub fn deallocate_memory(caller: &mut Caller<'_, StoreData>, ptr: Pointer) -> Result<()> { + let mut allocator = host_state_mut(caller) + .allocator + .take() + .expect("allocator is not empty when calling a function in wasm; qed"); + + let memory = caller.data().memory(); + + // We can not return on error early, as we need to store back allocator. + let res = allocator + .deallocate(&mut MemoryWrapper::from((&memory, &mut caller.as_context_mut())), ptr) + .map_err(|e| e.to_string()); + + host_state_mut(caller).allocator = Some(allocator); + + res +} diff --git a/substrate/substrate-wasm-builder/Cargo.toml b/substrate/substrate-wasm-builder/Cargo.toml new file mode 100644 index 00000000000..15c73df13be --- /dev/null +++ b/substrate/substrate-wasm-builder/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "substrate-wasm-builder" +version = "24.0.2" +authors.workspace = true +description = "Utility for building WASM binaries" +edition.workspace = true +rust-version.workspace = true +repository.workspace = true +license = "Apache-2.0" +homepage.workspace = true +documentation = "https://docs.rs/substrate-wasm-builder" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +build-helper = { workspace = true } +cargo_metadata = { workspace = true } +console = { workspace = true } +strum = { features = ["derive"], workspace = true, default-features = true } +tempfile = { workspace = true } +toml = { workspace = true } +walkdir = { workspace = true } +sp-maybe-compressed-blob.workspace = true +sp-maybe-compressed-blob.default-features = true +filetime = { workspace = true } +wasm-opt = { workspace = true } +parity-wasm = { workspace = true } +polkavm-linker = { workspace = true } +jobserver = { workspace = true } + +# Dependencies required for the `metadata-hash` feature. +merkleized-metadata = { optional = true, workspace = true } +sc-executor = { optional = true, workspace = true, default-features = true } +sp-core = { optional = true, workspace = true, default-features = true } +sp-io = { optional = true, workspace = true, default-features = true } +sp-version = { optional = true, workspace = true, default-features = true } +frame-metadata = { features = ["current"], optional = true, workspace = true, default-features = true } +codec = { optional = true, workspace = true, default-features = true } +array-bytes = { optional = true, workspace = true, default-features = true } +sp-tracing = { optional = true, workspace = true, default-features = true } + +[features] +# Enable support for generating the metadata hash. +# +# To generate the metadata hash the runtime is build once, executed to build the metadata and then +# build a second time with the `RUNTIME_METADATA_HASH` environment variable set. The environment +# variable then contains the hash and can be used inside the runtime. +# +# This pulls in quite a lot of dependencies and thus, is disabled by default. +metadata-hash = [ + "array-bytes", + "codec", + "frame-metadata", + "merkleized-metadata", + "sc-executor", + "sp-core", + "sp-io", + "sp-tracing", + "sp-version", +] diff --git a/substrate/substrate-wasm-builder/README.md b/substrate/substrate-wasm-builder/README.md new file mode 100644 index 00000000000..a63ee5adac7 --- /dev/null +++ b/substrate/substrate-wasm-builder/README.md @@ -0,0 +1,15 @@ + +# substrate-wasm-builder + +Utility for building WASM binaries. + +Local Cargo package name: `substrate-wasm-builder`. +Gear publish name: `gsubstrate-wasm-builder`. + +License: Apache-2.0. + +Source: Parity Polkadot SDK `stable2409` at `298f676c91d64f15f38ea7fd78f125c5889ab09c`. + +Copied source files retain the upstream SPDX headers and Parity Technologies copyright notices. Gear maintains local changes to isolate the remaining Polkadot SDK fork delta and publishes this crate under the `gsubstrate-wasm-builder` package name for Gear ecosystem crates. + +Apache-2.0 license text: . diff --git a/substrate/substrate-wasm-builder/src/builder.rs b/substrate/substrate-wasm-builder/src/builder.rs new file mode 100644 index 00000000000..e8501dcd9b5 --- /dev/null +++ b/substrate/substrate-wasm-builder/src/builder.rs @@ -0,0 +1,406 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +use std::{ + env, + path::{Path, PathBuf}, + process, +}; + +use crate::RuntimeTarget; + +/// Extra information when generating the `metadata-hash`. +#[cfg(feature = "metadata-hash")] +pub(crate) struct MetadataExtraInfo { + pub decimals: u8, + pub token_symbol: String, +} + +/// Returns the manifest dir from the `CARGO_MANIFEST_DIR` env. +fn get_manifest_dir() -> PathBuf { + env::var("CARGO_MANIFEST_DIR") + .expect("`CARGO_MANIFEST_DIR` is always set for `build.rs` files; qed") + .into() +} + +/// First step of the [`WasmBuilder`] to select the project to build. +pub struct WasmBuilderSelectProject { + /// This parameter just exists to make it impossible to construct + /// this type outside of this crate. + _ignore: (), +} + +impl WasmBuilderSelectProject { + /// Use the current project as project for building the WASM binary. + /// + /// # Panics + /// + /// Panics if the `CARGO_MANIFEST_DIR` variable is not set. This variable + /// is always set by `Cargo` in `build.rs` files. + pub fn with_current_project(self) -> WasmBuilder { + WasmBuilder { + cargo_flags: Vec::new(), + rust_flags: Vec::new(), + file_name: None, + project_cargo_toml: get_manifest_dir().join("Cargo.toml"), + features_to_enable: Vec::new(), + disable_runtime_version_section_check: false, + export_heap_base: false, + import_memory: false, + #[cfg(feature = "metadata-hash")] + enable_metadata_hash: None, + } + } + + /// Use the given `path` as project for building the WASM binary. + /// + /// Returns an error if the given `path` does not points to a `Cargo.toml`. + pub fn with_project(self, path: impl Into) -> Result { + let path = path.into(); + + if path.ends_with("Cargo.toml") && path.exists() { + Ok(WasmBuilder { + cargo_flags: Vec::new(), + rust_flags: Vec::new(), + file_name: None, + project_cargo_toml: path, + features_to_enable: Vec::new(), + disable_runtime_version_section_check: false, + export_heap_base: false, + import_memory: false, + #[cfg(feature = "metadata-hash")] + enable_metadata_hash: None, + }) + } else { + Err("Project path must point to the `Cargo.toml` of the project") + } + } +} + +/// The builder for building a wasm binary. +/// +/// The builder itself is separated into multiple structs to make the setup type safe. +/// +/// Building a wasm binary: +/// +/// 1. Call [`WasmBuilder::new`] to create a new builder. +/// 2. Select the project to build using the methods of [`WasmBuilderSelectProject`]. +/// 3. Set additional `RUST_FLAGS` or a different name for the file containing the WASM code using +/// methods of [`WasmBuilder`]. +/// 4. Build the WASM binary using [`Self::build`]. +pub struct WasmBuilder { + /// Flags that should be appended to `cargo rustc` invocation. + cargo_flags: Vec, + /// Flags that should be appended to `RUST_FLAGS` env variable. + rust_flags: Vec, + /// The name of the file that is being generated in `OUT_DIR`. + /// + /// Defaults to `wasm_binary.rs`. + file_name: Option, + /// The path to the `Cargo.toml` of the project that should be built + /// for wasm. + project_cargo_toml: PathBuf, + /// Features that should be enabled when building the wasm binary. + features_to_enable: Vec, + /// Should the builder not check that the `runtime_version` section exists in the wasm binary? + disable_runtime_version_section_check: bool, + + /// Whether `__heap_base` should be exported (WASM-only). + export_heap_base: bool, + /// Whether `--import-memory` should be added to the link args (WASM-only). + import_memory: bool, + + /// Whether to enable the metadata hash generation. + #[cfg(feature = "metadata-hash")] + enable_metadata_hash: Option, +} + +impl WasmBuilder { + /// Create a new instance of the builder. + pub fn new() -> WasmBuilderSelectProject { + WasmBuilderSelectProject { _ignore: () } + } + + /// Build the WASM binary using the recommended default values. + /// + /// This is the same as calling: + /// ```no_run + /// substrate_wasm_builder::WasmBuilder::new() + /// .with_current_project() + /// .import_memory() + /// .export_heap_base() + /// .build(); + /// ``` + pub fn build_using_defaults() { + WasmBuilder::new() + .with_current_project() + .import_memory() + .export_heap_base() + .build(); + } + + /// Init the wasm builder with the recommended default values. + /// + /// In contrast to [`Self::build_using_defaults`] it does not build the WASM binary directly. + /// + /// This is the same as calling: + /// ```no_run + /// substrate_wasm_builder::WasmBuilder::new() + /// .with_current_project() + /// .import_memory() + /// .export_heap_base(); + /// ``` + pub fn init_with_defaults() -> Self { + WasmBuilder::new() + .with_current_project() + .import_memory() + .export_heap_base() + } + + /// Enable exporting `__heap_base` as global variable in the WASM binary. + /// + /// This adds `-C link-arg=--export=__heap_base` to `RUST_FLAGS`. + pub fn export_heap_base(mut self) -> Self { + self.export_heap_base = true; + self + } + + /// Set the name of the file that will be generated in `OUT_DIR`. + /// + /// This file needs to be included to get access to the build WASM binary. + /// + /// If this function is not called, `file_name` defaults to `wasm_binary.rs` + pub fn set_file_name(mut self, file_name: impl Into) -> Self { + self.file_name = Some(file_name.into()); + self + } + + /// Instruct the linker to import the memory into the WASM binary. + /// + /// This adds `-C link-arg=--import-memory` to `RUST_FLAGS`. + pub fn import_memory(mut self) -> Self { + self.import_memory = true; + self + } + + /// Append the given `flag` to `cargo rustc` invocation. + /// + /// `flag` is appended as is, so it needs to be a valid flag. + pub fn append_to_cargo_flags(mut self, flag: impl Into) -> Self { + self.cargo_flags.push(flag.into()); + self + } + + /// Append the given `flag` to `RUST_FLAGS`. + /// + /// `flag` is appended as is, so it needs to be a valid flag. + pub fn append_to_rust_flags(mut self, flag: impl Into) -> Self { + self.rust_flags.push(flag.into()); + self + } + + /// Enable the given feature when building the wasm binary. + /// + /// `feature` needs to be a valid feature that is defined in the project `Cargo.toml`. + pub fn enable_feature(mut self, feature: impl Into) -> Self { + self.features_to_enable.push(feature.into()); + self + } + + /// Enable generation of the metadata hash. + /// + /// This will compile the runtime once, fetch the metadata, build the metadata hash and + /// then compile again with the env `RUNTIME_METADATA_HASH` set. For more information + /// about the metadata hash see [RFC78](https://polkadot-fellows.github.io/RFCs/approved/0078-merkleized-metadata.html). + /// + /// - `token_symbol`: The symbol of the main native token of the chain. + /// - `decimals`: The number of decimals of the main native token. + #[cfg(feature = "metadata-hash")] + pub fn enable_metadata_hash(mut self, token_symbol: impl Into, decimals: u8) -> Self { + self.enable_metadata_hash = Some(MetadataExtraInfo { + token_symbol: token_symbol.into(), + decimals, + }); + + self + } + + /// Disable the check for the `runtime_version` wasm section. + /// + /// By default the `wasm-builder` will ensure that the `runtime_version` section will + /// exists in the build wasm binary. This `runtime_version` section is used to get the + /// `RuntimeVersion` without needing to call into the wasm binary. However, for some + /// use cases (like tests) you may want to disable this check. + pub fn disable_runtime_version_section_check(mut self) -> Self { + self.disable_runtime_version_section_check = true; + self + } + + /// Build the WASM binary. + pub fn build(mut self) { + let target = crate::runtime_target(); + if target == RuntimeTarget::Wasm { + if self.export_heap_base { + self.rust_flags + .push("-C link-arg=--export=__heap_base".into()); + } + + if self.import_memory { + self.rust_flags.push("-C link-arg=--import-memory".into()); + } + } + + let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!")); + let file_path = out_dir.join( + self.file_name + .clone() + .unwrap_or_else(|| "wasm_binary.rs".into()), + ); + + if check_skip_build() { + // If we skip the build, we still want to make sure to be called when an env variable + // changes + generate_rerun_if_changed_instructions(); + + provide_dummy_wasm_binary_if_not_exist(&file_path); + + return; + } + + build_project( + target, + file_path, + self.project_cargo_toml, + self.cargo_flags, + self.rust_flags.join(" "), + self.features_to_enable, + self.file_name, + !self.disable_runtime_version_section_check, + #[cfg(feature = "metadata-hash")] + self.enable_metadata_hash, + ); + + // As last step we need to generate our `rerun-if-changed` stuff. If a build fails, we don't + // want to spam the output! + generate_rerun_if_changed_instructions(); + } +} + +/// Generate the name of the skip build environment variable for the current crate. +fn generate_crate_skip_build_env_name() -> String { + format!( + "SKIP_{}_WASM_BUILD", + env::var("CARGO_PKG_NAME") + .expect("Package name is set") + .to_uppercase() + .replace('-', "_"), + ) +} + +/// Checks if the build of the WASM binary should be skipped. +fn check_skip_build() -> bool { + env::var(crate::SKIP_BUILD_ENV).is_ok() || + env::var(generate_crate_skip_build_env_name()).is_ok() || + // If we are running in docs.rs, let's skip building. + // https://docs.rs/about/builds#detecting-docsrs + env::var("DOCS_RS").is_ok() +} + +/// Provide a dummy WASM binary if there doesn't exist one. +fn provide_dummy_wasm_binary_if_not_exist(file_path: &Path) { + if !file_path.exists() { + crate::write_file_if_changed( + file_path, + "pub const WASM_BINARY: Option<&[u8]> = None;\ + pub const WASM_BINARY_BLOATY: Option<&[u8]> = None;", + ); + } +} + +/// Generate the `rerun-if-changed` instructions for cargo to make sure that the WASM binary is +/// rebuilt when needed. +fn generate_rerun_if_changed_instructions() { + // Make sure that the `build.rs` is called again if one of the following env variables changes. + println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", crate::FORCE_WASM_BUILD_ENV); + println!( + "cargo:rerun-if-env-changed={}", + generate_crate_skip_build_env_name() + ); +} + +/// Build the currently built project as wasm binary. +/// +/// The current project is determined by using the `CARGO_MANIFEST_DIR` environment variable. +/// +/// `file_name` - The name + path of the file being generated. The file contains the +/// constant `WASM_BINARY`, which contains the built wasm binary. +/// +/// `project_cargo_toml` - The path to the `Cargo.toml` of the project that should be built. +/// +/// `default_rustflags` - Default `RUSTFLAGS` that will always be set for the build. +/// +/// `features_to_enable` - Features that should be enabled for the project. +/// +/// `wasm_binary_name` - The optional wasm binary name that is extended with +/// `.compact.compressed.wasm`. If `None`, the project name will be used. +/// +/// `check_for_runtime_version_section` - Should the wasm binary be checked for the +/// `runtime_version` section? +fn build_project( + target: RuntimeTarget, + file_name: PathBuf, + project_cargo_toml: PathBuf, + default_cargo_flags: Vec, + default_rustflags: String, + features_to_enable: Vec, + wasm_binary_name: Option, + check_for_runtime_version_section: bool, + #[cfg(feature = "metadata-hash")] enable_metadata_hash: Option, +) { + // Init jobserver as soon as possible + crate::wasm_project::get_jobserver(); + let cargo_cmd = match crate::prerequisites::check(target) { + Ok(cmd) => cmd, + Err(err_msg) => { + eprintln!("{err_msg}"); + process::exit(1); + } + }; + + let (wasm_binary, bloaty) = crate::wasm_project::create_and_compile( + target, + &project_cargo_toml, + &default_cargo_flags, + &default_rustflags, + cargo_cmd, + features_to_enable, + wasm_binary_name, + check_for_runtime_version_section, + #[cfg(feature = "metadata-hash")] + enable_metadata_hash, + ); + + let (wasm_binary, wasm_binary_bloaty) = if let Some(wasm_binary) = wasm_binary { + ( + wasm_binary.wasm_binary_path_escaped(), + bloaty.bloaty_path_escaped(), + ) + } else { + (bloaty.bloaty_path_escaped(), bloaty.bloaty_path_escaped()) + }; + + crate::write_file_if_changed( + file_name, + format!( + r#" + pub const WASM_BINARY: Option<&[u8]> = Some(include_bytes!("{wasm_binary}")); + pub const WASM_BINARY_BLOATY: Option<&[u8]> = Some(include_bytes!("{wasm_binary_bloaty}")); + "#, + wasm_binary = wasm_binary, + wasm_binary_bloaty = wasm_binary_bloaty, + ), + ); +} diff --git a/substrate/substrate-wasm-builder/src/lib.rs b/substrate/substrate-wasm-builder/src/lib.rs new file mode 100644 index 00000000000..711a5f48026 --- /dev/null +++ b/substrate/substrate-wasm-builder/src/lib.rs @@ -0,0 +1,498 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +//! # Wasm builder is a utility for building a project as a Wasm binary +//! +//! The Wasm builder is a tool that integrates the process of building the WASM binary of your +//! project into the main `cargo` build process. +//! +//! ## Project setup +//! +//! A project that should be compiled as a Wasm binary needs to: +//! +//! 1. Add a `build.rs` file. +//! 2. Add `wasm-builder` as dependency into `build-dependencies`. +//! +//! The `build.rs` file needs to contain the following code: +//! +//! ```no_run +//! use substrate_wasm_builder::WasmBuilder; +//! +//! fn main() { +//! // Builds the WASM binary using the recommended defaults. +//! // If you need more control, you can call `new` or `init_with_defaults`. +//! WasmBuilder::build_using_defaults(); +//! } +//! ``` +//! +//! As the final step, you need to add the following to your project: +//! +//! ```ignore +//! include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +//! ``` +//! +//! This will include the generated Wasm binary as two constants `WASM_BINARY` and +//! `WASM_BINARY_BLOATY`. The former is a compact Wasm binary and the latter is the Wasm binary as +//! being generated by the compiler. Both variables have `Option<&'static [u8]>` as type. +//! +//! ### Feature +//! +//! Wasm builder supports to enable cargo features while building the Wasm binary. By default it +//! will enable all features in the wasm build that are enabled for the native build except the +//! `default` and `std` features. Besides that, wasm builder supports the special `runtime-wasm` +//! feature. This `runtime-wasm` feature will be enabled by the wasm builder when it compiles the +//! Wasm binary. If this feature is not present, it will not be enabled. +//! +//! ## Environment variables +//! +//! By using environment variables, you can configure which Wasm binaries are built and how: +//! +//! - `SUBSTRATE_RUNTIME_TARGET` - Sets the target for building runtime. Supported values are `wasm` +//! or `riscv` (experimental, do not use it in production!). By default the target is equal to +//! `wasm`. +//! - `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when only native should be +//! recompiled. If this is the first run and there doesn't exist a Wasm binary, this will set both +//! variables to `None`. +//! - `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. Supported values are +//! `release` or `debug`. By default the build type is equal to the build type used by the main +//! build. +//! - `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls the value of the +//! variable needs to change. As wasm-builder instructs `cargo` to watch for file changes this +//! environment variable should only be required in certain circumstances. +//! - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while building the wasm +//! binary. +//! - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build. +//! - `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given directory. The path +//! needs to be absolute. +//! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the Wasm binaries. The +//! format needs to be the same as used by cargo, e.g. `nightly-2024-12-26`. +//! - `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This is normally not +//! required as we walk up from the target directory until we find a `Cargo.toml`. If the target +//! directory is changed for the build, this environment variable can be used to point to the +//! actual workspace. +//! - `WASM_BUILD_STD` - Sets whether the Rust's standard library crates (`core` and `alloc`) will +//! also be built. This is necessary to make sure the standard library crates only use the exact +//! WASM feature set that our executor supports. Enabled by default for RISC-V target and WASM +//! target (but only if Rust < 1.84). Disabled by default for WASM target and Rust >= 1.84. +//! - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to +//! prevent network access. Useful in offline environments. +//! +//! Each project can be skipped individually by using the environment variable +//! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by the name of the +//! cargo project, e.g. `kitchensink-runtime` will be `NODE_RUNTIME`. +//! +//! ## Prerequisites: +//! +//! Wasm builder requires the following prerequisites for building the Wasm binary: +//! - Rust >= 1.68 and Rust < 1.84: +//! - `wasm32-unknown-unknown` target +//! - `rust-src` component +//! - Rust >= 1.84: +//! - `wasm32v1-none` target +//! +//! If a specific Rust is installed with `rustup`, it is important that the WASM +//! target is installed as well. For example if installing the Rust from +//! 26.12.2024 using `rustup install nightly-2024-12-26`, the WASM target +//! (`wasm32-unknown-unknown` or `wasm32v1-none`) needs to be installed as well +//! `rustup target add wasm32-unknown-unknown --toolchain nightly-2024-12-26`. +//! To install the `rust-src` component, use `rustup component add rust-src +//! --toolchain nightly-2024-12-26`. + +#![allow( + clippy::collapsible_if, + clippy::get_first, + clippy::lines_filter_map_ok, + clippy::needless_borrow, + clippy::needless_borrows_for_generic_args, + clippy::needless_doctest_main, + clippy::needless_return, + clippy::new_ret_no_self, + clippy::option_map_unit_fn, + clippy::too_many_arguments, + clippy::unnecessary_map_or, + clippy::useless_conversion, + clippy::zero_prefixed_literal +)] + +use std::{ + collections::BTreeSet, + env, fs, + io::BufRead, + path::{Path, PathBuf}, + process::Command, +}; +use version::Version; + +mod builder; +#[cfg(feature = "metadata-hash")] +mod metadata_hash; +mod prerequisites; +mod version; +mod wasm_project; + +pub use builder::{WasmBuilder, WasmBuilderSelectProject}; + +/// Environment variable that tells us to skip building the wasm binary. +const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; + +/// Environment variable that tells us whether we should avoid network requests +const OFFLINE: &str = "CARGO_NET_OFFLINE"; + +/// Environment variable to force a certain build type when building the wasm binary. +/// Expects "debug", "release" or "production" as value. +/// +/// When unset the WASM binary uses the same build type as the main cargo build with +/// the exception of a debug build: In this case the wasm build defaults to `release` in +/// order to avoid a slowdown when not explicitly requested. +const WASM_BUILD_TYPE_ENV: &str = "WASM_BUILD_TYPE"; + +/// Environment variable to extend the `RUSTFLAGS` variable given to the wasm build. +const WASM_BUILD_RUSTFLAGS_ENV: &str = "WASM_BUILD_RUSTFLAGS"; + +/// Environment variable to set the target directory to copy the final wasm binary. +/// +/// The directory needs to be an absolute path. +const WASM_TARGET_DIRECTORY: &str = "WASM_TARGET_DIRECTORY"; + +/// Environment variable to disable color output of the wasm build. +const WASM_BUILD_NO_COLOR: &str = "WASM_BUILD_NO_COLOR"; + +/// Environment variable to set the toolchain used to compile the wasm binary. +const WASM_BUILD_TOOLCHAIN: &str = "WASM_BUILD_TOOLCHAIN"; + +/// Environment variable that makes sure the WASM build is triggered. +const FORCE_WASM_BUILD_ENV: &str = "FORCE_WASM_BUILD"; + +/// Environment variable that hints the workspace we are building. +const WASM_BUILD_WORKSPACE_HINT: &str = "WASM_BUILD_WORKSPACE_HINT"; + +/// Environment variable to set whether we'll build `core`/`alloc`. +const WASM_BUILD_STD: &str = "WASM_BUILD_STD"; + +/// The target to use for the runtime. Valid values are `wasm` (default) or `riscv`. +const RUNTIME_TARGET: &str = "SUBSTRATE_RUNTIME_TARGET"; + +/// Write to the given `file` if the `content` is different. +fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { + if fs::read_to_string(file.as_ref()).ok().as_deref() != Some(content.as_ref()) { + fs::write(file.as_ref(), content.as_ref()) + .unwrap_or_else(|_| panic!("Writing `{}` can not fail!", file.as_ref().display())); + } +} + +/// Copy `src` to `dst` if the `dst` does not exist or is different. +fn copy_file_if_changed(src: PathBuf, dst: PathBuf) { + let src_file = fs::read_to_string(&src).ok(); + let dst_file = fs::read_to_string(&dst).ok(); + + if src_file != dst_file { + fs::copy(&src, &dst).unwrap_or_else(|_| { + panic!( + "Copying `{}` to `{}` can not fail; qed", + src.display(), + dst.display() + ) + }); + } +} + +/// Get a cargo command that should be used to invoke the compilation. +fn get_cargo_command(target: RuntimeTarget) -> CargoCommand { + let env_cargo = + CargoCommand::new(&env::var("CARGO").expect("`CARGO` env variable is always set by cargo")); + let default_cargo = CargoCommand::new("cargo"); + let wasm_toolchain = env::var(WASM_BUILD_TOOLCHAIN).ok(); + + // First check if the user requested a specific toolchain + if let Some(cmd) = + wasm_toolchain.map(|t| CargoCommand::new_with_args("rustup", &["run", &t, "cargo"])) + { + cmd + } else if env_cargo.supports_substrate_runtime_env(target) { + env_cargo + } else if default_cargo.supports_substrate_runtime_env(target) { + default_cargo + } else { + // If no command before provided us with a cargo that supports our Substrate wasm env, we + // try to search one with rustup. If that fails as well, we return the default cargo and let + // the perquisites check fail. + get_rustup_command(target).unwrap_or(default_cargo) + } +} + +/// Get the newest rustup command that supports compiling a runtime. +/// +/// Stable versions are always favored over nightly versions even if the nightly versions are +/// newer. +fn get_rustup_command(target: RuntimeTarget) -> Option { + let output = Command::new("rustup") + .args(&["toolchain", "list"]) + .output() + .ok()? + .stdout; + let lines = output.as_slice().lines(); + + let mut versions = Vec::new(); + for line in lines.filter_map(|l| l.ok()) { + // Split by a space to get rid of e.g. " (default)" at the end. + let rustup_version = line.split(" ").next().unwrap(); + let cmd = CargoCommand::new_with_args("rustup", &["run", &rustup_version, "cargo"]); + + if !cmd.supports_substrate_runtime_env(target) { + continue; + } + + let Some(cargo_version) = cmd.version() else { + continue; + }; + + versions.push((cargo_version, rustup_version.to_string())); + } + + // Sort by the parsed version to get the latest version (greatest version) at the end of the + // vec. + versions.sort_by_key(|v| v.0); + let version = &versions.last()?.1; + + Some(CargoCommand::new_with_args( + "rustup", + &["run", &version, "cargo"], + )) +} + +/// Wraps a specific command which represents a cargo invocation. +#[derive(Debug, Clone)] +struct CargoCommand { + program: String, + args: Vec, + version: Option, + target_list: Option>, +} + +impl CargoCommand { + fn new(program: &str) -> Self { + let version = Self::extract_version(program, &[]); + let target_list = Self::extract_target_list(program, &[]); + + CargoCommand { + program: program.into(), + args: Vec::new(), + version, + target_list, + } + } + + fn new_with_args(program: &str, args: &[&str]) -> Self { + let version = Self::extract_version(program, args); + let target_list = Self::extract_target_list(program, args); + + CargoCommand { + program: program.into(), + args: args.iter().map(ToString::to_string).collect(), + version, + target_list, + } + } + + fn command(&self) -> Command { + let mut cmd = Command::new(&self.program); + cmd.args(&self.args); + cmd + } + + fn extract_version(program: &str, args: &[&str]) -> Option { + let version = Command::new(program) + .args(args) + .arg("--version") + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok())?; + + Version::extract(&version) + } + + fn extract_target_list(program: &str, args: &[&str]) -> Option> { + // This is technically an unstable option, but we don't care because we only need this + // to build RISC-V runtimes, and those currently require a specific nightly toolchain + // anyway, so it's totally fine for this to fail in other cases. + let list = Command::new(program) + .args(args) + .args(&["rustc", "-Z", "unstable-options", "--print", "target-list"]) + // Make sure if we're called from within a `build.rs` the host toolchain won't override + // a rustup toolchain we've picked. + .env_remove("RUSTC") + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok())?; + + Some(list.trim().split("\n").map(ToString::to_string).collect()) + } + + /// Returns the version of this cargo command or `None` if it failed to extract the version. + fn version(&self) -> Option { + self.version + } + + /// Returns whether this version of the toolchain supports nightly features. + fn supports_nightly_features(&self) -> bool { + self.version.map_or(false, |version| version.is_nightly) + || env::var("RUSTC_BOOTSTRAP").is_ok() + } + + /// Check if the supplied cargo command supports our runtime environment. + fn supports_substrate_runtime_env(&self, target: RuntimeTarget) -> bool { + match target { + RuntimeTarget::Wasm => self.supports_substrate_runtime_env_wasm(), + RuntimeTarget::Riscv => self.supports_substrate_runtime_env_riscv(), + } + } + + /// Check if the supplied cargo command supports our RISC-V runtime environment. + fn supports_substrate_runtime_env_riscv(&self) -> bool { + let Some(target_list) = self.target_list.as_ref() else { + return false; + }; + // This is our custom target which currently doesn't exist on any upstream toolchain, + // so if it exists it's guaranteed to be our custom toolchain and have have everything + // we need, so any further version checks are unnecessary at this point. + target_list.contains("riscv32ema-unknown-none-elf") + } + + /// Check if the supplied cargo command supports our Substrate wasm environment. + /// + /// This means that either the cargo version is at minimum 1.68.0 or this is a nightly cargo. + /// + /// Assumes that cargo version matches the rustc version. + fn supports_substrate_runtime_env_wasm(&self) -> bool { + // `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when this env + // variable is set, we can assume that whatever rust compiler we have, it is a nightly + // compiler. For "more" information, see: + // https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891 + if env::var("RUSTC_BOOTSTRAP").is_ok() { + return true; + } + + let Some(version) = self.version() else { + return false; + }; + + // Check if major and minor are greater or equal than 1.68 or this is a nightly. + version.major > 1 || (version.major == 1 && version.minor >= 68) || version.is_nightly + } + + /// Returns whether this version of the toolchain supports the `wasm32v1-none` target. + fn supports_wasm32v1_none_target(&self) -> bool { + self.version.map_or(false, |version| { + // Check if major and minor are greater or equal than 1.84. + version.major > 1 || (version.major == 1 && version.minor >= 84) + }) + } +} + +/// Wraps a [`CargoCommand`] and the version of `rustc` the cargo command uses. +#[derive(Clone)] +struct CargoCommandVersioned { + command: CargoCommand, + version: String, +} + +impl CargoCommandVersioned { + fn new(command: CargoCommand, version: String) -> Self { + Self { command, version } + } + + /// Returns the `rustc` version. + fn rustc_version(&self) -> &str { + &self.version + } +} + +impl std::ops::Deref for CargoCommandVersioned { + type Target = CargoCommand; + + fn deref(&self) -> &CargoCommand { + &self.command + } +} + +/// Returns `true` when color output is enabled. +fn color_output_enabled() -> bool { + env::var(crate::WASM_BUILD_NO_COLOR).is_err() +} + +/// Fetches a boolean environment variable. Will exit the process if the value is invalid. +fn get_bool_environment_variable(name: &str) -> Option { + let value = env::var_os(name)?; + + // We're comparing `OsString`s here so we can't use a `match`. + if value == "1" { + Some(true) + } else if value == "0" { + Some(false) + } else { + build_helper::warning!( + "the '{}' environment variable has an invalid value; it must be either '1' or '0'", + name + ); + std::process::exit(1); + } +} + +/// Returns whether we need to also compile the standard library when compiling the runtime. +fn build_std_required(cargo_command: &CargoCommand) -> bool { + crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or_else(|| { + match runtime_target() { + RuntimeTarget::Wasm => !cargo_command.supports_wasm32v1_none_target(), + RuntimeTarget::Riscv => true, + } + }) +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum RuntimeTarget { + Wasm, + Riscv, +} + +impl RuntimeTarget { + fn rustc_target(self, cargo_command: &CargoCommand) -> &'static str { + match self { + RuntimeTarget::Wasm => { + if cargo_command.supports_wasm32v1_none_target() { + "wasm32v1-none" + } else { + "wasm32-unknown-unknown" + } + } + RuntimeTarget::Riscv => "riscv32ema-unknown-none-elf", + } + } + + fn build_subdirectory(self) -> &'static str { + // Keep the build directories separate so that when switching between + // the targets we won't trigger unnecessary rebuilds. + match self { + RuntimeTarget::Wasm => "wbuild", + RuntimeTarget::Riscv => "rbuild", + } + } +} + +fn runtime_target() -> RuntimeTarget { + let Some(value) = env::var_os(RUNTIME_TARGET) else { + return RuntimeTarget::Wasm; + }; + + if value == "wasm" { + RuntimeTarget::Wasm + } else if value == "riscv" { + RuntimeTarget::Riscv + } else { + build_helper::warning!( + "the '{RUNTIME_TARGET}' environment variable has an invalid value; it must be either 'wasm' or 'riscv'" + ); + std::process::exit(1); + } +} diff --git a/substrate/substrate-wasm-builder/src/metadata_hash.rs b/substrate/substrate-wasm-builder/src/metadata_hash.rs new file mode 100644 index 00000000000..70f7c447635 --- /dev/null +++ b/substrate/substrate-wasm-builder/src/metadata_hash.rs @@ -0,0 +1,120 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +use crate::builder::MetadataExtraInfo; +use codec::{Decode, Encode}; +use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed}; +use merkleized_metadata::{ExtraInfo, generate_metadata_digest}; +use sc_executor::WasmExecutor; +use sp_core::traits::{CallContext, CodeExecutor, RuntimeCode, WrappedRuntimeCode}; +use std::path::Path; + +/// The host functions that we provide when calling into the wasm file. +/// +/// Any other host function will return an error. +type HostFunctions = ( + // The allocator functions. + sp_io::allocator::HostFunctions, + // Logging is good to have for debugging issues. + sp_io::logging::HostFunctions, + // Give access to the "state", actually the state will be empty, but some chains put constants + // into the state and this would panic at metadata generation. Thus, we give them an empty + // state to not panic. + sp_io::storage::HostFunctions, + // The hashing functions. + sp_io::hashing::HostFunctions, +); + +/// Generate the metadata hash. +/// +/// The metadata hash is generated as specced in +/// [RFC78](https://polkadot-fellows.github.io/RFCs/approved/0078-merkleized-metadata.html). +/// +/// Returns the metadata hash. +pub fn generate_metadata_hash(wasm: &Path, extra_info: MetadataExtraInfo) -> [u8; 32] { + sp_tracing::try_init_simple(); + + let wasm = std::fs::read(wasm).expect("Wasm file was just created and should be readable."); + + let executor = WasmExecutor::::builder() + .with_allow_missing_host_functions(true) + .build(); + + let runtime_code = RuntimeCode { + code_fetcher: &WrappedRuntimeCode(wasm.into()), + heap_pages: None, + // The hash is only used for caching and thus, not that important for our use case here. + hash: vec![1, 2, 3], + }; + + let metadata = executor + .call( + &mut sp_io::TestExternalities::default().ext(), + &runtime_code, + "Metadata_metadata_at_version", + &15u32.encode(), + CallContext::Offchain, + ) + .0 + .expect("`Metadata::metadata_at_version` should exist."); + + let metadata = Option::>::decode(&mut &metadata[..]) + .ok() + .flatten() + .expect("Metadata V15 support is required."); + + let metadata = RuntimeMetadataPrefixed::decode(&mut &metadata[..]) + .expect("Invalid encoded metadata?") + .1; + + let runtime_version = executor + .call( + &mut sp_io::TestExternalities::default().ext(), + &runtime_code, + "Core_version", + &[], + CallContext::Offchain, + ) + .0 + .expect("`Core_version` should exist."); + let runtime_version = sp_version::RuntimeVersion::decode(&mut &runtime_version[..]) + .expect("Invalid `RuntimeVersion` encoding"); + + let base58_prefix = extract_ss58_prefix(&metadata); + + let extra_info = ExtraInfo { + spec_version: runtime_version.spec_version, + spec_name: runtime_version.spec_name.into(), + base58_prefix, + decimals: extra_info.decimals, + token_symbol: extra_info.token_symbol, + }; + + generate_metadata_digest(&metadata, extra_info) + .expect("Failed to generate the metadata digest") + .hash() +} + +/// Extract the `SS58` from the constants in the given `metadata`. +fn extract_ss58_prefix(metadata: &RuntimeMetadata) -> u16 { + let RuntimeMetadata::V15(metadata) = metadata else { + panic!("Metadata version 15 required") + }; + + let system = metadata + .pallets + .iter() + .find(|p| p.name == "System") + .expect("Each FRAME runtime has the `System` pallet; qed"); + + system + .constants + .iter() + .find_map(|c| { + (c.name == "SS58Prefix") + .then(|| u16::decode(&mut &c.value[..]).expect("SS58 is an `u16`; qed")) + }) + .expect("`SS58PREFIX` exists in the `System` constants; qed") +} diff --git a/substrate/substrate-wasm-builder/src/prerequisites.rs b/substrate/substrate-wasm-builder/src/prerequisites.rs new file mode 100644 index 00000000000..8a0f618c19a --- /dev/null +++ b/substrate/substrate-wasm-builder/src/prerequisites.rs @@ -0,0 +1,264 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +use crate::{CargoCommand, CargoCommandVersioned, RuntimeTarget, write_file_if_changed}; + +use console::style; +use std::{ + fs, + path::{Path, PathBuf}, + process::Command, +}; + +use tempfile::tempdir; + +/// Colorizes an error message, if color output is enabled. +fn colorize_error_message(message: &str) -> String { + if super::color_output_enabled() { + style(message).red().bold().to_string() + } else { + message.into() + } +} + +/// Colorizes an auxiliary message, if color output is enabled. +fn colorize_aux_message(message: &str) -> String { + if super::color_output_enabled() { + style(message).yellow().bold().to_string() + } else { + message.into() + } +} + +/// Checks that all prerequisites are installed. +/// +/// Returns the versioned cargo command on success. +pub(crate) fn check(target: RuntimeTarget) -> Result { + let cargo_command = crate::get_cargo_command(target); + match target { + RuntimeTarget::Wasm => { + if !cargo_command.supports_substrate_runtime_env(target) { + return Err(colorize_error_message( + "Cannot compile a WASM runtime: no compatible Rust compiler found!\n\ + Install at least Rust 1.68.0 or a recent nightly version.", + )); + } + + check_wasm_toolchain_installed(cargo_command) + } + RuntimeTarget::Riscv => { + if !cargo_command.supports_substrate_runtime_env(target) { + return Err(colorize_error_message( + "Cannot compile a RISC-V runtime: no compatible Rust compiler found!\n\ + Install a toolchain from here and try again: https://github.com/paritytech/rustc-rv32e-toolchain/", + )); + } + + let dummy_crate = DummyCrate::new(&cargo_command, target); + let version = dummy_crate.get_rustc_version(); + Ok(CargoCommandVersioned::new(cargo_command, version)) + } + } +} + +struct DummyCrate<'a> { + cargo_command: &'a CargoCommand, + temp: tempfile::TempDir, + manifest_path: PathBuf, + target: RuntimeTarget, +} + +impl<'a> DummyCrate<'a> { + /// Creates a minimal dummy crate. + fn new(cargo_command: &'a CargoCommand, target: RuntimeTarget) -> Self { + let temp = tempdir().expect("Creating temp dir does not fail; qed"); + let project_dir = temp.path(); + fs::create_dir_all(project_dir.join("src")).expect("Creating src dir does not fail; qed"); + + let manifest_path = project_dir.join("Cargo.toml"); + match target { + RuntimeTarget::Wasm => { + write_file_if_changed( + &manifest_path, + r#" + [package] + name = "dummy-crate" + version = "1.0.0" + edition = "2021" + [lib] + crate-type = ["cdylib"] + [workspace] + "#, + ); + + write_file_if_changed( + project_dir.join("src/lib.rs"), + r#" + #![no_std] + #[panic_handler] + fn panic(_: &core::panic::PanicInfo<'_>) -> ! { + loop {} + } + "#, + ); + } + RuntimeTarget::Riscv => { + write_file_if_changed( + &manifest_path, + r#" + [package] + name = "dummy-crate" + version = "1.0.0" + edition = "2021" + [workspace] + "#, + ); + + write_file_if_changed( + project_dir.join("src/main.rs"), + "#![allow(missing_docs)] fn main() {}", + ); + } + } + + DummyCrate { + cargo_command, + temp, + manifest_path, + target, + } + } + + fn prepare_command(&self, subcommand: &str) -> Command { + let mut cmd = self.cargo_command.command(); + // Chdir to temp to avoid including project's .cargo/config.toml + // by accident - it can happen in some CI environments. + cmd.current_dir(&self.temp); + cmd.arg(subcommand) + .arg(format!( + "--target={}", + self.target.rustc_target(self.cargo_command) + )) + .args(&["--manifest-path", &self.manifest_path.display().to_string()]); + + if super::color_output_enabled() { + cmd.arg("--color=always"); + } + + // manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock + let target_dir = self.temp.path().join("target").display().to_string(); + cmd.env("CARGO_TARGET_DIR", &target_dir); + + // Make sure the host's flags aren't used here, e.g. if an alternative linker is specified + // in the RUSTFLAGS then the check we do here will break unless we clear these. + cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); + cmd.env_remove("RUSTFLAGS"); + // Make sure if we're called from within a `build.rs` the host toolchain won't override a + // rustup toolchain we've picked. + cmd.env_remove("RUSTC"); + cmd + } + + fn get_rustc_version(&self) -> String { + let mut run_cmd = self.prepare_command("rustc"); + run_cmd.args(&["-q", "--", "--version"]); + run_cmd + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap_or_else(|| "unknown rustc version".into()) + } + + fn get_sysroot(&self) -> Option { + let mut sysroot_cmd = self.prepare_command("rustc"); + sysroot_cmd.args(&["-q", "--", "--print", "sysroot"]); + sysroot_cmd + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + } + + fn get_toolchain(&self) -> Option { + let sysroot = self.get_sysroot()?; + Path::new(sysroot.trim()) + .file_name() + .and_then(|s| s.to_str()) + .map(|s| s.to_string()) + } + + fn try_build(&self) -> Result<(), Option> { + let Ok(result) = self.prepare_command("build").output() else { + return Err(None); + }; + if !result.status.success() { + return Err(Some(String::from_utf8_lossy(&result.stderr).into())); + } + Ok(()) + } +} + +fn check_wasm_toolchain_installed( + cargo_command: CargoCommand, +) -> Result { + let target = RuntimeTarget::Wasm; + let rustc_target = target.rustc_target(&cargo_command); + + let dummy_crate = DummyCrate::new(&cargo_command, RuntimeTarget::Wasm); + + if let Err(error) = dummy_crate.try_build() { + let toolchain = dummy_crate + .get_toolchain() + .unwrap_or("".to_string()); + let basic_error_message = colorize_error_message(&format!( + "Rust WASM target for toolchain {toolchain} is not properly installed; please install it!" + )); + return match error { + None => Err(basic_error_message), + Some(error) + if error.contains(&format!("the `{rustc_target}` target may not be installed")) => + { + Err(colorize_error_message(&format!( + "Cannot compile the WASM runtime: the `{rustc_target}` target is not installed!\n\ + You can install it with `rustup target add {rustc_target} --toolchain {toolchain}` if you're using `rustup`." + ))) + } + // Apparently this can happen when we're running on a non Tier 1 platform. + Some(ref error) if error.contains("linker `rust-lld` not found") => Err( + colorize_error_message("Cannot compile the WASM runtime: `rust-lld` not found!"), + ), + Some(error) => Err(format!( + "{}\n\n{}\n{}\n{}{}\n", + basic_error_message, + colorize_aux_message("Further error information:"), + colorize_aux_message(&"-".repeat(60)), + error, + colorize_aux_message(&"-".repeat(60)), + )), + }; + } + + let version = dummy_crate.get_rustc_version(); + if crate::build_std_required(&cargo_command) { + if let Some(sysroot) = dummy_crate.get_sysroot() { + let src_path = Path::new(sysroot.trim()) + .join("lib") + .join("rustlib") + .join("src") + .join("rust"); + if !src_path.exists() { + let toolchain = dummy_crate + .get_toolchain() + .unwrap_or("".to_string()); + return Err(colorize_error_message(&format!( + "Cannot compile the WASM runtime: no standard library sources found at {}!\n\ + You can install them with `rustup component add rust-src --toolchain {toolchain}` if you're using `rustup`.", + src_path.display() + ))); + } + } + } + + Ok(CargoCommandVersioned::new(cargo_command, version)) +} diff --git a/substrate/substrate-wasm-builder/src/version.rs b/substrate/substrate-wasm-builder/src/version.rs new file mode 100644 index 00000000000..6234c9c3ff1 --- /dev/null +++ b/substrate/substrate-wasm-builder/src/version.rs @@ -0,0 +1,220 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +use std::cmp::Ordering; + +/// The version of rustc/cargo. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Version { + pub major: u32, + pub minor: u32, + pub patch: u32, + pub is_nightly: bool, + pub year: Option, + pub month: Option, + pub day: Option, +} + +impl Version { + /// Returns if `self` is a stable version. + pub fn is_stable(&self) -> bool { + !self.is_nightly + } + + /// Return if `self` is a nightly version. + pub fn is_nightly(&self) -> bool { + self.is_nightly + } + + /// Extract from the given `version` string. + pub fn extract(version: &str) -> Option { + let mut is_nightly = false; + let version_parts = version + .trim() + .split(" ") + .nth(1)? + .split(".") + .filter_map(|v| { + if let Some(rest) = v.strip_suffix("-nightly") { + is_nightly = true; + rest.parse().ok() + } else { + v.parse().ok() + } + }) + .collect::>(); + + if version_parts.len() != 3 { + return None; + } + + let date_parts = version + .split(" ") + .nth(3) + .map(|date| { + date.split("-") + .filter_map(|v| v.trim().strip_suffix(")").unwrap_or(v).parse().ok()) + .collect::>() + }) + .unwrap_or_default(); + + Some(Version { + major: version_parts[0], + minor: version_parts[1], + patch: version_parts[2], + is_nightly, + year: date_parts.get(0).copied(), + month: date_parts.get(1).copied(), + day: date_parts.get(2).copied(), + }) + } +} + +/// Ordering is done in the following way: +/// +/// 1. `stable` > `nightly` +/// 2. Then compare major, minor and patch. +/// 3. Last compare the date. +impl Ord for Version { + fn cmp(&self, other: &Self) -> Ordering { + if self == other { + return Ordering::Equal; + } + + // Ensure that `stable > nightly` + if self.is_stable() && other.is_nightly() { + return Ordering::Greater; + } else if self.is_nightly() && other.is_stable() { + return Ordering::Less; + } + + let to_compare = [ + (Some(self.major), Some(other.major)), + (Some(self.minor), Some(other.minor)), + (Some(self.patch), Some(other.patch)), + (self.year, other.year), + (self.month, other.month), + (self.day, other.day), + ]; + + to_compare + .iter() + .find_map(|(l, r)| if l != r { l.partial_cmp(&r) } else { None }) + // We already checked this right at the beginning, so we should never return here + // `Equal`. + .unwrap_or(Ordering::Equal) + } +} + +impl PartialOrd for Version { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn version_compare_and_extract_works() { + let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_1 = Version::extract("cargo 1.66.1 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_0_nightly = + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-15)").unwrap(); + let version_1_66_0_nightly_older_date = + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-14)").unwrap(); + let version_1_65_0 = Version::extract("cargo 1.65.0 (d65d197ad 2022-10-15)").unwrap(); + let version_1_65_0_older_date = + Version::extract("cargo 1.65.0 (d65d197ad 2022-10-14)").unwrap(); + + assert!(version_1_66_1 > version_1_66_0); + assert!(version_1_66_1 > version_1_65_0); + assert!(version_1_66_1 > version_1_66_0_nightly); + assert!(version_1_66_1 > version_1_66_0_nightly_older_date); + assert!(version_1_66_1 > version_1_65_0_older_date); + + assert!(version_1_66_0 > version_1_65_0); + assert!(version_1_66_0 > version_1_66_0_nightly); + assert!(version_1_66_0 > version_1_66_0_nightly_older_date); + assert!(version_1_66_0 > version_1_65_0_older_date); + + assert!(version_1_65_0 > version_1_66_0_nightly); + assert!(version_1_65_0 > version_1_66_0_nightly_older_date); + assert!(version_1_65_0 > version_1_65_0_older_date); + + let mut versions = vec![ + version_1_66_0, + version_1_66_0_nightly, + version_1_66_0_nightly_older_date, + version_1_65_0_older_date, + version_1_65_0, + version_1_66_1, + ]; + versions.sort_by(|a, b| b.cmp(a)); + + let expected_versions_order = vec![ + version_1_66_1, + version_1_66_0, + version_1_65_0, + version_1_65_0_older_date, + version_1_66_0_nightly, + version_1_66_0_nightly_older_date, + ]; + assert_eq!(expected_versions_order, versions); + } + + #[test] + fn parse_with_newline() { + let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)\n").unwrap(); + assert_eq!( + Version { + major: 1, + minor: 66, + patch: 0, + is_nightly: false, + year: Some(2022), + month: Some(11), + day: Some(15), + }, + version_1_66_0, + ); + } + + #[test] + fn version_without_hash_and_date() { + // Apparently there are installations that print without the hash and date. + let version_1_69_0 = Version::extract("cargo 1.69.0-nightly").unwrap(); + assert_eq!( + Version { + major: 1, + minor: 69, + patch: 0, + is_nightly: true, + year: None, + month: None, + day: None, + }, + version_1_69_0, + ); + } + + #[test] + fn parse_rustc_version() { + let version = Version::extract("rustc 1.73.0 (cc66ad468 2023-10-03)").unwrap(); + assert_eq!( + version, + Version { + major: 1, + minor: 73, + patch: 0, + is_nightly: false, + year: Some(2023), + month: Some(10), + day: Some(03), + } + ); + } +} diff --git a/substrate/substrate-wasm-builder/src/wasm_project.rs b/substrate/substrate-wasm-builder/src/wasm_project.rs new file mode 100644 index 00000000000..732ad8625fb --- /dev/null +++ b/substrate/substrate-wasm-builder/src/wasm_project.rs @@ -0,0 +1,1297 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// See `README.md` for the upstream source and license reference. + +#[cfg(feature = "metadata-hash")] +use crate::builder::MetadataExtraInfo; +use crate::{CargoCommandVersioned, OFFLINE, RuntimeTarget, write_file_if_changed}; + +use build_helper::rerun_if_changed; +use cargo_metadata::{DependencyKind, Metadata, MetadataCommand}; +use console::style; +use parity_wasm::elements::{Module, deserialize_buffer}; +use std::{ + borrow::ToOwned, + collections::HashSet, + env, fs, + hash::{Hash, Hasher}, + ops::Deref, + path::{Path, PathBuf}, + process, + sync::OnceLock, +}; +use strum::{EnumIter, IntoEnumIterator}; +use toml::value::Table; +use walkdir::WalkDir; + +/// Colorize an info message. +/// +/// Returns the colorized message. +fn colorize_info_message(message: &str) -> String { + if super::color_output_enabled() { + style(message).yellow().bold().to_string() + } else { + message.into() + } +} + +/// Holds the path to the bloaty WASM binary. +pub struct WasmBinaryBloaty(PathBuf); + +impl WasmBinaryBloaty { + /// Returns the escaped path to the bloaty binary. + pub fn bloaty_path_escaped(&self) -> String { + self.0.display().to_string().escape_default().to_string() + } + + /// Returns the path to the binary. + pub fn bloaty_path(&self) -> &Path { + &self.0 + } +} + +/// Holds the path to the WASM binary. +pub struct WasmBinary(PathBuf); + +impl WasmBinary { + /// Returns the path to the wasm binary. + pub fn wasm_binary_path(&self) -> &Path { + &self.0 + } + + /// Returns the escaped path to the wasm binary. + pub fn wasm_binary_path_escaped(&self) -> String { + self.0.display().to_string().escape_default().to_string() + } +} + +fn crate_metadata(cargo_manifest: &Path) -> Metadata { + let mut cargo_lock = cargo_manifest.to_path_buf(); + cargo_lock.set_file_name("Cargo.lock"); + + let cargo_lock_existed = cargo_lock.exists(); + + // If we can find a `Cargo.lock`, we assume that this is the workspace root and there exists a + // `Cargo.toml` that we can use for getting the metadata. + let cargo_manifest = if let Some(mut cargo_lock) = find_cargo_lock(cargo_manifest) { + cargo_lock.set_file_name("Cargo.toml"); + cargo_lock + } else { + cargo_manifest.to_path_buf() + }; + + let crate_metadata_command = create_metadata_command(cargo_manifest); + + let crate_metadata = crate_metadata_command + .exec() + .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); + // If the `Cargo.lock` didn't exist, we need to remove it after + // calling `cargo metadata`. This is required to ensure that we don't change + // the build directory outside of the `target` folder. Commands like + // `cargo publish` require this. + if !cargo_lock_existed { + let _ = fs::remove_file(&cargo_lock); + } + + crate_metadata +} + +/// Creates the WASM project, compiles the WASM binary and compacts the WASM binary. +/// +/// # Returns +/// +/// The path to the compact runtime binary and the bloaty runtime binary. +pub(crate) fn create_and_compile( + target: RuntimeTarget, + orig_project_cargo_toml: &Path, + default_cargo_flags: &[String], + default_rustflags: &str, + cargo_cmd: CargoCommandVersioned, + features_to_enable: Vec, + blob_out_name_override: Option, + check_for_runtime_version_section: bool, + #[cfg(feature = "metadata-hash")] enable_metadata_hash: Option, +) -> (Option, WasmBinaryBloaty) { + let runtime_workspace_root = get_wasm_workspace_root(); + let runtime_workspace = runtime_workspace_root.join(target.build_subdirectory()); + + let crate_metadata = crate_metadata(orig_project_cargo_toml); + + let project = create_project( + target, + orig_project_cargo_toml, + &runtime_workspace, + &crate_metadata, + crate_metadata.workspace_root.as_ref(), + features_to_enable, + ); + let wasm_project_cargo_toml = project.join("Cargo.toml"); + + let build_config = BuildConfiguration::detect(target, &project); + + #[cfg(feature = "metadata-hash")] + let raw_blob_path = match enable_metadata_hash { + Some(extra_info) => { + // When the metadata hash is enabled we need to build the runtime twice. + let raw_blob_path = build_bloaty_blob( + target, + &build_config.blob_build_profile, + &project, + default_cargo_flags, + default_rustflags, + cargo_cmd.clone(), + None, + ); + + let hash = crate::metadata_hash::generate_metadata_hash(&raw_blob_path, extra_info); + + build_bloaty_blob( + target, + &build_config.blob_build_profile, + &project, + default_cargo_flags, + default_rustflags, + cargo_cmd, + Some(hash), + ) + } + None => build_bloaty_blob( + target, + &build_config.blob_build_profile, + &project, + default_cargo_flags, + default_rustflags, + cargo_cmd, + None, + ), + }; + + // If the feature is not enabled, we only need to do it once. + #[cfg(not(feature = "metadata-hash"))] + let raw_blob_path = { + build_bloaty_blob( + target, + &build_config.blob_build_profile, + &project, + default_cargo_flags, + default_rustflags, + cargo_cmd, + ) + }; + + let blob_name = + blob_out_name_override.unwrap_or_else(|| get_blob_name(target, &wasm_project_cargo_toml)); + + let (final_blob_binary, bloaty_blob_binary) = match target { + RuntimeTarget::Wasm => { + let out_path = project.join(format!("{blob_name}.wasm")); + fs::copy(raw_blob_path, &out_path).expect("copying the runtime blob should never fail"); + + maybe_compact_and_compress_wasm( + &wasm_project_cargo_toml, + &project, + WasmBinaryBloaty(out_path), + &blob_name, + check_for_runtime_version_section, + &build_config, + ) + } + RuntimeTarget::Riscv => { + let out_path = project.join(format!("{blob_name}.polkavm")); + fs::copy(raw_blob_path, &out_path).expect("copying the runtime blob should never fail"); + (None, WasmBinaryBloaty(out_path)) + } + }; + + generate_rerun_if_changed_instructions( + orig_project_cargo_toml, + &project, + &runtime_workspace, + final_blob_binary.as_ref(), + &bloaty_blob_binary, + ); + + if let Err(err) = adjust_mtime(&bloaty_blob_binary, final_blob_binary.as_ref()) { + build_helper::warning!( + "Error while adjusting the mtime of the blob binaries: {}", + err + ) + } + + (final_blob_binary, bloaty_blob_binary) +} + +fn maybe_compact_and_compress_wasm( + wasm_project_cargo_toml: &Path, + project: &Path, + bloaty_blob_binary: WasmBinaryBloaty, + blob_name: &str, + check_for_runtime_version_section: bool, + build_config: &BuildConfiguration, +) -> (Option, WasmBinaryBloaty) { + // Try to compact and compress the bloaty blob, if the *outer* profile wants it. + // + // This is because, by default the inner profile will be set to `Release` even when the outer + // profile is `Debug`, because the blob built in `Debug` profile is too slow for normal + // development activities. + let (compact_blob_path, compact_compressed_blob_path) = + if build_config.outer_build_profile.wants_compact() { + let compact_blob_path = compact_wasm(&project, blob_name, &bloaty_blob_binary); + let compact_compressed_blob_path = compact_blob_path + .as_ref() + .and_then(|p| try_compress_blob(&p.0, blob_name)); + (compact_blob_path, compact_compressed_blob_path) + } else { + // We at least want to lower the `sign-ext` code to `mvp`. + wasm_opt::OptimizationOptions::new_opt_level_0() + .add_pass(wasm_opt::Pass::SignextLowering) + .run( + bloaty_blob_binary.bloaty_path(), + bloaty_blob_binary.bloaty_path(), + ) + .expect("Failed to lower sign-ext in WASM binary."); + + (None, None) + }; + + if check_for_runtime_version_section { + ensure_runtime_version_wasm_section_exists(bloaty_blob_binary.bloaty_path()); + } + + let final_blob_binary = compact_compressed_blob_path.or(compact_blob_path); + + final_blob_binary + .as_ref() + .map(|binary| copy_blob_to_target_directory(wasm_project_cargo_toml, binary)); + + (final_blob_binary, bloaty_blob_binary) +} + +/// Ensures that the `runtime_version` section exists in the given blob. +/// +/// If the section can not be found, it will print an error and exit the builder. +fn ensure_runtime_version_wasm_section_exists(blob_path: &Path) { + let blob = fs::read(blob_path).expect("`{blob_path}` was just written and should exist; qed"); + + let module: Module = match deserialize_buffer(&blob) { + Ok(m) => m, + Err(e) => { + println!("Failed to deserialize `{}`: {e:?}", blob_path.display()); + process::exit(1); + } + }; + + if !module + .custom_sections() + .any(|cs| cs.name() == "runtime_version") + { + println!( + "Couldn't find the `runtime_version` section. \ + Please ensure that you are using the `sp_version::runtime_version` attribute macro!" + ); + process::exit(1); + } +} + +/// Adjust the mtime of the bloaty and compressed/compact wasm files. +/// +/// We add the bloaty and the compressed/compact wasm file to the `rerun-if-changed` files. +/// Cargo/Rustc determines based on the timestamp of the `invoked.timestamp` file that can be found +/// in the `OUT_DIR/..`, if it needs to rerun a `build.rs` script. The problem is that this +/// `invoked.timestamp` is created when the `build.rs` is executed and the wasm binaries are created +/// later. This leads to them having a later mtime than the `invoked.timestamp` file and thus, +/// cargo/rustc always re-executes the `build.rs` script. To hack around this, we copy the mtime of +/// the `invoked.timestamp` to the wasm binaries. +fn adjust_mtime( + bloaty_wasm: &WasmBinaryBloaty, + compressed_or_compact_wasm: Option<&WasmBinary>, +) -> std::io::Result<()> { + let out_dir = build_helper::out_dir(); + let invoked_timestamp = out_dir.join("../invoked.timestamp"); + + // Get the mtime of the `invoked.timestamp` + let metadata = fs::metadata(invoked_timestamp)?; + let mtime = filetime::FileTime::from_last_modification_time(&metadata); + + filetime::set_file_mtime(bloaty_wasm.bloaty_path(), mtime)?; + if let Some(binary) = compressed_or_compact_wasm.as_ref() { + filetime::set_file_mtime(binary.wasm_binary_path(), mtime)?; + } + + Ok(()) +} + +/// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable. +/// +/// If the `Cargo.lock` cannot be found, we emit a warning and return `None`. +fn find_cargo_lock(cargo_manifest: &Path) -> Option { + fn find_impl(mut path: PathBuf) -> Option { + loop { + if path.join("Cargo.lock").exists() { + return Some(path.join("Cargo.lock")); + } + + if !path.pop() { + return None; + } + } + } + + if let Ok(workspace) = env::var(crate::WASM_BUILD_WORKSPACE_HINT) { + let path = PathBuf::from(workspace); + + if path.join("Cargo.lock").exists() { + return Some(path.join("Cargo.lock")); + } else { + build_helper::warning!( + "`{}` env variable doesn't point to a directory that contains a `Cargo.lock`.", + crate::WASM_BUILD_WORKSPACE_HINT, + ); + } + } + + if let Some(path) = find_impl(build_helper::out_dir()) { + return Some(path); + } + + build_helper::warning!( + "Could not find `Cargo.lock` for `{}`, while searching from `{}`. \ + To fix this, point the `{}` env variable to the directory of the workspace being compiled.", + cargo_manifest.display(), + build_helper::out_dir().display(), + crate::WASM_BUILD_WORKSPACE_HINT, + ); + + None +} + +/// Extract the crate name from the given `Cargo.toml`. +fn get_crate_name(cargo_manifest: &Path) -> String { + let cargo_toml: Table = toml::from_str( + &fs::read_to_string(cargo_manifest).expect("File exists as checked before; qed"), + ) + .expect("Cargo manifest is a valid toml file; qed"); + + let package = cargo_toml + .get("package") + .and_then(|t| t.as_table()) + .expect("`package` key exists in valid `Cargo.toml`; qed"); + + package + .get("name") + .and_then(|p| p.as_str()) + .map(ToOwned::to_owned) + .expect("Package name exists; qed") +} + +/// Extract the `lib.name` from the given `Cargo.toml`. +fn get_lib_name(cargo_manifest: &Path) -> Option { + let cargo_toml: Table = toml::from_str( + &fs::read_to_string(cargo_manifest).expect("File exists as checked before; qed"), + ) + .expect("Cargo manifest is a valid toml file; qed"); + + let lib = cargo_toml.get("lib").and_then(|t| t.as_table())?; + + lib.get("name") + .and_then(|p| p.as_str()) + .map(ToOwned::to_owned) +} + +/// Returns the name for the blob binary. +fn get_blob_name(target: RuntimeTarget, cargo_manifest: &Path) -> String { + match target { + RuntimeTarget::Wasm => get_lib_name(cargo_manifest) + .expect("The wasm project should have a `lib.name`; qed") + .replace('-', "_"), + RuntimeTarget::Riscv => get_crate_name(cargo_manifest), + } +} + +/// Returns the root path of the wasm workspace. +fn get_wasm_workspace_root() -> PathBuf { + let mut out_dir = build_helper::out_dir(); + + loop { + match out_dir.parent() { + Some(parent) if out_dir.ends_with("build") => return parent.to_path_buf(), + _ => { + if !out_dir.pop() { + break; + } + } + } + } + + panic!( + "Could not find target dir in: {}", + build_helper::out_dir().display() + ) +} + +fn create_project_cargo_toml( + target: RuntimeTarget, + wasm_workspace: &Path, + workspace_root_path: &Path, + crate_name: &str, + crate_path: &Path, + enabled_features: impl Iterator, +) { + let mut workspace_toml: Table = toml::from_str( + &fs::read_to_string(workspace_root_path.join("Cargo.toml")) + .expect("Workspace root `Cargo.toml` exists; qed"), + ) + .expect("Workspace root `Cargo.toml` is a valid toml file; qed"); + + let mut wasm_workspace_toml = Table::new(); + + // Add different profiles which are selected by setting `WASM_BUILD_TYPE`. + let mut release_profile = Table::new(); + release_profile.insert("panic".into(), "abort".into()); + release_profile.insert("lto".into(), "thin".into()); + + let mut production_profile = Table::new(); + production_profile.insert("inherits".into(), "release".into()); + production_profile.insert("lto".into(), "fat".into()); + production_profile.insert("codegen-units".into(), 1.into()); + + let mut dev_profile = Table::new(); + dev_profile.insert("panic".into(), "abort".into()); + + let mut profile = Table::new(); + profile.insert("release".into(), release_profile.into()); + profile.insert("production".into(), production_profile.into()); + profile.insert("dev".into(), dev_profile.into()); + + wasm_workspace_toml.insert("profile".into(), profile.into()); + + // Add patch section from the project root `Cargo.toml` + while let Some(mut patch) = workspace_toml + .remove("patch") + .and_then(|p| p.try_into::
().ok()) + { + // Iterate over all patches and make the patch path absolute from the workspace root path. + patch + .iter_mut() + .filter_map(|p| { + p.1.as_table_mut() + .map(|t| t.iter_mut().filter_map(|t| t.1.as_table_mut())) + }) + .flatten() + .for_each(|p| { + p.iter_mut() + .filter(|(k, _)| k == &"path") + .for_each(|(_, v)| { + if let Some(path) = v.as_str().map(PathBuf::from) { + if path.is_relative() { + *v = workspace_root_path.join(path).display().to_string().into(); + } + } + }) + }); + + wasm_workspace_toml.insert("patch".into(), patch.into()); + } + + let mut package = Table::new(); + package.insert("name".into(), format!("{}-blob", crate_name).into()); + package.insert("version".into(), "1.0.0".into()); + package.insert("edition".into(), "2021".into()); + + wasm_workspace_toml.insert("package".into(), package.into()); + + if target == RuntimeTarget::Wasm { + let mut lib = Table::new(); + lib.insert("name".into(), crate_name.replace("-", "_").into()); + lib.insert("crate-type".into(), vec!["cdylib".to_string()].into()); + wasm_workspace_toml.insert("lib".into(), lib.into()); + } + + let mut dependencies = Table::new(); + + let mut wasm_project = Table::new(); + wasm_project.insert("package".into(), crate_name.into()); + wasm_project.insert("path".into(), crate_path.display().to_string().into()); + wasm_project.insert("default-features".into(), false.into()); + wasm_project.insert( + "features".into(), + enabled_features.collect::>().into(), + ); + + dependencies.insert("wasm-project".into(), wasm_project.into()); + + wasm_workspace_toml.insert("dependencies".into(), dependencies.into()); + + let mut workspace = Table::new(); + workspace.insert("resolver".into(), "2".into()); + + wasm_workspace_toml.insert("workspace".into(), workspace.into()); + + if target == RuntimeTarget::Riscv { + // This dependency currently doesn't compile under RISC-V, so patch it with our own fork. + // + // TODO: Remove this once a new version of `bitvec` (which uses a new version of `radium` + // which doesn't have this problem) is released on crates.io. + let patch = toml::toml! { + [crates-io] + radium = { git = "https://github.com/paritytech/radium-0.7-fork.git", rev = "a5da15a15c90fd169d661d206cf0db592487f52b" } + }; + wasm_workspace_toml.insert("patch".into(), patch.into()); + } + + write_file_if_changed( + wasm_workspace.join("Cargo.toml"), + toml::to_string_pretty(&wasm_workspace_toml).expect("Wasm workspace toml is valid; qed"), + ); +} + +/// Find a package by the given `manifest_path` in the metadata. In case it can't be found by its +/// manifest_path, fallback to finding it by name; this is necessary during publish because the +/// package's manifest path will be *generated* within a specific packaging directory, thus it won't +/// be found by its original path anymore. +/// +/// Panics if the package could not be found. +fn find_package_by_manifest_path<'a>( + pkg_name: &str, + manifest_path: &Path, + crate_metadata: &'a cargo_metadata::Metadata, +) -> &'a cargo_metadata::Package { + if let Some(pkg) = crate_metadata + .packages + .iter() + .find(|p| p.manifest_path == manifest_path) + { + return pkg; + } + + let pkgs_by_name = crate_metadata + .packages + .iter() + .filter(|p| *p.name == pkg_name) + .collect::>(); + + if let Some(pkg) = pkgs_by_name.first() { + if pkgs_by_name.len() > 1 { + panic!( + "Found multiple packages matching the name {pkg_name} ({manifest_path:?}): {:?}", + pkgs_by_name + ); + } else { + return pkg; + } + } else { + panic!("Failed to find entry for package {pkg_name} ({manifest_path:?})."); + } +} + +/// Get a list of enabled features for the project. +fn project_enabled_features( + pkg_name: &str, + cargo_manifest: &Path, + crate_metadata: &cargo_metadata::Metadata, +) -> Vec { + let package = find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); + + let std_enabled = package.features.get("std"); + + let mut enabled_features = package + .features + .iter() + .filter(|(f, v)| { + let mut feature_env = f.replace("-", "_"); + feature_env.make_ascii_uppercase(); + + // If this is a feature that corresponds only to an optional dependency + // and this feature is enabled by the `std` feature, we assume that this + // is only done through the `std` feature. This is a bad heuristic and should + // be removed after namespaced features are landed: + // https://doc.rust-lang.org/cargo/reference/unstable.html#namespaced-features + // Then we can just express this directly in the `Cargo.toml` and do not require + // this heuristic anymore. However, for the transition phase between now and namespaced + // features already being present in nightly, we need this code to make + // runtimes compile with all the possible rustc versions. + if v.len() == 1 + && v.get(0).map_or(false, |v| *v == format!("dep:{}", f)) + && std_enabled + .as_ref() + .map(|e| e.iter().any(|ef| ef == *f)) + .unwrap_or(false) + { + return false; + } + + // We don't want to enable the `std`/`default` feature for the wasm build and + // we need to check if the feature is enabled by checking the env variable. + *f != "std" + && *f != "default" + && env::var(format!("CARGO_FEATURE_{}", feature_env)) + .map(|v| v == "1") + .unwrap_or_default() + }) + .map(|d| d.0.clone()) + .collect::>(); + + enabled_features.sort(); + enabled_features +} + +/// Returns if the project has the `runtime-wasm` feature +fn has_runtime_wasm_feature_declared( + pkg_name: &str, + cargo_manifest: &Path, + crate_metadata: &cargo_metadata::Metadata, +) -> bool { + let package = find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); + + package.features.keys().any(|k| k == "runtime-wasm") +} + +/// Create the project used to build the wasm binary. +/// +/// # Returns +/// +/// The path to the created wasm project. +fn create_project( + target: RuntimeTarget, + project_cargo_toml: &Path, + wasm_workspace: &Path, + crate_metadata: &Metadata, + workspace_root_path: &Path, + features_to_enable: Vec, +) -> PathBuf { + let crate_name = get_crate_name(project_cargo_toml); + let crate_path = project_cargo_toml + .parent() + .expect("Parent path exists; qed"); + let wasm_project_folder = wasm_workspace.join(&crate_name); + + fs::create_dir_all(wasm_project_folder.join("src")) + .expect("Wasm project dir create can not fail; qed"); + + let mut enabled_features = + project_enabled_features(&crate_name, project_cargo_toml, crate_metadata); + + if has_runtime_wasm_feature_declared(&crate_name, project_cargo_toml, crate_metadata) { + enabled_features.push("runtime-wasm".into()); + } + + let mut enabled_features = enabled_features.into_iter().collect::>(); + enabled_features.extend(features_to_enable.into_iter()); + + create_project_cargo_toml( + target, + &wasm_project_folder, + workspace_root_path, + &crate_name, + crate_path, + enabled_features.into_iter(), + ); + + match target { + RuntimeTarget::Wasm => { + write_file_if_changed( + wasm_project_folder.join("src/lib.rs"), + "#![no_std] #![allow(unused_imports)] pub use wasm_project::*;", + ); + } + RuntimeTarget::Riscv => { + write_file_if_changed( + wasm_project_folder.join("src/main.rs"), + "#![no_std] #![no_main] #![allow(unused_imports)] pub use wasm_project::*;", + ); + } + } + + if let Some(crate_lock_file) = find_cargo_lock(project_cargo_toml) { + // Use the `Cargo.lock` of the main project. + crate::copy_file_if_changed(crate_lock_file, wasm_project_folder.join("Cargo.lock")); + } + + wasm_project_folder +} + +/// A rustc profile. +#[derive(Clone, Debug, EnumIter)] +enum Profile { + /// The `--profile dev` profile. + Debug, + /// The `--profile release` profile. + Release, + /// The `--profile production` profile. + Production, +} + +impl Profile { + /// The name of the profile as supplied to the cargo `--profile` cli option. + fn name(&self) -> &'static str { + match self { + Self::Debug => "dev", + Self::Release => "release", + Self::Production => "production", + } + } + + /// The sub directory within `target` where cargo places the build output. + /// + /// # Note + /// + /// Usually this is the same as [`Self::name`] with the exception of the debug + /// profile which is called `dev`. + fn directory(&self) -> &'static str { + match self { + Self::Debug => "debug", + _ => self.name(), + } + } + + /// Whether the resulting binary should be compacted and compressed. + fn wants_compact(&self) -> bool { + !matches!(self, Self::Debug) + } +} + +/// The build configuration for this build. +#[derive(Debug)] +struct BuildConfiguration { + /// The profile that is used to build the outer project. + pub outer_build_profile: Profile, + /// The profile to use to build the runtime blob. + pub blob_build_profile: Profile, +} + +impl BuildConfiguration { + /// Create a [`BuildConfiguration`] by detecting which profile is used for the main build and + /// checking any env var overrides. + /// + /// We cannot easily determine the profile that is used by the main cargo invocation + /// because the `PROFILE` environment variable won't contain any custom profiles like + /// "production". It would only contain the builtin profile where the custom profile + /// inherits from. This is why we inspect the build path to learn which profile is used. + /// + /// When not overridden by a env variable we always default to building wasm with the `Release` + /// profile even when the main build uses the debug build. This is because wasm built with the + /// `Debug` profile is too slow for normal development activities and almost never intended. + /// + /// When cargo is building in `--profile dev`, user likely intends to compile fast, so we don't + /// bother producing compact or compressed blobs. + /// + /// # Note + /// + /// Can be overridden by setting [`crate::WASM_BUILD_TYPE_ENV`]. + fn detect(target: RuntimeTarget, wasm_project: &Path) -> Self { + let (name, overridden) = if let Ok(name) = env::var(crate::WASM_BUILD_TYPE_ENV) { + (name, true) + } else { + // First go backwards to the beginning of the target directory. + // Then go forwards to find the build subdirectory. + // We need to go backwards first because when starting from the root there + // might be a chance that someone has a directory somewhere in the path with the same + // name. + let name = wasm_project + .components() + .rev() + .take_while(|c| c.as_os_str() != "target") + .collect::>() + .iter() + .rev() + .take_while(|c| c.as_os_str() != target.build_subdirectory()) + .last() + .expect("We put the runtime project within a `target/.../[rw]build` path; qed") + .as_os_str() + .to_str() + .expect("All our profile directory names are ascii; qed") + .to_string(); + (name, false) + }; + let outer_build_profile = Profile::iter().find(|p| p.directory() == name); + let blob_build_profile = match (outer_build_profile.clone(), overridden) { + // When not overridden by a env variable we default to using the `Release` profile + // for the wasm build even when the main build uses the debug build. This + // is because the `Debug` profile is too slow for normal development activities. + (Some(Profile::Debug), false) => Profile::Release, + // For any other profile or when overridden we take it at face value. + (Some(profile), _) => profile, + // For non overridden unknown profiles we fall back to `Release`. + // This allows us to continue building when a custom profile is used for the + // main builds cargo. When explicitly passing a profile via env variable we are + // not doing a fallback. + (None, false) => { + let profile = Profile::Release; + build_helper::warning!( + "Unknown cargo profile `{name}`. Defaulted to `{profile:?}` for the runtime build.", + ); + profile + } + // Invalid profile specified. + (None, true) => { + // We use println! + exit instead of a panic in order to have a cleaner output. + println!( + "Unexpected profile name: `{name}`. One of the following is expected: {:?}", + Profile::iter().map(|p| p.directory()).collect::>(), + ); + process::exit(1); + } + }; + BuildConfiguration { + outer_build_profile: outer_build_profile.unwrap_or(Profile::Release), + blob_build_profile, + } + } +} + +/// Check environment whether we should build without network +fn offline_build() -> bool { + env::var(OFFLINE).map_or(false, |v| v == "true") +} + +/// Build the project and create the bloaty runtime blob. +/// +/// Returns the path to the generated bloaty runtime blob. +fn build_bloaty_blob( + target: RuntimeTarget, + blob_build_profile: &Profile, + project: &Path, + default_cargo_flags: &[String], + default_rustflags: &str, + cargo_cmd: CargoCommandVersioned, + #[cfg(feature = "metadata-hash")] metadata_hash: Option<[u8; 32]>, +) -> PathBuf { + let manifest_path = project.join("Cargo.toml"); + let mut build_cmd = cargo_cmd.command(); + + let mut rustflags = String::new(); + match target { + RuntimeTarget::Wasm => { + // For Rust >= 1.70 and Rust < 1.84 with `wasm32-unknown-unknown` target, + // it's required to disable default WASM features: + // - `sign-ext` (since Rust 1.70) + // - `multivalue` and `reference-types` (since Rust 1.82) + // + // For Rust >= 1.84, we use `wasm32v1-none` target + // (disables all "post-MVP" WASM features except `mutable-globals`): + // - https://doc.rust-lang.org/beta/rustc/platform-support/wasm32v1-none.html + // + // Also see: + // https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features.html#disabling-on-by-default-webassembly-proposals + + if !cargo_cmd.supports_wasm32v1_none_target() { + rustflags.push_str("-C target-cpu=mvp "); + } + + rustflags.push_str("-C link-arg=--export-table "); + } + RuntimeTarget::Riscv => { + rustflags.push_str("-C target-feature=+lui-addi-fusion -C relocation-model=pie -C link-arg=--emit-relocs -C link-arg=--unique "); + } + } + + rustflags.push_str(default_rustflags); + rustflags.push_str(" --cfg substrate_runtime "); + rustflags.push_str(&env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default()); + + build_cmd + .arg("rustc") + .arg(format!("--target={}", target.rustc_target(&cargo_cmd))) + .arg(format!("--manifest-path={}", manifest_path.display())) + .args(default_cargo_flags) + .env("RUSTFLAGS", rustflags) + // Manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir + // exclusive). The runner project is created in `CARGO_TARGET_DIR` and executing it will + // create a sub target directory inside of `CARGO_TARGET_DIR`. + .env( + "CARGO_TARGET_DIR", + &project.join("target").display().to_string(), + ) + // As we are being called inside a build-script, this env variable is set. However, we set + // our own `RUSTFLAGS` and thus, we need to remove this. Otherwise cargo favors this + // env variable. + .env_remove("CARGO_ENCODED_RUSTFLAGS") + // Make sure if we're called from within a `build.rs` the host toolchain won't override a + // rustup toolchain we've picked. + .env_remove("RUSTC") + // We don't want to call ourselves recursively + .env(crate::SKIP_BUILD_ENV, ""); + + #[cfg(feature = "metadata-hash")] + if let Some(hash) = metadata_hash { + build_cmd.env("RUNTIME_METADATA_HASH", array_bytes::bytes2hex("0x", &hash)); + } + + if super::color_output_enabled() { + build_cmd.arg("--color=always"); + } + + build_cmd.arg("--profile"); + build_cmd.arg(blob_build_profile.name()); + + if offline_build() { + build_cmd.arg("--offline"); + } + + // For Rust >= 1.70 and Rust < 1.84 with `wasm32-unknown-unknown` target, + // it's required to disable default WASM features: + // - `sign-ext` (since Rust 1.70) + // - `multivalue` and `reference-types` (since Rust 1.82) + // + // For Rust >= 1.84, we use `wasm32v1-none` target + // (disables all "post-MVP" WASM features except `mutable-globals`): + // - https://doc.rust-lang.org/beta/rustc/platform-support/wasm32v1-none.html + // + // Our executor currently only supports the WASM MVP feature set, however nowadays + // when compiling WASM the Rust compiler has more features enabled by default. + // + // We do set the `-C target-cpu=mvp` flag to make sure that *our* code gets compiled + // in a way that is compatible with our executor, however this doesn't affect Rust's + // standard library crates (`std`, `core` and `alloc`) which are by default precompiled + // and still can make use of these extra features. + // + // So here we force the compiler to also compile the standard library crates for us + // to make sure that they also only use the MVP features. + // + // So the `-Zbuild-std` and `RUSTC_BOOTSTRAP=1` hacks are only used for Rust < 1.84. + // + // Also see: + // https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features.html#disabling-on-by-default-webassembly-proposals + if crate::build_std_required(&cargo_cmd) { + // Unfortunately this is still a nightly-only flag, but FWIW it is pretty widely used + // so it's unlikely to break without a replacement. + // We only build `core` and `alloc` crates since wasm-builder disables `std` feature for + // runtime. Thus the runtime is `#![no_std]` crate. + build_cmd.arg("-Z").arg("build-std=core,alloc"); + if !cargo_cmd.supports_nightly_features() { + build_cmd.env("RUSTC_BOOTSTRAP", "1"); + } + } + + // Inherit jobserver in child cargo command to ensure we don't try to use more concurrency than + // available + if let Some(c) = get_jobserver() { + c.configure(&mut build_cmd); + } + + println!( + "{}", + colorize_info_message("Information that should be included in a bug report.") + ); + println!( + "{} {:?}", + colorize_info_message("Executing build command:"), + build_cmd + ); + println!( + "{} {}", + colorize_info_message("Using rustc version:"), + cargo_cmd.rustc_version() + ); + + // Use `process::exit(1)` to have a clean error output. + if !build_cmd.status().map_or(false, |s| s.success()) { + process::exit(1); + } + + let blob_name = get_blob_name(target, &manifest_path); + let target_directory = project + .join("target") + .join(target.rustc_target(&cargo_cmd)) + .join(blob_build_profile.directory()); + match target { + RuntimeTarget::Riscv => { + let elf_path = target_directory.join(&blob_name); + let elf_metadata = match elf_path.metadata() { + Ok(path) => path, + Err(error) => { + panic!("internal error: couldn't read the metadata of {elf_path:?}: {error}") + } + }; + + let polkavm_path = target_directory.join(format!("{}.polkavm", blob_name)); + if polkavm_path + .metadata() + .map(|polkavm_metadata| { + polkavm_metadata.modified().unwrap() < elf_metadata.modified().unwrap() + }) + .unwrap_or(true) + { + let blob_bytes = + std::fs::read(elf_path).expect("binary always exists after its built"); + + let mut config = polkavm_linker::Config::default(); + config.set_strip(true); // TODO: This shouldn't always be done. + + let program = match polkavm_linker::program_from_elf(config, &blob_bytes) { + Ok(program) => program, + Err(error) => { + println!("Failed to link the runtime blob; this is probably a bug!"); + println!("Linking error: {error}"); + process::exit(1); + } + }; + + std::fs::write(&polkavm_path, program.as_bytes()) + .expect("writing the blob to a file always works"); + } + + polkavm_path + } + RuntimeTarget::Wasm => target_directory.join(format!("{}.wasm", blob_name)), + } +} + +fn compact_wasm( + project: &Path, + blob_name: &str, + bloaty_binary: &WasmBinaryBloaty, +) -> Option { + let wasm_compact_path = project.join(format!("{blob_name}.compact.wasm")); + let start = std::time::Instant::now(); + wasm_opt::OptimizationOptions::new_opt_level_0() + .mvp_features_only() + .debug_info(true) + .add_pass(wasm_opt::Pass::StripDwarf) + .add_pass(wasm_opt::Pass::SignextLowering) + .run(bloaty_binary.bloaty_path(), &wasm_compact_path) + .expect("Failed to compact generated WASM binary."); + + println!( + "{} {}", + colorize_info_message("Compacted wasm in"), + colorize_info_message(format!("{:?}", start.elapsed()).as_str()) + ); + + Some(WasmBinary(wasm_compact_path)) +} + +fn try_compress_blob(compact_blob_path: &Path, out_name: &str) -> Option { + use sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT; + + let project = compact_blob_path + .parent() + .expect("blob path should have a parent directory"); + let compact_compressed_blob_path = + project.join(format!("{}.compact.compressed.wasm", out_name)); + + let start = std::time::Instant::now(); + let data = fs::read(compact_blob_path).expect("Failed to read WASM binary"); + if let Some(compressed) = sp_maybe_compressed_blob::compress(&data, CODE_BLOB_BOMB_LIMIT) { + fs::write(&compact_compressed_blob_path, &compressed[..]) + .expect("Failed to write WASM binary"); + + println!( + "{} {}", + colorize_info_message("Compressed blob in"), + colorize_info_message(format!("{:?}", start.elapsed()).as_str()) + ); + Some(WasmBinary(compact_compressed_blob_path)) + } else { + build_helper::warning!( + "Writing uncompressed blob. Exceeded maximum size {}", + CODE_BLOB_BOMB_LIMIT, + ); + println!("{}", colorize_info_message("Skipping blob compression")); + None + } +} + +/// Custom wrapper for a [`cargo_metadata::Package`] to store it in +/// a `HashSet`. +#[derive(Debug)] +struct DeduplicatePackage<'a> { + package: &'a cargo_metadata::Package, + identifier: String, +} + +impl<'a> From<&'a cargo_metadata::Package> for DeduplicatePackage<'a> { + fn from(package: &'a cargo_metadata::Package) -> Self { + Self { + package, + identifier: format!("{}{}{:?}", package.name, package.version, package.source), + } + } +} + +impl<'a> Hash for DeduplicatePackage<'a> { + fn hash(&self, state: &mut H) { + self.identifier.hash(state); + } +} + +impl<'a> PartialEq for DeduplicatePackage<'a> { + fn eq(&self, other: &Self) -> bool { + self.identifier == other.identifier + } +} + +impl<'a> Eq for DeduplicatePackage<'a> {} + +impl<'a> Deref for DeduplicatePackage<'a> { + type Target = cargo_metadata::Package; + + fn deref(&self) -> &Self::Target { + self.package + } +} + +fn create_metadata_command(path: impl Into) -> MetadataCommand { + let mut metadata_command = MetadataCommand::new(); + metadata_command.manifest_path(path); + + if offline_build() { + metadata_command.other_options(vec!["--offline".to_owned()]); + } + + // As we are being called inside a build-script, this env variable is set. + // However, this can lead to cross-compilation errors. + metadata_command.env_remove("CARGO_ENCODED_RUSTFLAGS"); + + metadata_command +} + +/// Generate the `rerun-if-changed` instructions for cargo to make sure that the WASM binary is +/// rebuilt when needed. +fn generate_rerun_if_changed_instructions( + cargo_manifest: &Path, + project_folder: &Path, + wasm_workspace: &Path, + compressed_or_compact_wasm: Option<&WasmBinary>, + bloaty_wasm: &WasmBinaryBloaty, +) { + // Rerun `build.rs` if the `Cargo.lock` changes + if let Some(cargo_lock) = find_cargo_lock(cargo_manifest) { + rerun_if_changed(cargo_lock); + } + + let metadata = create_metadata_command(project_folder.join("Cargo.toml")) + .exec() + .expect("`cargo metadata` can not fail!"); + + let package = metadata + .packages + .iter() + .find(|p| p.manifest_path == cargo_manifest) + .expect("The crate package is contained in its own metadata; qed"); + + // Start with the dependencies of the crate we want to compile for wasm. + let mut dependencies = package.dependencies.iter().collect::>(); + + // Collect all packages by follow the dependencies of all packages we find. + let mut packages = HashSet::new(); + packages.insert(DeduplicatePackage::from(package)); + + while let Some(dependency) = dependencies.pop() { + // Ignore all dev dependencies + if dependency.kind == DependencyKind::Development { + continue; + } + + let path_or_git_dep = dependency + .source + .as_ref() + .map(|s| s.repr.starts_with("git+")) + .unwrap_or(true); + + let package = metadata + .packages + .iter() + .filter(|p| !p.manifest_path.starts_with(wasm_workspace)) + .find(|p| { + // Check that the name matches and that the version matches or this is + // a git or path dep. A git or path dependency can only occur once, so we don't + // need to check the version. + (path_or_git_dep || dependency.req.matches(&p.version)) + && dependency.name == *p.name + }); + + if let Some(package) = package { + if packages.insert(DeduplicatePackage::from(package)) { + dependencies.extend(package.dependencies.iter()); + } + } + } + + // Make sure that if any file/folder of a dependency change, we need to rerun the `build.rs` + packages.iter().for_each(package_rerun_if_changed); + + compressed_or_compact_wasm.map(|w| rerun_if_changed(w.wasm_binary_path())); + rerun_if_changed(bloaty_wasm.bloaty_path()); + + // Register our env variables + println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TYPE_ENV); + println!( + "cargo:rerun-if-env-changed={}", + crate::WASM_BUILD_RUSTFLAGS_ENV + ); + println!( + "cargo:rerun-if-env-changed={}", + crate::WASM_TARGET_DIRECTORY + ); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TOOLCHAIN); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_STD); + println!("cargo:rerun-if-env-changed={}", crate::RUNTIME_TARGET); +} + +/// Track files and paths related to the given package to rerun `build.rs` on any relevant change. +fn package_rerun_if_changed(package: &DeduplicatePackage) { + let mut manifest_path = package.manifest_path.clone(); + if manifest_path.ends_with("Cargo.toml") { + manifest_path.pop(); + } + + WalkDir::new(&manifest_path) + .into_iter() + .filter_entry(|p| { + // Ignore this entry if it is a directory that contains a `Cargo.toml` that is not the + // `Cargo.toml` related to the current package. This is done to ignore sub-crates of a + // crate. If such a sub-crate is a dependency, it will be processed independently + // anyway. + p.path() == manifest_path || !p.path().is_dir() || !p.path().join("Cargo.toml").exists() + }) + .filter_map(|p| p.ok().map(|p| p.into_path())) + .filter(|p| { + p.extension() + .map(|e| e == "rs" || e == "toml") + .unwrap_or_default() + }) + .for_each(rerun_if_changed); +} + +/// Copy the blob binary to the target directory set in `WASM_TARGET_DIRECTORY` environment +/// variable. If the variable is not set, this is a no-op. +fn copy_blob_to_target_directory(cargo_manifest: &Path, blob_binary: &WasmBinary) { + let target_dir = match env::var(crate::WASM_TARGET_DIRECTORY) { + Ok(path) => PathBuf::from(path), + Err(_) => return, + }; + + if !target_dir.is_absolute() { + // We use println! + exit instead of a panic in order to have a cleaner output. + println!( + "Environment variable `{}` with `{}` is not an absolute path!", + crate::WASM_TARGET_DIRECTORY, + target_dir.display(), + ); + process::exit(1); + } + + fs::create_dir_all(&target_dir).expect("Creates `WASM_TARGET_DIRECTORY`."); + + fs::copy( + blob_binary.wasm_binary_path(), + target_dir.join(format!( + "{}.wasm", + get_blob_name(RuntimeTarget::Wasm, cargo_manifest) + )), + ) + .expect("Copies blob binary to `WASM_TARGET_DIRECTORY`."); +} + +// Get jobserver from parent cargo command +pub fn get_jobserver() -> &'static Option { + static JOBSERVER: OnceLock> = OnceLock::new(); + + JOBSERVER.get_or_init(|| { + // Unsafe because it deals with raw fds + unsafe { jobserver::Client::from_env() } + }) +} diff --git a/utils/crates-io/src/handler.rs b/utils/crates-io/src/handler.rs index 47ee624182d..dea7ef7adbb 100644 --- a/utils/crates-io/src/handler.rs +++ b/utils/crates-io/src/handler.rs @@ -12,12 +12,19 @@ pub const GP_RUNTIME_INTERFACE_VERSION: &str = "18.0.0"; /// Get the crates-io name of the provided package. pub fn crates_io_name(pkg: &str) -> &str { - // `gear-core-processor` is taken by others, see the docs - // of [`core-processor::patch_workspace`] for more details. - if pkg == "gear-core-processor" { - "core-processor" - } else { - pkg + match pkg { + // `gear-core-processor` is taken by others, see the docs + // of [`core_processor::patch_workspace`] for more details. + "gear-core-processor" => "core-processor", + "sp-allocator" => "gsp-allocator", + "sp-wasm-interface" => "gsp-wasm-interface", + "sp-wasm-interface-common" => "gsp-wasm-interface-common", + "sc-executor" => "gsc-executor", + "sc-executor-common" => "gsc-executor-common", + "sc-executor-polkavm" => "gsc-executor-polkavm", + "sc-executor-wasmtime" => "gsc-executor-wasmtime", + "substrate-wasm-builder" => "gsubstrate-wasm-builder", + _ => pkg, } } @@ -26,16 +33,25 @@ pub fn patch(pkg: &Package, is_published: bool, is_actualized: bool) -> Result { + substrate_fork::patch_manifest(local_name, doc) + } "ethexe-rpc" => ethexe_rpc::patch(doc), "gear-core-processor" => core_processor::patch(doc), "gear-sandbox" => sandbox::patch(doc), - "gear-sandbox-host" => sandbox_host::patch(doc), "gear-sandbox-interface" => sandbox_interface::patch(doc), _ => {} } - - Ok(manifest) } /// Patch package alias. @@ -49,8 +65,12 @@ pub fn patch_alias(index: &mut Vec<&str>) { /// Patch the workspace manifest. pub fn patch_workspace(name: &str, table: &mut toml_edit::InlineTable) { + patch_workspace_alias(name, table); + match name { - "core-processor" | "gear-core-processor" => core_processor::patch_workspace(name, table), + local_name if crate::GEAR_SUBSTRATE_DEPENDENCIES.contains(&local_name) => { + substrate_fork::patch_workspace(local_name, table) + } sub if ["sc-", "sp-", "frame-", "try-runtime-cli"] .iter() .any(|p| sub.starts_with(p)) => @@ -61,6 +81,77 @@ pub fn patch_workspace(name: &str, table: &mut toml_edit::InlineTable) { } } +/// Patch the workspace manifest for publish-only state. +pub fn patch_publish_workspace(doc: &mut toml_edit::DocumentMut) { + substrate_fork::patch_publish_workspace(doc); +} + +/// Patch workspace aliases required by package manifest patches. +pub fn patch_workspace_alias(name: &str, table: &mut toml_edit::InlineTable) { + match name { + "core-processor" | "gear-core-processor" => core_processor::patch_workspace(name, table), + _ => {} + } +} + +/// Gear-maintained Polkadot SDK-compatible local crates. +mod substrate_fork { + use toml_edit::{DocumentMut, InlineTable}; + + /// Rename the package manifest to the Gear-owned crates.io alias. + pub fn patch_manifest(local_name: &str, manifest: &mut DocumentMut) { + let crates_io_name = super::crates_io_name(local_name); + + manifest["package"]["name"] = toml_edit::value(crates_io_name); + manifest["package"]["documentation"] = + toml_edit::value(format!("https://docs.rs/{crates_io_name}")); + + if local_name == "sc-executor-wasmtime" { + // `sc-runtime-test` is a Polkadot SDK git-only dev dependency and + // is not part of the Gear crates.io publish set. + if let Some(dev_deps) = manifest["dev-dependencies"].as_table_like_mut() { + dev_deps.remove("sc-runtime-test"); + } + } + + if local_name == "substrate-wasm-builder" { + super::substrate_wasm_builder::patch(manifest); + } + } + + /// Point the workspace dependency to the Gear-owned crates.io alias. + pub fn patch_workspace(local_name: &str, table: &mut InlineTable) { + table.insert("package", super::crates_io_name(local_name).into()); + + table.remove("branch"); + table.remove("git"); + table.remove("rev"); + } + + /// Remove local Polkadot SDK source patches after copied crates are renamed. + pub fn patch_publish_workspace(manifest: &mut DocumentMut) { + let Some(patches) = manifest["patch"].as_table_like_mut() else { + return; + }; + + let source = "https://github.com/paritytech/polkadot-sdk.git"; + let Some(polkadot_sdk) = patches + .get_mut(source) + .and_then(toml_edit::Item::as_table_mut) + else { + return; + }; + + for local_name in crate::GEAR_SUBSTRATE_DEPENDENCIES { + polkadot_sdk.remove(local_name); + } + + if polkadot_sdk.is_empty() { + patches.remove(source); + } + } +} + /// ethexe-rpc handler. mod ethexe_rpc { use toml_edit::{Array, DocumentMut}; @@ -146,27 +237,59 @@ mod sandbox_interface { /// `sp_runtime_interface_proc_macro` includes some hardcode /// that could not locate alias packages. pub fn patch(manifest: &mut DocumentMut) { + if let Some(deps) = manifest["dependencies"].as_table_like_mut() { + deps.remove("sc-executor"); + } + + if let Some(features) = manifest["features"].as_table_like_mut() { + if let Some(default_features) = features + .get_mut("default") + .and_then(toml_edit::Item::as_array_mut) + { + default_features.retain(|feature| feature.as_str() != Some("host-api")); + } + + if let Some(host_api_features) = features + .get_mut("host-api") + .and_then(toml_edit::Item::as_array_mut) + { + host_api_features.retain(|feature| feature.as_str() != Some("sc-executor")); + } + } + let Some(wi) = manifest["dependencies"]["sp-runtime-interface"].as_table_like_mut() else { return; }; wi.insert("version", toml_edit::value(GP_RUNTIME_INTERFACE_VERSION)); wi.insert("package", toml_edit::value("gp-runtime-interface")); wi.remove("workspace"); + + let Some(wi) = manifest["dependencies"]["sp-wasm-interface"].as_table_like_mut() else { + return; + }; + // The copied stable2409 executor crates use upstream `sp-wasm-interface` + // 21.0.1, but `gear-sandbox-interface` still pairs with the old + // Gear-published runtime-interface stack. + wi.insert("version", toml_edit::value("15.0.0")); + wi.insert("package", toml_edit::value("gp-wasm-interface")); + wi.remove("workspace"); } } -/// sandbox_host handler. -mod sandbox_host { +/// substrate-wasm-builder handler. +mod substrate_wasm_builder { use toml_edit::DocumentMut; - /// Replace the wasmi module to the crates-io version. + /// Keep the optional `metadata-hash` feature on the upstream executor + /// stack. Gear only publishes the lower executor crates that are needed by + /// its crates.io packages. pub fn patch(manifest: &mut DocumentMut) { - let Some(wasmi) = manifest["dependencies"]["sandbox-wasmi"].as_table_like_mut() else { + let Some(sc_executor) = manifest["dependencies"]["sc-executor"].as_table_like_mut() else { return; }; - wasmi.insert("package", toml_edit::value("wasmi")); - wasmi.insert("version", toml_edit::value("0.13.2")); - wasmi.remove("workspace"); + + sc_executor.insert("version", toml_edit::value("0.40.1")); + sc_executor.remove("workspace"); } } @@ -188,18 +311,10 @@ mod substrate { // TODO: https://github.com/gear-tech/gear/issues/5485 pub fn patch_workspace(name: &str, table: &mut InlineTable) { match name { - // sp-allocator is outdated on crates.io, last - // 3.0.0 forever, here we use gp-allocator instead. - "sp-allocator" => { - table.insert("version", "4.1.2".into()); - table.insert("package", "gp-allocator".into()); - } - // Our sp-wasm-interface is different from the substrate one. - // - // ref: sp-wasm-interface-15.0.0 + // stable2409 executor crates require the upstream 21.0.1 API. "sp-wasm-interface" => { - table.insert("package", "gp-wasm-interface".into()); - table.insert("version", "15.0.0".into()); + table.insert("version", "21.0.1".into()); + table.remove("package"); } // Related to sp-wasm-interface. // @@ -219,7 +334,9 @@ mod substrate { _ => return, } + table.remove("path"); table.remove("branch"); table.remove("git"); + table.remove("rev"); } } diff --git a/utils/crates-io/src/lib.rs b/utils/crates-io/src/lib.rs index dcdefe20beb..6da80f097a3 100644 --- a/utils/crates-io/src/lib.rs +++ b/utils/crates-io/src/lib.rs @@ -44,6 +44,20 @@ pub const SAFE_DEPENDENCIES: &[&str] = &[ "gbuiltin-bls381", ]; +/// Local Polkadot SDK-compatible crates that Gear publishes under `g*` aliases. +/// +/// NOTE: Each package in this array could possibly depend on the previous one, +/// please be cautious about changing the order. +pub const GEAR_SUBSTRATE_DEPENDENCIES: &[&str] = &[ + "sp-wasm-interface-common", + "sp-allocator", + "sp-wasm-interface", + "sc-executor-common", + "sc-executor-polkavm", + "sc-executor-wasmtime", + "substrate-wasm-builder", +]; + /// Required packages with local dependencies. /// /// NOTE: Each package in this array could possibly depend diff --git a/utils/crates-io/src/main.rs b/utils/crates-io/src/main.rs index d240ca3996e..0bdef5ecc6f 100644 --- a/utils/crates-io/src/main.rs +++ b/utils/crates-io/src/main.rs @@ -47,16 +47,19 @@ async fn main() -> Result<()> { simulate, registry_path, } => { - let publisher = Publisher::with_simulation(simulate, registry_path)? + let mut publisher = Publisher::with_simulation(simulate, registry_path)? .build(true, version) - .await? - .check()?; - let result = publisher.publish(); + .await?; + let result = publisher.check().and_then(|()| { + publisher.prepare_publish()?; + publisher.publish() + }); publisher.restore()?; result } Command::Build => { - Publisher::new()?.build(false, None).await?; + let mut publisher = Publisher::new()?.build(false, None).await?; + publisher.prepare_publish()?; Ok(()) } } diff --git a/utils/crates-io/src/manifest.rs b/utils/crates-io/src/manifest.rs index 81509392357..bc402c62c52 100644 --- a/utils/crates-io/src/manifest.rs +++ b/utils/crates-io/src/manifest.rs @@ -7,11 +7,12 @@ use crate::{CARGO_REGISTRY_NAME, handler, version}; use anyhow::{Result, anyhow}; use cargo_metadata::Package; use std::{ + collections::BTreeMap, env, fs, ops::{Deref, DerefMut}, path::{Path, PathBuf}, }; -use toml_edit::{DocumentMut, Item}; +use toml_edit::{DocumentMut, InlineTable, Item}; const WORKSPACE_NAME: &str = "__gear_workspace"; @@ -77,10 +78,15 @@ impl Workspace { } /// Complete the versions of the specified crates. - pub fn complete(&mut self, mut index: Vec<&str>, simulate: bool) -> Result<()> { + pub fn complete( + &mut self, + mut index: Vec<&str>, + versions: &BTreeMap, + simulate: bool, + ) -> Result<()> { handler::patch_alias(&mut index); - let version = self.mutable_manifest["workspace"]["package"]["version"] + let workspace_version = self.mutable_manifest["workspace"]["package"]["version"] .clone() .as_str() .ok_or_else(|| anyhow!("Could not find version in workspace manifest"))? @@ -100,6 +106,7 @@ impl Workspace { continue; } + let version = versions.get(name).unwrap_or(&workspace_version); dep["version"] = toml_edit::value(format!("={version}")); if simulate { @@ -107,7 +114,7 @@ impl Workspace { } } - self.rename()?; + self.rename_aliases()?; Ok(()) } @@ -125,7 +132,17 @@ impl Workspace { } /// Rename workspace manifest. - fn rename(&mut self) -> Result<()> { + pub(crate) fn rename(&mut self) -> Result<()> { + self.rename_with(handler::patch_workspace)?; + handler::patch_publish_workspace(&mut self.mutable_manifest); + Ok(()) + } + + fn rename_aliases(&mut self) -> Result<()> { + self.rename_with(handler::patch_workspace_alias) + } + + fn rename_with(&mut self, patch: fn(&str, &mut InlineTable)) -> Result<()> { let Some(deps) = self.mutable_manifest["workspace"]["dependencies"].as_table_like_mut() else { return Ok(()); @@ -137,7 +154,7 @@ impl Workspace { continue; }; - handler::patch_workspace(name, table); + patch(name, table); } Ok(()) diff --git a/utils/crates-io/src/publisher.rs b/utils/crates-io/src/publisher.rs index 86f48d9233f..74f4b2ecbad 100644 --- a/utils/crates-io/src/publisher.rs +++ b/utils/crates-io/src/publisher.rs @@ -4,12 +4,12 @@ //! Packages publisher use crate::{ - Manifest, PACKAGES, PackageStatus, SAFE_DEPENDENCIES, STACKED_DEPENDENCIES, Simulator, - TEAM_OWNER, Workspace, handler, + GEAR_SUBSTRATE_DEPENDENCIES, Manifest, PACKAGES, PackageStatus, SAFE_DEPENDENCIES, + STACKED_DEPENDENCIES, Simulator, TEAM_OWNER, Workspace, handler, }; use anyhow::{Result, bail}; use cargo_metadata::{Metadata, MetadataCommand}; -use std::path::PathBuf; +use std::{collections::BTreeMap, path::PathBuf}; /// crates-io packages publisher. pub struct Publisher { @@ -31,7 +31,13 @@ impl Publisher { Ok(Self { metadata: MetadataCommand::new().no_deps().exec()?, graph: vec![], - index: [SAFE_DEPENDENCIES, STACKED_DEPENDENCIES, PACKAGES].concat(), + index: [ + GEAR_SUBSTRATE_DEPENDENCIES, + SAFE_DEPENDENCIES, + STACKED_DEPENDENCIES, + PACKAGES, + ] + .concat(), workspace: None, simulator: simulate .then(|| Simulator::new(registry_path)) @@ -46,11 +52,12 @@ impl Publisher { /// 3. Patch dependencies if needed pub async fn build(mut self, verify: bool, version: Option) -> Result { let mut workspace = Workspace::lookup(version)?; - let version = workspace.version()?; + let workspace_version = workspace.version()?; + let mut package_versions = BTreeMap::new(); for name in self.index.iter() { let Some(pkg) = self.metadata.packages.iter().find(|pkg| *pkg.name == *name) else { - println!("Package {name}@{version} not found in cargo metadata!"); + println!("Package {name}@{workspace_version} not found in cargo metadata!"); continue; }; @@ -89,6 +96,13 @@ impl Publisher { bail!("Package {name} has empty rust-version!"); } + let package_version = if GEAR_SUBSTRATE_DEPENDENCIES.contains(name) { + pkg.version.to_string() + } else { + workspace_version.clone() + }; + package_versions.insert(name.to_string(), package_version.clone()); + let mut is_published = false; let mut is_actualized = false; @@ -100,8 +114,8 @@ impl Publisher { } } - if verify && crate::verify(name, &version, self.simulator.as_ref()).await? { - println!("Package {name}@{version} already published!"); + if verify && crate::verify(name, &package_version, self.simulator.as_ref()).await? { + println!("Package {name}@{package_version} already published!"); is_actualized = true; } @@ -109,7 +123,11 @@ impl Publisher { .push(handler::patch(pkg, is_published, is_actualized)?); } - workspace.complete(self.index.clone(), self.simulator.is_some())?; + workspace.complete( + self.index.clone(), + &package_versions, + self.simulator.is_some(), + )?; self.workspace = Some(workspace); @@ -154,7 +172,7 @@ impl Publisher { } /// Check the to-be-published packages - pub fn check(self) -> Result { + pub fn check(&self) -> Result<()> { // Post tests for gtest for (pkg, test) in [ ("demo-syscall-error", "program_can_be_initialized"), @@ -165,7 +183,20 @@ impl Publisher { } } - Ok(self) + Ok(()) + } + + /// Apply publish-only workspace dependency rewrites. + pub fn prepare_publish(&mut self) -> Result<()> { + for manifest in self.graph.iter_mut() { + handler::patch_publish(&manifest.name, &mut manifest.mutable_manifest); + } + + if let Some(workspace) = self.workspace.as_mut() { + workspace.rename()?; + } + + self.patch() } /// Publish packages @@ -178,13 +209,16 @@ impl Publisher { } in self.graph.iter().filter(|m| !m.is_actualized) { println!("Publishing {path:?}"); + if let Some(simulator) = self.simulator.as_ref() { + simulator.clear_cache()?; + } let status = crate::publish(&path.to_string_lossy())?; if !status.success() { bail!("Failed to publish package {path:?} ..."); } if self.simulator.is_none() && !is_published { - let status = crate::add_owner(name, TEAM_OWNER)?; + let status = crate::add_owner(handler::crates_io_name(name), TEAM_OWNER)?; if !status.success() { bail!("Failed to add owner to package {name} ..."); } diff --git a/utils/crates-io/src/simulator.rs b/utils/crates-io/src/simulator.rs index ed8e438a2fc..b74f29e1b91 100644 --- a/utils/crates-io/src/simulator.rs +++ b/utils/crates-io/src/simulator.rs @@ -6,7 +6,7 @@ use crate::{CARGO_REGISTRY_NAME, Workspace}; use anyhow::Result; use std::{ - fs, + env, fs, net::SocketAddr, ops::Deref, path::{Path, PathBuf}, @@ -85,6 +85,84 @@ impl Simulator { /// Patch cargo config pub fn patch(&self) -> Result<()> { + self.clear_cache()?; fs::write(&self.config_path, self.mutable_config.to_string()).map_err(Into::into) } + + /// Clear Cargo cache entries that can retain stale simulated packages. + pub fn clear_cache(&self) -> Result<()> { + clear_local_registry_cache()?; + clear_target_package_dir() + } +} + +fn clear_local_registry_cache() -> Result<()> { + let cargo_home = env::var_os("CARGO_HOME") + .map(PathBuf::from) + .or_else(|| env::var_os("HOME").map(|home| PathBuf::from(home).join(".cargo"))); + let Some(cargo_home) = cargo_home else { + return Ok(()); + }; + + let registry = cargo_home.join("registry"); + clear_registry_dir(®istry.join("src"))?; + clear_registry_dir(®istry.join("cache")) +} + +fn clear_registry_dir(path: &Path) -> Result<()> { + let Ok(entries) = fs::read_dir(path) else { + return Ok(()); + }; + + for entry in entries { + let entry = entry?; + let file_name = entry.file_name(); + if file_name.to_string_lossy().starts_with("127.0.0.1-") { + let path = entry.path(); + if entry.file_type()?.is_dir() { + fs::remove_dir_all(path)?; + } else { + fs::remove_file(path)?; + } + } + } + + Ok(()) +} + +fn clear_target_package_dir() -> Result<()> { + let manifest = Workspace::resolve_path("Cargo.toml")?; + let Some(workspace_dir) = manifest.parent() else { + return Ok(()); + }; + + let package_dir = workspace_dir.join("target").join("package"); + if package_dir.exists() { + fs::remove_dir_all(package_dir)?; + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn clear_registry_dir_removes_local_registry_dirs_and_files() { + let temp_dir = TempDir::new().unwrap(); + let local_dir = temp_dir.path().join("127.0.0.1-abc"); + let local_file = temp_dir.path().join("127.0.0.1-def"); + let upstream_dir = temp_dir.path().join("github.com-abc"); + + fs::create_dir(&local_dir).unwrap(); + fs::write(&local_file, b"crate").unwrap(); + fs::create_dir(&upstream_dir).unwrap(); + + clear_registry_dir(temp_dir.path()).unwrap(); + + assert!(!local_dir.exists()); + assert!(!local_file.exists()); + assert!(upstream_dir.exists()); + } } diff --git a/utils/gear-workspace-hack/Cargo.toml b/utils/gear-workspace-hack/Cargo.toml index b8799ac2347..d1d3febece9 100644 --- a/utils/gear-workspace-hack/Cargo.toml +++ b/utils/gear-workspace-hack/Cargo.toml @@ -17,200 +17,200 @@ publish = false # they have features like `runtime-benchmarks` and `try-runtime` # so we cannot, for example, run `cargo build -p gear-cli` without `--all-features` -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.frame-executive] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.frame-executive] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.frame-support] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.frame-support] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" features = ["experimental"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.frame-try-runtime] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.frame-try-runtime] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-authority-discovery] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-authority-discovery] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-authorship] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-authorship] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-babe] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-babe] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-bags-list] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-bags-list] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-balances] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-balances] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-bounties] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-bounties] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-child-bounties] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-child-bounties] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-conviction-voting] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-conviction-voting] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-election-provider-multi-phase] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-election-provider-multi-phase] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-grandpa] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-grandpa] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-identity] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-identity] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-im-online] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-im-online] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-multisig] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-multisig] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-nomination-pools] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-nomination-pools] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-offences] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-offences] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-preimage] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-preimage] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-proxy] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-proxy] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-ranked-collective] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-ranked-collective] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-referenda] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-referenda] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-scheduler] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-scheduler] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-session] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-session] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["historical", "std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-sudo] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-sudo] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-timestamp] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-timestamp] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-transaction-payment] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-transaction-payment] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-treasury] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-treasury] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-utility] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-utility] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-vesting] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-vesting] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-whitelist] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.pallet-whitelist] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["std"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.sc-client-db] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.sc-client-db] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" default-features = false features = ["rocksdb", "test-helpers"] -[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.sc-service] -git = "https://github.com/gear-tech/polkadot-sdk.git" -branch = "gear-polkadot-stable2409-updated-wasmtime" +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.sc-service] +git = "https://github.com/paritytech/polkadot-sdk.git" +rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" features = ["test-helpers"] ### BEGIN HAKARI SECTION @@ -241,14 +241,14 @@ ark-serialize = { version = "0.4", default-features = false, features = ["derive ark-std = { version = "0.4", default-features = false, features = ["parallel"] } arrayvec = { version = "0.7", features = ["serde"] } base64 = { version = "0.22" } -binary-merkle-tree = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } +binary-merkle-tree = { version = "16", default-features = false, features = ["std"] } bitflags = { version = "2", default-features = false, features = ["std"] } bitvec = { version = "1" } blake2 = { version = "0.10" } blake2b_simd = { version = "1", default-features = false, features = ["std"] } bounded-collections = { version = "0.2", default-features = false, features = ["std"] } -bp-header-chain = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -bp-runtime = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } +bp-header-chain = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +bp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } bs58 = { version = "0.5", features = ["check"] } bumpalo = { version = "3", features = ["allocator-api2"] } byte-slice-cast = { version = "1", default-features = false, features = ["std"] } @@ -260,6 +260,7 @@ clap_builder = { version = "4", default-features = false, features = ["color", " concurrent-queue = { version = "2" } const-hex = { version = "1", features = ["core-error", "serde"] } cranelift-bitset = { version = "0.131", default-features = false, features = ["enable-serde"] } +cranelift-codegen = { version = "0.131", default-features = false, features = ["host-arch", "pulley", "std", "timing", "unwind"] } crc32fast = { version = "1" } crossbeam-channel = { version = "0.5" } crossbeam-epoch = { version = "0.9" } @@ -269,7 +270,7 @@ crypto-common = { version = "0.1", default-features = false, features = ["getran curve25519-dalek = { version = "4", features = ["digest", "legacy_compatibility"] } data-encoding = { version = "2" } der = { version = "0.7", default-features = false, features = ["oid", "pem", "std"] } -derive_more = { version = "2", default-features = false, features = ["full", "std"] } +derive_more-f595c2ba2a3f28df = { package = "derive_more", version = "2", default-features = false, features = ["full", "std"] } digest-274715c4dabd11b0 = { package = "digest", version = "0.9", default-features = false, features = ["std"] } digest-93f6ce9d446188ac = { package = "digest", version = "0.10", features = ["mac", "oid", "std"] } ecdsa = { version = "0.16", default-features = false, features = ["pem", "serde", "signing", "std", "verifying"] } @@ -287,10 +288,10 @@ fixed-hash = { version = "0.8", default-features = false, features = ["std"] } fnv = { version = "1" } foldhash = { version = "0.2", default-features = false, features = ["std"] } form_urlencoded = { version = "1" } -frame-metadata-8ee676a8f9a6c413 = { package = "frame-metadata", version = "16", default-features = false, features = ["current", "std"] } +frame-metadata-8ee676a8f9a6c413 = { package = "frame-metadata", version = "16" } frame-metadata-e761569b921b4a02 = { package = "frame-metadata", version = "23", default-features = false, features = ["current", "std"] } -frame-metadata-hash-extension = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -frame-system-rpc-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +frame-metadata-hash-extension = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } futures = { version = "0.3", features = ["bilock", "thread-pool", "unstable"] } futures-channel = { version = "0.3", features = ["sink", "unstable"] } futures-core = { version = "0.3", features = ["unstable"] } @@ -354,16 +355,15 @@ num-rational = { version = "0.4", features = ["num-bigint-std"] } num-traits = { version = "0.2", features = ["i128", "libm"] } numerated = { version = "2", default-features = false, features = ["mock"] } once_cell = { version = "1" } -pallet-nomination-pools-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -pallet-staking-reward-fn = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -pallet-staking-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +pallet-nomination-pools-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +pallet-staking-reward-fn = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +pallet-staking-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } parity-bip39 = { version = "2", features = ["rand"] } parity-scale-codec = { version = "3", features = ["bytes", "derive", "full", "max-encoded-len"] } parity-wasm = { git = "https://github.com/gear-tech/parity-wasm", branch = "v0.45.0-sign-ext" } pbkdf2 = { version = "0.12", features = ["std"] } percent-encoding = { version = "2" } -petgraph = { version = "0.6" } pkcs8 = { version = "0.10", default-features = false, features = ["pem", "std"] } polkavm-common = { version = "0.9", features = ["alloc", "logging"] } portable-atomic = { version = "1", features = ["require-cas"] } @@ -389,11 +389,10 @@ regex-syntax = { version = "0.8" } reqwest = { version = "0.12", default-features = false, features = ["default-tls", "json", "rustls-tls"] } ring = { version = "0.17", features = ["std"] } ruint = { version = "1", default-features = false, features = ["alloy-rlp", "serde", "std"] } -rustc-demangle = { version = "0.1", default-features = false, features = ["std"] } rustc-hash-dff4ba8e3ae991db = { package = "rustc-hash", version = "1" } rustc-hash-f595c2ba2a3f28df = { package = "rustc-hash", version = "2" } rustc-hex = { version = "2", default-features = false, features = ["std"] } -sc-cli = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +sc-cli = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } scale-bits = { version = "0.7" } scale-decode = { version = "0.16" } scale-encode = { version = "0.10" } @@ -414,52 +413,48 @@ sha3 = { version = "0.10", features = ["asm"] } signature = { version = "2", default-features = false, features = ["digest", "rand_core", "std"] } smallvec = { version = "1", default-features = false, features = ["const_new", "serde", "union"] } soketto = { version = "0.8", features = ["http"] } -sp-allocator = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["frame-metadata"] } -sp-application-crypto = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-arithmetic = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-authority-discovery = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-block-builder = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-consensus-babe = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-consensus-grandpa = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-consensus-slots = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-core = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-crypto-ec-utils = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["bls12-381", "std"] } -sp-crypto-hashing-35ef219cb4e8d0b3 = { package = "sp-crypto-hashing", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +sp-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", features = ["frame-metadata"] } +sp-application-crypto = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-arithmetic = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-authority-discovery = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-block-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-consensus-babe = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-consensus-slots = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-crypto-ec-utils = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["bls12-381", "std"] } sp-crypto-hashing-c65f7effa3be6d31 = { package = "sp-crypto-hashing", version = "0.1", default-features = false, features = ["std"] } -sp-externalities = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-genesis-builder = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-inherents = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-io = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["disable_oom", "disable_panic_handler"] } -sp-keyring = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-keystore = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-metadata-ir = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-npos-elections = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-offchain = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-runtime-interface = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["disable_target_static_assertions"] } -sp-session = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-state-machine = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-std = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-storage = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-timestamp = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-tracing = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-transaction-pool = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-trie = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-version = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-wasm-interface = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["wasmtime"] } -sp-wasm-interface-common = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-weights = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +sp-crypto-hashing-d9686075916df9f5 = { package = "sp-crypto-hashing", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-externalities = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-genesis-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-inherents = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", features = ["disable_oom", "disable_panic_handler", "improved_panic_error_reporting"] } +sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-metadata-ir = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-npos-elections = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-runtime-interface = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", features = ["disable_target_static_assertions"] } +sp-session = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-state-machine = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-storage = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-tracing = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-trie = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-version = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-weights = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } spki = { version = "0.7", default-features = false, features = ["pem", "std"] } ss58-registry = { version = "1", default-features = false, features = ["std"] } stable_deref_trait = { version = "1", default-features = false, features = ["std"] } strum-2f80eeee3b1b6c7e = { package = "strum", version = "0.26", features = ["derive"] } strum-754bda37e0fb3874 = { package = "strum", version = "0.27", default-features = false, features = ["derive", "std"] } strum-adf3d7031871b0af = { package = "strum", version = "0.24", features = ["derive"] } -substrate-bip39 = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } +substrate-bip39 = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } subtle = { version = "2" } subxt-metadata = { version = "0.44", default-features = false, features = ["std"] } syn-f595c2ba2a3f28df = { package = "syn", version = "2", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } -target-lexicon = { version = "0.13", features = ["std"] } thiserror = { version = "2" } time = { version = "0.3", features = ["formatting", "macros", "parsing"] } tiny-keccak = { version = "2", features = ["keccak", "shake"] } @@ -483,19 +478,13 @@ unicode-normalization = { version = "0.1", default-features = false, features = unsigned-varint-c38e5c1d305a1b54 = { package = "unsigned-varint", version = "0.8", default-features = false, features = ["asynchronous_codec", "codec"] } unsigned-varint-ca01ad9e24f5d932 = { package = "unsigned-varint", version = "0.7", default-features = false, features = ["asynchronous_codec", "futures"] } url = { version = "2", features = ["serde"] } -uuid = { version = "1", features = ["v4"] } wasm-bindgen = { version = "0.2" } -wasm-encoder-1a16dca237765f34 = { package = "wasm-encoder", version = "0.230", default-features = false, features = ["std", "wasmparser"] } -wasm-encoder-3c4f6f7c21879200 = { package = "wasm-encoder", version = "0.246", features = ["wasmparser"] } -wasmi-3d9dd527f574b61f = { package = "wasmi", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", features = ["virtual_memory"] } -wasmi-d585fab2519d2d1 = { package = "wasmi", version = "0.38", features = ["extra-checks"] } -wasmi_core = { git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", default-features = false, features = ["virtual_memory"] } -wasmparser-1a16dca237765f34 = { package = "wasmparser", version = "0.230", default-features = false, features = ["component-model", "features", "simd", "std", "validate"] } -wasmparser-3c4f6f7c21879200 = { package = "wasmparser", version = "0.246", default-features = false, features = ["component-model", "features", "serde", "simd", "std", "validate"] } -wasmtime = { version = "44", features = ["winch"] } -wasmtime-environ = { version = "44", default-features = false, features = ["backtrace", "compile", "component-model", "demangle", "gc-drc", "gc-null", "stack-switching", "threads"] } -wasmtime-internal-core = { version = "44", default-features = false, features = ["anyhow", "backtrace", "serde"] } -wasmtime-internal-cranelift = { version = "44", default-features = false, features = ["component-model", "gc-drc", "gc-null", "pulley", "stack-switching", "threads"] } +wasm-encoder = { version = "0.230", default-features = false, features = ["std", "wasmparser"] } +wasmi = { version = "0.38", features = ["extra-checks"] } +wasmparser = { version = "0.230", default-features = false, features = ["component-model", "features", "simd", "std", "validate"] } +wasmtime = { version = "44", default-features = false, features = ["anyhow", "cache", "cranelift", "parallel-compilation", "pooling-allocator", "winch"] } +wasmtime-internal-core = { version = "44", default-features = false, features = ["anyhow", "serde", "std"] } +wasmtime-internal-cranelift = { version = "44", default-features = false, features = ["pulley"] } winnow = { version = "0.7" } x25519-dalek = { version = "2", features = ["static_secrets"] } zeroize = { version = "1", features = ["derive", "std"] } @@ -530,14 +519,14 @@ ark-serialize = { version = "0.4", default-features = false, features = ["derive ark-std = { version = "0.4", default-features = false, features = ["parallel"] } arrayvec = { version = "0.7", features = ["serde"] } base64 = { version = "0.22" } -binary-merkle-tree = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } +binary-merkle-tree = { version = "16", default-features = false, features = ["std"] } bitflags = { version = "2", default-features = false, features = ["std"] } bitvec = { version = "1" } blake2 = { version = "0.10" } blake2b_simd = { version = "1", default-features = false, features = ["std"] } bounded-collections = { version = "0.2", default-features = false, features = ["std"] } -bp-header-chain = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -bp-runtime = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } +bp-header-chain = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +bp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } bs58 = { version = "0.5", features = ["check"] } bumpalo = { version = "3", features = ["allocator-api2"] } byte-slice-cast = { version = "1", default-features = false, features = ["std"] } @@ -550,6 +539,8 @@ clap_builder = { version = "4", default-features = false, features = ["color", " concurrent-queue = { version = "2" } const-hex = { version = "1", features = ["core-error", "serde"] } cranelift-bitset = { version = "0.131", default-features = false, features = ["enable-serde"] } +cranelift-codegen = { version = "0.131", default-features = false, features = ["host-arch", "pulley", "std", "timing", "unwind"] } +cranelift-codegen-meta = { version = "0.131", default-features = false, features = ["pulley"] } crc32fast = { version = "1" } crossbeam-channel = { version = "0.5" } crossbeam-epoch = { version = "0.9" } @@ -559,7 +550,8 @@ crypto-common = { version = "0.1", default-features = false, features = ["getran curve25519-dalek = { version = "4", features = ["digest", "legacy_compatibility"] } data-encoding = { version = "2" } der = { version = "0.7", default-features = false, features = ["oid", "pem", "std"] } -derive_more = { version = "2", default-features = false, features = ["full", "std"] } +derive_more-2247a326473123a6 = { package = "derive_more", version = "0.99" } +derive_more-f595c2ba2a3f28df = { package = "derive_more", version = "2", default-features = false, features = ["full", "std"] } digest-274715c4dabd11b0 = { package = "digest", version = "0.9", default-features = false, features = ["std"] } digest-93f6ce9d446188ac = { package = "digest", version = "0.10", features = ["mac", "oid", "std"] } displaydoc = { version = "0.2" } @@ -578,11 +570,11 @@ fixed-hash = { version = "0.8", default-features = false, features = ["std"] } fnv = { version = "1" } foldhash = { version = "0.2", default-features = false, features = ["std"] } form_urlencoded = { version = "1" } -frame-metadata-8ee676a8f9a6c413 = { package = "frame-metadata", version = "16", default-features = false, features = ["current", "std"] } +frame-metadata-8ee676a8f9a6c413 = { package = "frame-metadata", version = "16" } frame-metadata-e761569b921b4a02 = { package = "frame-metadata", version = "23", default-features = false, features = ["current", "std"] } -frame-metadata-hash-extension = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -frame-support-procedural = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["experimental", "std"] } -frame-system-rpc-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +frame-metadata-hash-extension = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +frame-support-procedural = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["experimental", "std"] } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } futures = { version = "0.3", features = ["bilock", "thread-pool", "unstable"] } futures-channel = { version = "0.3", features = ["sink", "unstable"] } futures-core = { version = "0.3", features = ["unstable"] } @@ -646,17 +638,16 @@ num-rational = { version = "0.4", features = ["num-bigint-std"] } num-traits = { version = "0.2", features = ["i128", "libm"] } numerated = { version = "2", default-features = false, features = ["mock"] } once_cell = { version = "1" } -pallet-nomination-pools-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -pallet-staking-reward-fn = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -pallet-staking-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +pallet-nomination-pools-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +pallet-staking-reward-fn = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +pallet-staking-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } parity-bip39 = { version = "2", features = ["rand"] } parity-scale-codec = { version = "3", features = ["bytes", "derive", "full", "max-encoded-len"] } parity-scale-codec-derive = { version = "3", default-features = false, features = ["max-encoded-len"] } parity-wasm = { git = "https://github.com/gear-tech/parity-wasm", branch = "v0.45.0-sign-ext" } pbkdf2 = { version = "0.12", features = ["std"] } percent-encoding = { version = "2" } -petgraph = { version = "0.6" } pkcs8 = { version = "0.10", default-features = false, features = ["pem", "std"] } polkavm-common = { version = "0.9", features = ["alloc", "logging"] } portable-atomic = { version = "1", features = ["require-cas"] } @@ -682,11 +673,10 @@ regex-syntax = { version = "0.8" } reqwest = { version = "0.12", default-features = false, features = ["default-tls", "json", "rustls-tls"] } ring = { version = "0.17", features = ["std"] } ruint = { version = "1", default-features = false, features = ["alloy-rlp", "serde", "std"] } -rustc-demangle = { version = "0.1", default-features = false, features = ["std"] } rustc-hash-dff4ba8e3ae991db = { package = "rustc-hash", version = "1" } rustc-hash-f595c2ba2a3f28df = { package = "rustc-hash", version = "2" } rustc-hex = { version = "2", default-features = false, features = ["std"] } -sc-cli = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +sc-cli = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } scale-bits = { version = "0.7" } scale-decode = { version = "0.16" } scale-encode = { version = "0.10" } @@ -708,55 +698,51 @@ sha3 = { version = "0.10", features = ["asm"] } signature = { version = "2", default-features = false, features = ["digest", "rand_core", "std"] } smallvec = { version = "1", default-features = false, features = ["const_new", "serde", "union"] } soketto = { version = "0.8", features = ["http"] } -sp-allocator = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-api = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["frame-metadata"] } -sp-api-proc-macro = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-application-crypto = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-arithmetic = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-authority-discovery = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-block-builder = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-consensus-babe = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-consensus-grandpa = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-consensus-slots = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-core = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-crypto-ec-utils = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["bls12-381", "std"] } -sp-crypto-hashing-35ef219cb4e8d0b3 = { package = "sp-crypto-hashing", git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +sp-api = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", features = ["frame-metadata"] } +sp-api-proc-macro = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-application-crypto = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-arithmetic = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-authority-discovery = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-block-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-consensus-babe = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-consensus-slots = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-crypto-ec-utils = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["bls12-381", "std"] } sp-crypto-hashing-c65f7effa3be6d31 = { package = "sp-crypto-hashing", version = "0.1", default-features = false, features = ["std"] } -sp-debug-derive = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["force-debug", "std"] } -sp-externalities = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-genesis-builder = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-inherents = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-io = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["disable_oom", "disable_panic_handler"] } -sp-keyring = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-keystore = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-metadata-ir = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-npos-elections = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-offchain = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-runtime-interface = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["disable_target_static_assertions"] } -sp-session = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-state-machine = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-std = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-storage = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-timestamp = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-tracing = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-transaction-pool = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-trie = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-version = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } -sp-wasm-interface = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", features = ["wasmtime"] } -sp-wasm-interface-common = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } -sp-weights = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime" } +sp-crypto-hashing-d9686075916df9f5 = { package = "sp-crypto-hashing", git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-debug-derive = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["force-debug", "std"] } +sp-externalities = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-genesis-builder = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-inherents = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", features = ["disable_oom", "disable_panic_handler", "improved_panic_error_reporting"] } +sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-metadata-ir = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-npos-elections = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-runtime-interface = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", features = ["disable_target_static_assertions"] } +sp-session = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-state-machine = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-storage = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } +sp-tracing = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-trie = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-version = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } +sp-weights = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c" } spki = { version = "0.7", default-features = false, features = ["pem", "std"] } ss58-registry = { version = "1", default-features = false, features = ["std"] } stable_deref_trait = { version = "1", default-features = false, features = ["std"] } strum-2f80eeee3b1b6c7e = { package = "strum", version = "0.26", features = ["derive"] } strum-754bda37e0fb3874 = { package = "strum", version = "0.27", default-features = false, features = ["derive", "std"] } strum-adf3d7031871b0af = { package = "strum", version = "0.24", features = ["derive"] } -substrate-bip39 = { git = "https://github.com/gear-tech/polkadot-sdk.git", branch = "gear-polkadot-stable2409-updated-wasmtime", default-features = false, features = ["std"] } +substrate-bip39 = { git = "https://github.com/paritytech/polkadot-sdk.git", rev = "298f676c91d64f15f38ea7fd78f125c5889ab09c", default-features = false, features = ["std"] } subtle = { version = "2" } subxt-metadata = { version = "0.44", default-features = false, features = ["std"] } syn-dff4ba8e3ae991db = { package = "syn", version = "1", features = ["extra-traits", "full", "visit"] } syn-f595c2ba2a3f28df = { package = "syn", version = "2", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } -target-lexicon = { version = "0.13", features = ["std"] } thiserror = { version = "2" } time = { version = "0.3", features = ["formatting", "macros", "parsing"] } tiny-keccak = { version = "2", features = ["keccak", "shake"] } @@ -780,19 +766,13 @@ unicode-normalization = { version = "0.1", default-features = false, features = unsigned-varint-c38e5c1d305a1b54 = { package = "unsigned-varint", version = "0.8", default-features = false, features = ["asynchronous_codec", "codec"] } unsigned-varint-ca01ad9e24f5d932 = { package = "unsigned-varint", version = "0.7", default-features = false, features = ["asynchronous_codec", "futures"] } url = { version = "2", features = ["serde"] } -uuid = { version = "1", features = ["v4"] } wasm-bindgen = { version = "0.2" } -wasm-encoder-1a16dca237765f34 = { package = "wasm-encoder", version = "0.230", default-features = false, features = ["std", "wasmparser"] } -wasm-encoder-3c4f6f7c21879200 = { package = "wasm-encoder", version = "0.246", features = ["wasmparser"] } -wasmi-3d9dd527f574b61f = { package = "wasmi", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", features = ["virtual_memory"] } -wasmi-d585fab2519d2d1 = { package = "wasmi", version = "0.38", features = ["extra-checks"] } -wasmi_core = { git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", default-features = false, features = ["virtual_memory"] } -wasmparser-1a16dca237765f34 = { package = "wasmparser", version = "0.230", default-features = false, features = ["component-model", "features", "simd", "std", "validate"] } -wasmparser-3c4f6f7c21879200 = { package = "wasmparser", version = "0.246", default-features = false, features = ["component-model", "features", "serde", "simd", "std", "validate"] } -wasmtime = { version = "44", features = ["winch"] } -wasmtime-environ = { version = "44", default-features = false, features = ["backtrace", "compile", "component-model", "demangle", "gc-drc", "gc-null", "stack-switching", "threads"] } -wasmtime-internal-core = { version = "44", default-features = false, features = ["anyhow", "backtrace", "serde"] } -wasmtime-internal-cranelift = { version = "44", default-features = false, features = ["component-model", "gc-drc", "gc-null", "pulley", "stack-switching", "threads"] } +wasm-encoder = { version = "0.230", default-features = false, features = ["std", "wasmparser"] } +wasmi = { version = "0.38", features = ["extra-checks"] } +wasmparser = { version = "0.230", default-features = false, features = ["component-model", "features", "simd", "std", "validate"] } +wasmtime = { version = "44", default-features = false, features = ["anyhow", "cache", "cranelift", "parallel-compilation", "pooling-allocator", "winch"] } +wasmtime-internal-core = { version = "44", default-features = false, features = ["anyhow", "serde", "std"] } +wasmtime-internal-cranelift = { version = "44", default-features = false, features = ["pulley"] } winnow = { version = "0.7" } x25519-dalek = { version = "2", features = ["static_secrets"] } zeroize = { version = "1", features = ["derive", "std"] } @@ -813,7 +793,7 @@ once_cell = { version = "1", default-features = false, features = ["critical-sec openssl = { version = "0.10", features = ["vendored"] } openssl-sys = { version = "0.9", default-features = false, features = ["vendored"] } rocksdb = { version = "0.21", default-features = false, features = ["jemalloc", "snappy"] } -rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "thread", "time", "use-libc"] } +rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "use-libc"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "aws_lc_rs", "logging", "ring", "std", "tls12"] } rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } @@ -837,7 +817,7 @@ once_cell = { version = "1", default-features = false, features = ["critical-sec openssl = { version = "0.10", features = ["vendored"] } openssl-sys = { version = "0.9", default-features = false, features = ["vendored"] } rocksdb = { version = "0.21", default-features = false, features = ["jemalloc", "snappy"] } -rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "thread", "time", "use-libc"] } +rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "use-libc"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "aws_lc_rs", "logging", "ring", "std", "tls12"] } rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } @@ -861,7 +841,7 @@ once_cell = { version = "1", default-features = false, features = ["critical-sec openssl = { version = "0.10", features = ["vendored"] } openssl-sys = { version = "0.9", default-features = false, features = ["vendored"] } rocksdb = { version = "0.21", default-features = false, features = ["jemalloc", "snappy"] } -rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "thread", "time", "use-libc"] } +rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "use-libc"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "aws_lc_rs", "logging", "ring", "std", "tls12"] } rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } @@ -885,7 +865,7 @@ once_cell = { version = "1", default-features = false, features = ["critical-sec openssl = { version = "0.10", features = ["vendored"] } openssl-sys = { version = "0.9", default-features = false, features = ["vendored"] } rocksdb = { version = "0.21", default-features = false, features = ["jemalloc", "snappy"] } -rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "thread", "time", "use-libc"] } +rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "use-libc"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "aws_lc_rs", "logging", "ring", "std", "tls12"] } rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } @@ -905,7 +885,7 @@ miniz_oxide = { version = "0.8", default-features = false, features = ["simd", " once_cell = { version = "1", default-features = false, features = ["critical-section"] } openssl-sys = { version = "0.9", default-features = false, features = ["vendored"] } rocksdb = { version = "0.21", default-features = false, features = ["jemalloc", "snappy"] } -rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "thread", "use-libc"] } +rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "use-libc"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "aws_lc_rs", "logging", "ring", "std", "tls12"] } rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } security-framework = { version = "3", features = ["OSX_10_14"] } @@ -927,7 +907,7 @@ miniz_oxide = { version = "0.8", default-features = false, features = ["simd", " once_cell = { version = "1", default-features = false, features = ["critical-section"] } openssl-sys = { version = "0.9", default-features = false, features = ["vendored"] } rocksdb = { version = "0.21", default-features = false, features = ["jemalloc", "snappy"] } -rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "thread", "use-libc"] } +rustix = { version = "1", features = ["fs", "mm", "param", "process", "termios", "use-libc"] } rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "aws_lc_rs", "logging", "ring", "std", "tls12"] } rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } security-framework = { version = "3", features = ["OSX_10_14"] } diff --git a/vara/node/cli/Cargo.toml b/vara/node/cli/Cargo.toml index f44a1570312..2fa54f1192b 100644 --- a/vara/node/cli/Cargo.toml +++ b/vara/node/cli/Cargo.toml @@ -21,7 +21,6 @@ path = "src/main.rs" [dependencies] clap = { workspace = true, features = ["derive"] } mimalloc = { workspace = true, default-features = false } -log = { workspace = true, features = ["std"] } futures.workspace = true derive_more.workspace = true diff --git a/vara/node/cli/src/command.rs b/vara/node/cli/src/command.rs index 5c8a351c5e7..f2ae568a677 100644 --- a/vara/node/cli/src/command.rs +++ b/vara/node/cli/src/command.rs @@ -329,7 +329,6 @@ pub fn run() -> sc_cli::Result<()> { let runner = if cli.run.base.validator && cli.run.base.shared_params.log.is_empty() { cli.create_runner_with_logger_hook(&cli.run.base, |logger, _| { logger.with_detailed_output(false); - logger.with_max_level(log::LevelFilter::Info); })? } else { cli.create_runner(&cli.run.base)? diff --git a/vara/pallets/gear-eth-bridge/src/lib.rs b/vara/pallets/gear-eth-bridge/src/lib.rs index f95b9816684..333b58bf1e1 100644 --- a/vara/pallets/gear-eth-bridge/src/lib.rs +++ b/vara/pallets/gear-eth-bridge/src/lib.rs @@ -441,7 +441,8 @@ pub mod pallet { let idx = queue.iter().position(|&v| v == hash)?; // Generating proof. - let proof = binary_merkle_tree::merkle_proof_raw::(queue, idx); + let proof = + binary_merkle_tree::merkle_proof_raw::(queue, idx.try_into().ok()?); // Returning appropriate type. Some(proof.into()) diff --git a/vara/runtime/interface/sandbox/Cargo.toml b/vara/runtime/interface/sandbox/Cargo.toml index 3ab33546fb8..15edf26028c 100644 --- a/vara/runtime/interface/sandbox/Cargo.toml +++ b/vara/runtime/interface/sandbox/Cargo.toml @@ -16,6 +16,7 @@ workspace = true [dependencies] sp-runtime-interface.workspace = true sp-wasm-interface.workspace = true +sc-executor = { workspace = true, optional = true } gear-sandbox-host = { workspace = true, optional = true } log = { workspace = true, optional = true } @@ -32,4 +33,4 @@ std = [ "sp-wasm-interface/std", ] -host-api = ["std", "sp-wasm-interface/wasmtime"] +host-api = ["std", "sc-executor", "sp-wasm-interface/wasmtime"] diff --git a/vara/runtime/interface/sandbox/src/detail.rs b/vara/runtime/interface/sandbox/src/detail.rs index 5c09a90c15e..9d1eaf6181a 100644 --- a/vara/runtime/interface/sandbox/src/detail.rs +++ b/vara/runtime/interface/sandbox/src/detail.rs @@ -4,8 +4,9 @@ use gear_sandbox_host::context::{ self, HostPointer, HostResult, Instantiate, Pointer, SupervisorFuncIndex, Value, WordSize, }; +use sc_executor::{Caller, wasmtime_util as util, with_caller_mut}; use sp_wasm_interface::{ - Caller, FunctionContext, StoreData, util, + FunctionContext, wasmtime::{AsContext, AsContextMut, Val}, }; @@ -17,11 +18,11 @@ pub fn init( } struct RuntimeInterfaceContext<'a, 'b> { - caller: &'a mut Caller<'b, StoreData>, + caller: &'a mut Caller<'b>, } impl<'a, 'b> RuntimeInterfaceContext<'a, 'b> { - fn new(caller: &'a mut Caller<'b, StoreData>) -> Self { + fn new(caller: &'a mut Caller<'b>) -> Self { Self { caller } } @@ -123,7 +124,7 @@ impl context::SupervisorContextDispatcher for RuntimeInterfaceDispatchContext<'_ .expect("dispatch_thunk_idx should be a funcref") .expect("dispatch_thunk_idx should point to actual func"); - let mut ret_vals = [Val::FuncRef(None)]; + let mut ret_vals = [Val::I64(0)]; let result = dispatch_thunk.call( &mut *self.context.caller, &[ @@ -148,7 +149,7 @@ impl context::SupervisorContextDispatcher for RuntimeInterfaceDispatchContext<'_ } } -fn trace(func: &str, caller: &Caller<'_, StoreData>) { +fn trace(func: &str, caller: &Caller<'_>) { let data_ptr: *const _ = caller.data(); let caller_ptr: *const _ = caller; let thread_id = std::thread::current().id(); @@ -164,7 +165,7 @@ fn trace(func: &str, caller: &Caller<'_, StoreData>) { pub fn get_buff(context: &mut dyn FunctionContext, memory_idx: u32) -> HostPointer { let mut method_result: HostPointer = u32::MAX.into(); - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("get_buff", caller); method_result = context::get_buff(RuntimeInterfaceContext::new(caller), memory_idx); @@ -180,7 +181,7 @@ pub fn get_global_val( ) -> Option { let mut method_result = None::; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("get_global_val", caller); method_result = @@ -193,7 +194,7 @@ pub fn get_global_val( pub fn get_instance_ptr(context: &mut dyn FunctionContext, instance_id: u32) -> HostPointer { let mut method_result: HostPointer = u32::MAX.into(); - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("get_instance_ptr", caller); method_result = @@ -204,7 +205,7 @@ pub fn get_instance_ptr(context: &mut dyn FunctionContext, instance_id: u32) -> } pub fn instance_teardown(context: &mut dyn FunctionContext, instance_idx: u32) { - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("instance_teardown", caller); context::instance_teardown(RuntimeInterfaceContext::new(caller), instance_idx); @@ -221,7 +222,7 @@ pub fn instantiate( ) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("instantiate", caller); method_result = context::instantiate( @@ -246,7 +247,7 @@ pub fn invoke( ) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("invoke", caller); method_result = context::invoke( @@ -273,7 +274,7 @@ pub fn memory_get( ) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("memory_get", caller); method_result = context::memory_get( @@ -291,7 +292,7 @@ pub fn memory_get( pub fn memory_grow(context: &mut dyn FunctionContext, memory_idx: u32, size: u32) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("memory_grow", caller); method_result = @@ -304,7 +305,7 @@ pub fn memory_grow(context: &mut dyn FunctionContext, memory_idx: u32, size: u32 pub fn memory_new(context: &mut dyn FunctionContext, initial: u32, maximum: u32) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("memory_new", caller); method_result = context::memory_new(RuntimeInterfaceContext::new(caller), initial, maximum); @@ -322,7 +323,7 @@ pub fn memory_set( ) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("memory_set", caller); method_result = context::memory_set( @@ -340,7 +341,7 @@ pub fn memory_set( pub fn memory_size(context: &mut dyn FunctionContext, memory_idx: u32) -> u32 { let mut method_result = 0; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("memory_size", caller); method_result = context::memory_size(RuntimeInterfaceContext::new(caller), memory_idx); @@ -350,7 +351,7 @@ pub fn memory_size(context: &mut dyn FunctionContext, memory_idx: u32) -> u32 { } pub fn memory_teardown(context: &mut dyn FunctionContext, memory_idx: u32) { - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("memory_teardown", caller); context::memory_teardown(RuntimeInterfaceContext::new(caller), memory_idx); @@ -365,7 +366,7 @@ pub fn set_global_val( ) -> u32 { let mut method_result = u32::MAX; - sp_wasm_interface::with_caller_mut(context, |caller| { + with_caller_mut(context, |caller| { trace("set_global_val", caller); method_result = context::set_global_val( diff --git a/vara/runtime/interface/sandbox/src/lib.rs b/vara/runtime/interface/sandbox/src/lib.rs index 11e5096f548..0d175fc6571 100644 --- a/vara/runtime/interface/sandbox/src/lib.rs +++ b/vara/runtime/interface/sandbox/src/lib.rs @@ -8,7 +8,8 @@ #[cfg(feature = "std")] pub use gear_sandbox_host::sandbox::{SandboxBackend, env::Instantiate}; use sp_runtime_interface::{Pointer, runtime_interface}; -use sp_wasm_interface::HostPointer; + +type HostPointer = u64; #[cfg(feature = "host-api")] pub mod detail; diff --git a/vara/sdk/gsdk/vara_runtime.scale b/vara/sdk/gsdk/vara_runtime.scale index 2b6efe332c2..2537de001cf 100644 Binary files a/vara/sdk/gsdk/vara_runtime.scale and b/vara/sdk/gsdk/vara_runtime.scale differ diff --git a/vara/tools/calc-stack-height/Cargo.toml b/vara/tools/calc-stack-height/Cargo.toml index 460f983ff6b..c4abcd3cc54 100644 --- a/vara/tools/calc-stack-height/Cargo.toml +++ b/vara/tools/calc-stack-height/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true [dependencies] gear-core.workspace = true gear-wasm-instrument.workspace = true -wasmtime.workspace = true +wasmtime = { features = ["runtime", "winch"], workspace = true } wat.workspace = true log.workspace = true tracing-subscriber.workspace = true