mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 12:51:02 +00:00
Switch parachain interface to new runtime_interface macro (#665)
* Make use of `runtime_interface` for parachain externalities This also changes the encoding of the `ValidationResult` return value to match the default encoding used in Substrate. * Fix compilation for web * Update `Cargo.lock` * Include feedback * Move proc macro * Update parachain/src/lib.rs Co-Authored-By: Robert Habermeier <rphmeier@gmail.com> Co-authored-by: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
Generated
+49
-37
@@ -29,7 +29,8 @@ dependencies = [
|
|||||||
"ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"exit-future 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"exit-future 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"polkadot-collator 0.7.15",
|
"polkadot-collator 0.7.15",
|
||||||
"polkadot-parachain 0.7.15",
|
"polkadot-parachain 0.7.15",
|
||||||
"polkadot-primitives 0.7.15",
|
"polkadot-primitives 0.7.15",
|
||||||
@@ -2623,7 +2624,6 @@ name = "lock_api"
|
|||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3500,14 +3500,6 @@ dependencies = [
|
|||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parity-wasm"
|
|
||||||
version = "0.31.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-wasm"
|
name = "parity-wasm"
|
||||||
version = "0.41.0"
|
version = "0.41.0"
|
||||||
@@ -3542,6 +3534,15 @@ dependencies = [
|
|||||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -3583,6 +3584,19 @@ dependencies = [
|
|||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -3803,18 +3817,21 @@ name = "polkadot-parachain"
|
|||||||
version = "0.7.15"
|
version = "0.7.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adder 0.7.15",
|
"adder 0.7.15",
|
||||||
"derive_more 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"halt 0.7.15",
|
"halt 0.7.15",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"sc-executor 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"shared_memory 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sp-core 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
"sp-core 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
|
"sp-externalities 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
|
"sp-io 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
|
"sp-runtime-interface 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
"sp-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
"sp-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
|
||||||
"tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5412,19 +5429,32 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shared_memory"
|
name = "shared_memory"
|
||||||
version = "0.8.2"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memrange 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memrange 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"shared_memory_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"theban_interval_tree 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"theban_interval_tree 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shared_memory_derive"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shell32-sys"
|
name = "shell32-sys"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -6897,16 +6927,6 @@ dependencies = [
|
|||||||
"web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasmi"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmi"
|
name = "wasmi"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -6920,14 +6940,6 @@ dependencies = [
|
|||||||
"wasmi-validation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasmi-validation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasmi-validation"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmi-validation"
|
name = "wasmi-validation"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -7556,14 +7568,15 @@ dependencies = [
|
|||||||
"checksum parity-scale-codec-derive 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "492ac3aa93d6caa5d20e4e3e0b75d08e2dcd9dd8a50d19529548b6fe11b3f295"
|
"checksum parity-scale-codec-derive 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "492ac3aa93d6caa5d20e4e3e0b75d08e2dcd9dd8a50d19529548b6fe11b3f295"
|
||||||
"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f"
|
"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f"
|
||||||
"checksum parity-util-mem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8174d85e62c4d615fddd1ef67966bdc5757528891d0742f15b131ad04667b3f9"
|
"checksum parity-util-mem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8174d85e62c4d615fddd1ef67966bdc5757528891d0742f15b131ad04667b3f9"
|
||||||
"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc"
|
|
||||||
"checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865"
|
"checksum parity-wasm 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865"
|
||||||
|
"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc"
|
||||||
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
||||||
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
|
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
|
||||||
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
|
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
|
||||||
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
||||||
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
|
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
|
||||||
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
|
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
|
||||||
|
"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1"
|
||||||
"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49"
|
"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49"
|
||||||
"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
|
"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5"
|
||||||
"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
|
"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
|
||||||
@@ -7683,7 +7696,8 @@ dependencies = [
|
|||||||
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||||
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
|
||||||
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
|
"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
|
||||||
"checksum shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be289420c5900abb177b756f39625ca7a0df68069cfb242fb31feb6e8c480f04"
|
"checksum shared_memory 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3ab0cdff84d6c66fc9e268010ea6508e58ee942575afb66f2cf194bb218bb4"
|
||||||
|
"checksum shared_memory_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767a14f1304be2f0b04e69860252f8ae9cfae0afaa9cc07b675147c43425dd3a"
|
||||||
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
||||||
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
@@ -7829,9 +7843,7 @@ dependencies = [
|
|||||||
"checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d"
|
"checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d"
|
||||||
"checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5"
|
"checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5"
|
||||||
"checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac"
|
"checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac"
|
||||||
"checksum wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aebbaef470840d157a5c47c8c49f024da7b1b80e90ff729ca982b2b80447e78b"
|
|
||||||
"checksum wasmi 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff"
|
"checksum wasmi 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff"
|
||||||
"checksum wasmi-validation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab380192444b3e8522ae79c0a1976e42a82920916ccdfbce3def89f456ea33f3"
|
|
||||||
"checksum wasmi-validation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93"
|
"checksum wasmi-validation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93"
|
||||||
"checksum wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470"
|
"checksum wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470"
|
||||||
"checksum wasmtime-debug 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5008729ad53f75020f28fa0d682269335d6f0eac0b3ffafe31f185b2f33aca74"
|
"checksum wasmtime-debug 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5008729ad53f75020f28fa0d682269335d6f0eac0b3ffafe31f185b2f33aca74"
|
||||||
|
|||||||
@@ -7,17 +7,20 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "parity-scale-codec", version = "1.1.0", default-features = false, features = [ "derive" ] }
|
codec = { package = "parity-scale-codec", version = "1.1.0", default-features = false, features = [ "derive" ] }
|
||||||
wasmi = { version = "0.4.5", optional = true }
|
derive_more = { version = "0.99.2", optional = true }
|
||||||
derive_more = { version = "0.14.1", optional = true }
|
serde = { version = "1.0.102", default-features = false, features = [ "derive" ], optional = true }
|
||||||
serde = { version = "1.0.102", default-features = false, features = [ "derive" ] }
|
|
||||||
rstd = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
rstd = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
||||||
|
sp-runtime-interface = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
|
||||||
|
sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", optional = true }
|
||||||
|
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", optional = true }
|
||||||
|
sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", optional = true }
|
||||||
lazy_static = { version = "1.4.0", optional = true }
|
lazy_static = { version = "1.4.0", optional = true }
|
||||||
parking_lot = { version = "0.7.1", optional = true }
|
parking_lot = { version = "0.10.0", optional = true }
|
||||||
log = { version = "0.4.8", optional = true }
|
log = { version = "0.4.8", optional = true }
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "unknown"))'.dependencies]
|
[target.'cfg(not(target_os = "unknown"))'.dependencies]
|
||||||
shared_memory = { version = "0.8.2", optional = true }
|
shared_memory = { version = "0.10.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tiny-keccak = "1.5.0"
|
tiny-keccak = "1.5.0"
|
||||||
@@ -29,7 +32,6 @@ default = ["std"]
|
|||||||
wasm-api = []
|
wasm-api = []
|
||||||
std = [
|
std = [
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"wasmi",
|
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"serde/std",
|
"serde/std",
|
||||||
"rstd/std",
|
"rstd/std",
|
||||||
@@ -37,5 +39,9 @@ std = [
|
|||||||
"sp-core/std",
|
"sp-core/std",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"log"
|
"log",
|
||||||
|
"sp-runtime-interface/std",
|
||||||
|
"sp-externalities",
|
||||||
|
"sc-executor",
|
||||||
|
"sp-io",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -22,40 +22,40 @@
|
|||||||
//! ## Parachain WASM
|
//! ## Parachain WASM
|
||||||
//!
|
//!
|
||||||
//! Polkadot parachain WASM is in the form of a module which imports a memory
|
//! Polkadot parachain WASM is in the form of a module which imports a memory
|
||||||
//! instance and exports a function `validate`.
|
//! instance and exports a function `validate_block`.
|
||||||
//!
|
//!
|
||||||
//! `validate` accepts as input two `i32` values, representing a pointer/length pair
|
//! `validate` accepts as input two `i32` values, representing a pointer/length pair
|
||||||
//! respectively, that encodes `ValidationParams`.
|
//! respectively, that encodes [`ValidationParams`].
|
||||||
//!
|
//!
|
||||||
//! `validate` returns an `i32` which is a pointer to a little-endian 32-bit integer denoting a length.
|
//! `validate` returns an `u64` which is a pointer to an `u8` array and its length.
|
||||||
//! Subtracting the length from the initial pointer will give a new pointer to the actual return data,
|
//! The data in the array is expected to be a SCALE encoded [`ValidationResult`].
|
||||||
//!
|
//!
|
||||||
//! ASCII-diagram demonstrating the return data format:
|
//! ASCII-diagram demonstrating the return data format:
|
||||||
//!
|
//!
|
||||||
//! ```ignore
|
//! ```ignore
|
||||||
//! [return data][len (LE-u32)]
|
//! [pointer][length]
|
||||||
//! ^~~returned pointer
|
//! 32bit 32bit
|
||||||
|
//! ^~~ returned pointer & length
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The `wasm_api` module (enabled only with the wasm-api feature) provides utilities
|
//! The wasm-api (enabled only when `std` feature is not enabled and `wasm-api` feature is enabled)
|
||||||
//! for setting up a parachain WASM module in Rust.
|
//! provides utilities for setting up a parachain WASM module in Rust.
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
/// Re-export of parity-codec.
|
|
||||||
pub use codec;
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod wasm_executor;
|
pub mod wasm_executor;
|
||||||
|
|
||||||
#[cfg(feature = "wasm-api")]
|
mod wasm_api;
|
||||||
pub mod wasm_api;
|
|
||||||
|
|
||||||
use rstd::vec::Vec;
|
use rstd::{vec::Vec, cmp::Ordering};
|
||||||
|
|
||||||
use codec::{Encode, Decode, CompactAs};
|
use codec::{Encode, Decode, CompactAs};
|
||||||
use sp_core::{RuntimeDebug, TypeId};
|
use sp_core::{RuntimeDebug, TypeId};
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "std"), feature = "wasm-api"))]
|
||||||
|
pub use wasm_api::*;
|
||||||
|
|
||||||
/// Validation parameters for evaluating the parachain validity function.
|
/// Validation parameters for evaluating the parachain validity function.
|
||||||
// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
|
// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
|
||||||
#[derive(PartialEq, Eq, Decode)]
|
#[derive(PartialEq, Eq, Decode)]
|
||||||
@@ -155,7 +155,8 @@ pub trait AccountIdConversion<AccountId>: Sized {
|
|||||||
fn try_from_account(a: &AccountId) -> Option<Self>;
|
fn try_from_account(a: &AccountId) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format is b"para" ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing zeroes to fill AccountId.
|
/// Format is b"para" ++ encode(parachain ID) ++ 00.... where 00... is indefinite trailing
|
||||||
|
/// zeroes to fill AccountId.
|
||||||
impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
|
impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
|
||||||
fn into_account(&self) -> T {
|
fn into_account(&self) -> T {
|
||||||
(b"para", self).using_encoded(|b|
|
(b"para", self).using_encoded(|b|
|
||||||
@@ -177,24 +178,6 @@ impl<T: Encode + Decode + Default> AccountIdConversion<T> for Id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An incoming message.
|
|
||||||
#[derive(PartialEq, Eq, Decode)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Debug, Encode))]
|
|
||||||
pub struct IncomingMessage {
|
|
||||||
/// The source parachain.
|
|
||||||
pub source: Id,
|
|
||||||
/// The data of the message.
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A reference to a message.
|
|
||||||
pub struct MessageRef<'a> {
|
|
||||||
/// The target parachain.
|
|
||||||
pub target: Id,
|
|
||||||
/// Underlying data of the message.
|
|
||||||
pub data: &'a [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Which origin a parachain's message to the relay chain should be dispatched from.
|
/// Which origin a parachain's message to the relay chain should be dispatched from.
|
||||||
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
@@ -224,16 +207,8 @@ impl rstd::convert::TryFrom<u8> for ParachainDispatchOrigin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reference to an upward message.
|
|
||||||
pub struct UpwardMessageRef<'a> {
|
|
||||||
/// The origin type.
|
|
||||||
pub origin: ParachainDispatchOrigin,
|
|
||||||
/// Underlying data of the message.
|
|
||||||
pub data: &'a [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A message from a parachain to its Relay Chain.
|
/// A message from a parachain to its Relay Chain.
|
||||||
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, sp_runtime_interface::pass_by::PassByCodec)]
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
pub struct UpwardMessage {
|
pub struct UpwardMessage {
|
||||||
/// The origin for the message to be sent from.
|
/// The origin for the message to be sent from.
|
||||||
@@ -241,3 +216,43 @@ pub struct UpwardMessage {
|
|||||||
/// The message data.
|
/// The message data.
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An incoming message.
|
||||||
|
#[derive(PartialEq, Eq, Decode)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Debug, Encode))]
|
||||||
|
pub struct IncomingMessage {
|
||||||
|
/// The source parachain.
|
||||||
|
pub source: Id,
|
||||||
|
/// The data of the message.
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A message targeted to a specific parachain.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Encode, Decode, sp_runtime_interface::pass_by::PassByCodec)]
|
||||||
|
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Debug))]
|
||||||
|
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
|
||||||
|
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
|
||||||
|
pub struct TargetedMessage {
|
||||||
|
/// The target parachain.
|
||||||
|
pub target: Id,
|
||||||
|
/// The message data.
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for TargetedMessage {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.data[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for TargetedMessage {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.target.cmp(&other.target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for TargetedMessage {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.target.cmp(&other.target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,13 +16,31 @@
|
|||||||
|
|
||||||
//! Utilities for writing parachain WASM.
|
//! Utilities for writing parachain WASM.
|
||||||
|
|
||||||
use codec::{Encode, Decode};
|
use crate::{TargetedMessage, UpwardMessage};
|
||||||
use super::{ValidationParams, ValidationResult, MessageRef, UpwardMessageRef};
|
use sp_runtime_interface::runtime_interface;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use sp_externalities::ExternalitiesExt;
|
||||||
|
|
||||||
mod ll {
|
/// The parachain api for posting messages.
|
||||||
extern "C" {
|
// Either activate on `std` to get access to the `HostFunctions` or when `wasm-api` is given and on
|
||||||
pub(super) fn ext_post_message(target: u32, data_ptr: *const u8, data_len: u32);
|
// `no_std`.
|
||||||
pub(super) fn ext_post_upward_message(origin: u32, data_ptr: *const u8, data_len: u32);
|
#[cfg(any(feature = "std", all(not(feature = "std"), feature = "wasm-api")))]
|
||||||
|
#[runtime_interface]
|
||||||
|
pub trait Parachain {
|
||||||
|
/// Post a message to another parachain.
|
||||||
|
fn post_message(&mut self, msg: TargetedMessage) {
|
||||||
|
self.extension::<crate::wasm_executor::ParachainExt>()
|
||||||
|
.expect("No `ParachainExt` associated with the current context.")
|
||||||
|
.post_message(msg)
|
||||||
|
.expect("Failed to post message")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Post a message to this parachain's relay chain.
|
||||||
|
fn post_upward_message(&mut self, msg: UpwardMessage) {
|
||||||
|
self.extension::<crate::wasm_executor::ParachainExt>()
|
||||||
|
.expect("No `ParachainExt` associated with the current context.")
|
||||||
|
.post_upward_message(msg)
|
||||||
|
.expect("Failed to post upward message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,43 +48,18 @@ mod ll {
|
|||||||
///
|
///
|
||||||
/// Offset and length must have been provided by the validation
|
/// Offset and length must have been provided by the validation
|
||||||
/// function's entry point.
|
/// function's entry point.
|
||||||
pub unsafe fn load_params(params: *const u8, len: usize) -> ValidationParams {
|
#[cfg(not(feature = "std"))]
|
||||||
|
pub unsafe fn load_params(params: *const u8, len: usize) -> crate::ValidationParams {
|
||||||
let mut slice = rstd::slice::from_raw_parts(params, len);
|
let mut slice = rstd::slice::from_raw_parts(params, len);
|
||||||
|
|
||||||
ValidationParams::decode(&mut slice).expect("Invalid input data")
|
codec::Decode::decode(&mut slice).expect("Invalid input data")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate the validation result in memory, getting the return-pointer back.
|
/// Allocate the validation result in memory, getting the return-pointer back.
|
||||||
///
|
///
|
||||||
/// As described in the crate docs, this is a pointer to the appended length
|
/// As described in the crate docs, this is a pointer to the appended length
|
||||||
/// of the vector.
|
/// of the vector.
|
||||||
pub fn write_result(result: ValidationResult) -> usize {
|
#[cfg(not(feature = "std"))]
|
||||||
let mut encoded = result.encode();
|
pub fn write_result(result: &crate::ValidationResult) -> u64 {
|
||||||
let len = encoded.len();
|
sp_core::to_substrate_wasm_fn_return_value(&result)
|
||||||
|
|
||||||
assert!(len <= u32::max_value() as usize, "Len too large for parachain-WASM abi");
|
|
||||||
(len as u32).using_encoded(|s| encoded.extend(s));
|
|
||||||
|
|
||||||
// do not alter `encoded` beyond this point. may reallocate.
|
|
||||||
let end_ptr = &encoded[len] as *const u8 as usize;
|
|
||||||
|
|
||||||
// leak so it doesn't get zeroed.
|
|
||||||
rstd::mem::forget(encoded);
|
|
||||||
end_ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Post a message to another parachain.
|
|
||||||
pub fn post_message(message: MessageRef) {
|
|
||||||
let data_ptr = message.data.as_ptr();
|
|
||||||
let data_len = message.data.len();
|
|
||||||
|
|
||||||
unsafe { ll::ext_post_message(message.target.into(), data_ptr, data_len as u32) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Post a message to this parachain's relay chain.
|
|
||||||
pub fn post_upward_message(message: UpwardMessageRef) {
|
|
||||||
let data_ptr = message.data.as_ptr();
|
|
||||||
let data_len = message.data.len();
|
|
||||||
|
|
||||||
unsafe { ll::ext_post_upward_message(u32::from(message.origin as u8), data_ptr, data_len as u32) }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,16 +20,10 @@
|
|||||||
//! Assuming the parameters are correct, this module provides a wrapper around
|
//! Assuming the parameters are correct, this module provides a wrapper around
|
||||||
//! a WASM VM for re-execution of a parachain candidate.
|
//! a WASM VM for re-execution of a parachain candidate.
|
||||||
|
|
||||||
use std::{cell::RefCell, fmt, convert::TryInto};
|
use std::any::{TypeId, Any};
|
||||||
use crate::codec::{Decode, Encode};
|
use crate::{ValidationParams, ValidationResult, UpwardMessage, TargetedMessage};
|
||||||
use wasmi::{
|
use codec::{Decode, Encode};
|
||||||
self, Module, ModuleInstance, Trap, MemoryInstance, MemoryDescriptor, MemoryRef,
|
use sp_core::storage::{ChildStorageKey, ChildInfo};
|
||||||
ModuleImportResolver, RuntimeValue, Externals, Error as WasmError, ValueType,
|
|
||||||
memory_units::{self, Bytes, Pages, RoundUpTo}
|
|
||||||
};
|
|
||||||
use super::{
|
|
||||||
ValidationParams, ValidationResult, MessageRef, UpwardMessageRef,
|
|
||||||
UpwardMessage, IncomingMessage};
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "unknown"))]
|
#[cfg(not(target_os = "unknown"))]
|
||||||
pub use validation_host::{run_worker, EXECUTION_TIMEOUT_SEC};
|
pub use validation_host::{run_worker, EXECUTION_TIMEOUT_SEC};
|
||||||
@@ -40,12 +34,16 @@ mod validation_host;
|
|||||||
const MAX_RUNTIME_MEM: usize = 1024 * 1024 * 1024; // 1 GiB
|
const MAX_RUNTIME_MEM: usize = 1024 * 1024 * 1024; // 1 GiB
|
||||||
const MAX_CODE_MEM: usize = 16 * 1024 * 1024; // 16 MiB
|
const MAX_CODE_MEM: usize = 16 * 1024 * 1024; // 16 MiB
|
||||||
|
|
||||||
mod ids {
|
sp_externalities::decl_extension! {
|
||||||
/// Post a message to another parachain.
|
/// The extension that is registered at the `Externalities` when validating a parachain state
|
||||||
pub const POST_MESSAGE: usize = 1;
|
/// transition.
|
||||||
|
pub(crate) struct ParachainExt(Box<dyn Externalities>);
|
||||||
|
}
|
||||||
|
|
||||||
/// Post a message to this parachain's relay chain.
|
impl ParachainExt {
|
||||||
pub const POST_UPWARD_MESSAGE: usize = 2;
|
pub fn new<T: Externalities + 'static>(ext: T) -> Self {
|
||||||
|
Self(Box::new(ext))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WASM code execution mode.
|
/// WASM code execution mode.
|
||||||
@@ -63,16 +61,16 @@ pub enum ExecutionMode {
|
|||||||
/// Error type for the wasm executor
|
/// Error type for the wasm executor
|
||||||
#[derive(Debug, derive_more::Display, derive_more::From)]
|
#[derive(Debug, derive_more::Display, derive_more::From)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Wasm error
|
/// Wasm executor error.
|
||||||
Wasm(WasmError),
|
#[display(fmt = "WASM executor error: {:?}", _0)]
|
||||||
/// Externalities error
|
WasmExecutor(sc_executor::error::Error),
|
||||||
Externalities(ExternalitiesError),
|
/// Call data is too large.
|
||||||
|
#[display(fmt = "Validation parameters are {} bytes, max allowed is {}", _0, MAX_RUNTIME_MEM)]
|
||||||
|
#[from(ignore)]
|
||||||
|
ParamsTooLarge(usize),
|
||||||
/// Code size it too large.
|
/// Code size it too large.
|
||||||
#[display(fmt = "WASM code is {} bytes, max allowed is {}", _0, MAX_CODE_MEM)]
|
#[display(fmt = "WASM code is {} bytes, max allowed is {}", _0, MAX_CODE_MEM)]
|
||||||
CodeTooLarge(usize),
|
CodeTooLarge(usize),
|
||||||
/// Call data is too large.
|
|
||||||
#[display(fmt = "Validation parameters are {} bytes, max allowed is {}", _0, MAX_RUNTIME_MEM)]
|
|
||||||
ParamsTooLarge(usize),
|
|
||||||
/// Bad return data or type.
|
/// Bad return data or type.
|
||||||
#[display(fmt = "Validation function returned invalid data.")]
|
#[display(fmt = "Validation function returned invalid data.")]
|
||||||
BadReturn,
|
BadReturn,
|
||||||
@@ -84,264 +82,54 @@ pub enum Error {
|
|||||||
System(Box<dyn std::error::Error>),
|
System(Box<dyn std::error::Error>),
|
||||||
#[display(fmt = "WASM worker error: {}", _0)]
|
#[display(fmt = "WASM worker error: {}", _0)]
|
||||||
External(String),
|
External(String),
|
||||||
|
#[display(fmt = "Shared memory error: {}", _0)]
|
||||||
|
#[cfg(not(target_os = "unknown"))]
|
||||||
|
SharedMem(shared_memory::SharedMemError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
Error::Wasm(ref err) => Some(err),
|
Error::WasmExecutor(ref err) => Some(err),
|
||||||
Error::Externalities(ref err) => Some(err),
|
|
||||||
Error::Io(ref err) => Some(err),
|
Error::Io(ref err) => Some(err),
|
||||||
Error::System(ref err) => Some(&**err),
|
Error::System(ref err) => Some(&**err),
|
||||||
|
#[cfg(not(target_os = "unknown"))]
|
||||||
|
Error::SharedMem(ref err) => Some(err),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can occur in externalities of parachain validation.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ExternalitiesError {
|
|
||||||
/// Unable to post a message due to the given reason.
|
|
||||||
CannotPostMessage(&'static str),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Externalities for parachain validation.
|
/// Externalities for parachain validation.
|
||||||
pub trait Externalities {
|
pub trait Externalities: Send {
|
||||||
/// Called when a message is to be posted to another parachain.
|
/// Called when a message is to be posted to another parachain.
|
||||||
fn post_message(&mut self, message: MessageRef) -> Result<(), ExternalitiesError>;
|
fn post_message(&mut self, message: TargetedMessage) -> Result<(), String>;
|
||||||
|
|
||||||
/// Called when a message is to be posted to the parachain's relay chain.
|
/// Called when a message is to be posted to the parachain's relay chain.
|
||||||
fn post_upward_message(&mut self, message: UpwardMessageRef) -> Result<(), ExternalitiesError>;
|
fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String>;
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ExternalitiesError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
ExternalitiesError::CannotPostMessage(ref s)
|
|
||||||
=> write!(f, "Cannot post message: {}", s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl wasmi::HostError for ExternalitiesError {}
|
|
||||||
impl std::error::Error for ExternalitiesError {}
|
|
||||||
|
|
||||||
struct Resolver {
|
|
||||||
max_memory: u32, // in pages.
|
|
||||||
memory: RefCell<Option<MemoryRef>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ModuleImportResolver for Resolver {
|
|
||||||
fn resolve_func(
|
|
||||||
&self,
|
|
||||||
field_name: &str,
|
|
||||||
signature: &wasmi::Signature
|
|
||||||
) -> Result<wasmi::FuncRef, WasmError> {
|
|
||||||
match field_name {
|
|
||||||
"ext_post_message" => {
|
|
||||||
let index = ids::POST_MESSAGE;
|
|
||||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
|
||||||
(&[ValueType::I32, ValueType::I32, ValueType::I32], None);
|
|
||||||
|
|
||||||
if signature.params() != params || signature.return_type() != ret_ty {
|
|
||||||
Err(WasmError::Instantiation(
|
|
||||||
format!("Export {} has a bad signature", field_name)
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok(wasmi::FuncInstance::alloc_host(
|
|
||||||
wasmi::Signature::new(¶ms[..], ret_ty),
|
|
||||||
index,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"ext_upwards_post_message" => {
|
|
||||||
let index = ids::POST_UPWARD_MESSAGE;
|
|
||||||
let (params, ret_ty): (&[ValueType], Option<ValueType>) =
|
|
||||||
(&[ValueType::I32, ValueType::I32], None);
|
|
||||||
|
|
||||||
if signature.params() != params || signature.return_type() != ret_ty {
|
|
||||||
Err(WasmError::Instantiation(
|
|
||||||
format!("Export {} has a bad signature", field_name)
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok(wasmi::FuncInstance::alloc_host(
|
|
||||||
wasmi::Signature::new(¶ms[..], ret_ty),
|
|
||||||
index,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
Err(WasmError::Instantiation(
|
|
||||||
format!("Export {} not found", field_name),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_memory(
|
|
||||||
&self,
|
|
||||||
field_name: &str,
|
|
||||||
descriptor: &MemoryDescriptor,
|
|
||||||
) -> Result<MemoryRef, WasmError> {
|
|
||||||
if field_name == "memory" {
|
|
||||||
let effective_max = descriptor.maximum().unwrap_or(self.max_memory);
|
|
||||||
if descriptor.initial() > self.max_memory || effective_max > self.max_memory {
|
|
||||||
Err(WasmError::Instantiation("Module requested too much memory".to_owned()))
|
|
||||||
} else {
|
|
||||||
let mem = MemoryInstance::alloc(
|
|
||||||
memory_units::Pages(descriptor.initial() as usize),
|
|
||||||
descriptor.maximum().map(|x| memory_units::Pages(x as usize)),
|
|
||||||
)?;
|
|
||||||
*self.memory.borrow_mut() = Some(mem.clone());
|
|
||||||
Ok(mem)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(WasmError::Instantiation("Memory imported under unknown name".to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ValidationExternals<'a, E: 'a> {
|
|
||||||
externalities: &'a mut E,
|
|
||||||
memory: &'a MemoryRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: 'a + Externalities> ValidationExternals<'a, E> {
|
|
||||||
/// Signature: post_message(u32, *const u8, u32) -> None
|
|
||||||
/// usage: post_message(target parachain, data ptr, data len).
|
|
||||||
/// Data is the raw data of the message.
|
|
||||||
fn ext_post_message(&mut self, args: ::wasmi::RuntimeArgs) -> Result<(), Trap> {
|
|
||||||
let target: u32 = args.nth_checked(0)?;
|
|
||||||
let data_ptr: u32 = args.nth_checked(1)?;
|
|
||||||
let data_len: u32 = args.nth_checked(2)?;
|
|
||||||
|
|
||||||
let (data_ptr, data_len) = (data_ptr as usize, data_len as usize);
|
|
||||||
|
|
||||||
self.memory.with_direct_access(|mem| {
|
|
||||||
if mem.len() < (data_ptr + data_len) {
|
|
||||||
Err(Trap::new(wasmi::TrapKind::MemoryAccessOutOfBounds))
|
|
||||||
} else {
|
|
||||||
let res = self.externalities.post_message(MessageRef {
|
|
||||||
target: target.into(),
|
|
||||||
data: &mem[data_ptr..][..data_len],
|
|
||||||
});
|
|
||||||
|
|
||||||
res.map_err(|e| Trap::new(wasmi::TrapKind::Host(
|
|
||||||
Box::new(e) as Box<_>
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/// Signature: post_upward_message(u32, *const u8, u32) -> None
|
|
||||||
/// usage: post_upward_message(origin, data ptr, data len).
|
|
||||||
/// Origin is the integer representation of the dispatch origin.
|
|
||||||
/// Data is the raw data of the message.
|
|
||||||
fn ext_post_upward_message(&mut self, args: ::wasmi::RuntimeArgs) -> Result<(), Trap> {
|
|
||||||
let origin: u32 = args.nth_checked(0)?;
|
|
||||||
let data_ptr: u32 = args.nth_checked(1)?;
|
|
||||||
let data_len: u32 = args.nth_checked(2)?;
|
|
||||||
|
|
||||||
let (data_ptr, data_len) = (data_ptr as usize, data_len as usize);
|
|
||||||
|
|
||||||
self.memory.with_direct_access(|mem| {
|
|
||||||
if mem.len() < (data_ptr + data_len) {
|
|
||||||
Err(Trap::new(wasmi::TrapKind::MemoryAccessOutOfBounds))
|
|
||||||
} else {
|
|
||||||
let origin = (origin as u8).try_into()
|
|
||||||
.map_err(|_| Trap::new(wasmi::TrapKind::UnexpectedSignature))?;
|
|
||||||
let message = UpwardMessageRef { origin, data: &mem[data_ptr..][..data_len] };
|
|
||||||
let res = self.externalities.post_upward_message(message);
|
|
||||||
res.map_err(|e| Trap::new(wasmi::TrapKind::Host(
|
|
||||||
Box::new(e) as Box<_>
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: 'a + Externalities> Externals for ValidationExternals<'a, E> {
|
|
||||||
fn invoke_index(
|
|
||||||
&mut self,
|
|
||||||
index: usize,
|
|
||||||
args: ::wasmi::RuntimeArgs,
|
|
||||||
) -> Result<Option<RuntimeValue>, Trap> {
|
|
||||||
match index {
|
|
||||||
ids::POST_MESSAGE => self.ext_post_message(args).map(|_| None),
|
|
||||||
ids::POST_UPWARD_MESSAGE => self.ext_post_upward_message(args).map(|_| None),
|
|
||||||
_ => panic!("no externality at given index"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Params header in shared memory. All offsets should be aligned to WASM page size.
|
|
||||||
#[derive(Encode, Decode, Debug)]
|
|
||||||
struct ValidationHeader {
|
|
||||||
code_size: u64,
|
|
||||||
params_size: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Encode, Decode, Debug)]
|
|
||||||
pub enum ValidationResultHeader {
|
|
||||||
Ok {
|
|
||||||
result: ValidationResult,
|
|
||||||
egress_message_count: u64,
|
|
||||||
up_message_count: u64,
|
|
||||||
},
|
|
||||||
Error(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct WorkerExternalities {
|
|
||||||
egress_data: Vec<u8>,
|
|
||||||
egress_message_count: usize,
|
|
||||||
up_data: Vec<u8>,
|
|
||||||
up_message_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Externalities for WorkerExternalities {
|
|
||||||
fn post_message(&mut self, message: MessageRef) -> Result<(), ExternalitiesError> {
|
|
||||||
IncomingMessage {
|
|
||||||
source: message.target,
|
|
||||||
data: message.data.to_vec(),
|
|
||||||
}
|
|
||||||
.encode_to(&mut self.egress_data);
|
|
||||||
self.egress_message_count += 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn post_upward_message(&mut self, message: UpwardMessageRef) -> Result<(), ExternalitiesError> {
|
|
||||||
UpwardMessage {
|
|
||||||
origin: message.origin,
|
|
||||||
data: message.data.to_vec(),
|
|
||||||
}
|
|
||||||
.encode_to(&mut self.up_data);
|
|
||||||
self.up_message_count += 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate a candidate under the given validation code.
|
/// Validate a candidate under the given validation code.
|
||||||
///
|
///
|
||||||
/// This will fail if the validation code is not a proper parachain validation module.
|
/// This will fail if the validation code is not a proper parachain validation module.
|
||||||
pub fn validate_candidate<E: Externalities>(
|
pub fn validate_candidate<E: Externalities + 'static>(
|
||||||
validation_code: &[u8],
|
validation_code: &[u8],
|
||||||
params: ValidationParams,
|
params: ValidationParams,
|
||||||
externalities: &mut E,
|
ext: E,
|
||||||
options: ExecutionMode,
|
options: ExecutionMode,
|
||||||
) -> Result<ValidationResult, Error>
|
) -> Result<ValidationResult, Error> {
|
||||||
{
|
|
||||||
match options {
|
match options {
|
||||||
ExecutionMode::Local => {
|
ExecutionMode::Local => {
|
||||||
validate_candidate_internal(validation_code, ¶ms.encode(), externalities)
|
validate_candidate_internal(validation_code, ¶ms.encode(), ext)
|
||||||
},
|
},
|
||||||
#[cfg(not(target_os = "unknown"))]
|
#[cfg(not(target_os = "unknown"))]
|
||||||
ExecutionMode::Remote =>
|
ExecutionMode::Remote => {
|
||||||
validation_host::validate_candidate(validation_code, params, externalities, false),
|
validation_host::validate_candidate(validation_code, params, ext, false)
|
||||||
|
},
|
||||||
#[cfg(not(target_os = "unknown"))]
|
#[cfg(not(target_os = "unknown"))]
|
||||||
ExecutionMode::RemoteTest =>
|
ExecutionMode::RemoteTest => {
|
||||||
validation_host::validate_candidate(validation_code, params, externalities, true),
|
validation_host::validate_candidate(validation_code, params, ext, true)
|
||||||
|
},
|
||||||
#[cfg(target_os = "unknown")]
|
#[cfg(target_os = "unknown")]
|
||||||
ExecutionMode::Remote =>
|
ExecutionMode::Remote =>
|
||||||
Err(Error::System("Remote validator not available".to_string().into())),
|
Err(Error::System("Remote validator not available".to_string().into())),
|
||||||
@@ -351,105 +139,120 @@ pub fn validate_candidate<E: Externalities>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The host functions provided by the wasm executor to the parachain wasm blob.
|
||||||
|
type HostFunctions = (sp_io::SubstrateHostFunctions, crate::wasm_api::parachain::HostFunctions);
|
||||||
|
|
||||||
/// Validate a candidate under the given validation code.
|
/// Validate a candidate under the given validation code.
|
||||||
///
|
///
|
||||||
/// This will fail if the validation code is not a proper parachain validation module.
|
/// This will fail if the validation code is not a proper parachain validation module.
|
||||||
pub fn validate_candidate_internal<E: Externalities>(
|
pub fn validate_candidate_internal<E: Externalities + 'static>(
|
||||||
validation_code: &[u8],
|
validation_code: &[u8],
|
||||||
encoded_call_data: &[u8],
|
encoded_call_data: &[u8],
|
||||||
externalities: &mut E,
|
externalities: E,
|
||||||
) -> Result<ValidationResult, Error> {
|
) -> Result<ValidationResult, Error> {
|
||||||
use wasmi::LINEAR_MEMORY_PAGE_SIZE;
|
let mut ext = ValidationExternalities(ParachainExt::new(externalities));
|
||||||
|
|
||||||
// instantiate the module.
|
let res = sc_executor::call_in_wasm::<_, HostFunctions>(
|
||||||
let memory;
|
"validate_block",
|
||||||
let mut externals;
|
encoded_call_data,
|
||||||
let module = {
|
sc_executor::WasmExecutionMethod::Interpreted,
|
||||||
let module = Module::from_buffer(validation_code)?;
|
&mut ext,
|
||||||
|
validation_code,
|
||||||
let module_resolver = Resolver {
|
// TODO: Make sure we don't use more than 1GB: https://github.com/paritytech/polkadot/issues/699
|
||||||
max_memory: (MAX_RUNTIME_MEM / LINEAR_MEMORY_PAGE_SIZE.0) as u32,
|
1024,
|
||||||
memory: RefCell::new(None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let module = ModuleInstance::new(
|
|
||||||
&module,
|
|
||||||
&wasmi::ImportsBuilder::new().with_resolver("env", &module_resolver),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
memory = module_resolver.memory.borrow()
|
ValidationResult::decode(&mut &res[..]).map_err(|_| Error::BadReturn.into())
|
||||||
.as_ref()
|
|
||||||
.ok_or_else(|| WasmError::Instantiation("No imported memory instance".to_owned()))?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
externals = ValidationExternals {
|
|
||||||
externalities,
|
|
||||||
memory: &memory,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.run_start(&mut externals).map_err(WasmError::Trap)?
|
|
||||||
};
|
|
||||||
|
|
||||||
// allocate call data in memory.
|
|
||||||
// we guarantee that:
|
|
||||||
// - `offset` has alignment at least of 8,
|
|
||||||
// - `len` is not zero.
|
|
||||||
let (offset, len) = {
|
|
||||||
// hard limit from WASM.
|
|
||||||
if encoded_call_data.len() > i32::max_value() as usize {
|
|
||||||
return Err(Error::ParamsTooLarge(encoded_call_data.len()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate sufficient amount of wasm pages to fit encoded call data.
|
/// The validation externalities that will panic on any storage related access. They just provide
|
||||||
let call_data_pages: Pages = Bytes(encoded_call_data.len()).round_up_to();
|
/// access to the parachain extension.
|
||||||
let allocated_mem_start: Bytes = memory.grow(call_data_pages)?.into();
|
struct ValidationExternalities(ParachainExt);
|
||||||
|
|
||||||
memory.set(allocated_mem_start.0 as u32, &encoded_call_data)
|
impl sp_externalities::Externalities for ValidationExternalities {
|
||||||
.expect(
|
fn storage(&self, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
"enough memory allocated just before this; \
|
panic!("storage: unsupported feature for parachain validation")
|
||||||
copying never fails if memory is large enough; qed"
|
}
|
||||||
);
|
|
||||||
|
|
||||||
(allocated_mem_start.0, encoded_call_data.len())
|
fn storage_hash(&self, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
};
|
panic!("storage_hash: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
let output = module.invoke_export(
|
fn child_storage_hash(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
"validate_block",
|
panic!("child_storage_hash: unsupported feature for parachain validation")
|
||||||
&[RuntimeValue::I32(offset as i32), RuntimeValue::I32(len as i32)],
|
}
|
||||||
&mut externals,
|
|
||||||
).map_err(|e| -> Error {
|
|
||||||
e.as_host_error()
|
|
||||||
.and_then(|he| he.downcast_ref::<ExternalitiesError>())
|
|
||||||
.map(|ee| Error::Externalities(ee.clone()))
|
|
||||||
.unwrap_or_else(move || e.into())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
match output {
|
fn original_storage(&self, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
Some(RuntimeValue::I32(len_offset)) => {
|
panic!("original_sorage: unsupported feature for parachain validation")
|
||||||
let len_offset = len_offset as u32;
|
}
|
||||||
|
|
||||||
let mut len_bytes = [0u8; 4];
|
fn original_child_storage(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
memory.get_into(len_offset, &mut len_bytes)?;
|
panic!("original_child_storage: unsupported feature for parachain validation")
|
||||||
let len_offset = len_offset as usize;
|
}
|
||||||
|
|
||||||
let len = u32::decode(&mut &len_bytes[..])
|
fn original_storage_hash(&self, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
.map_err(|_| Error::BadReturn)? as usize;
|
panic!("original_storage_hash: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
let return_offset = if len > len_offset {
|
fn original_child_storage_hash(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
return Err(Error::BadReturn);
|
panic!("original_child_storage_hash: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn child_storage(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
panic!("child_storage: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kill_child_storage(&mut self, _: ChildStorageKey, _: ChildInfo) {
|
||||||
|
panic!("kill_child_storage: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_prefix(&mut self, _: &[u8]) {
|
||||||
|
panic!("clear_prefix: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_child_prefix(&mut self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) {
|
||||||
|
panic!("clear_child_prefix: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn place_storage(&mut self, _: Vec<u8>, _: Option<Vec<u8>>) {
|
||||||
|
panic!("place_storage: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn place_child_storage(&mut self, _: ChildStorageKey, _: ChildInfo, _: Vec<u8>, _: Option<Vec<u8>>) {
|
||||||
|
panic!("place_child_storage: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chain_id(&self) -> u64 {
|
||||||
|
panic!("chain_id: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_root(&mut self) -> Vec<u8> {
|
||||||
|
panic!("storage_root: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn child_storage_root(&mut self, _: ChildStorageKey) -> Vec<u8> {
|
||||||
|
panic!("child_storage_root: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_changes_root(&mut self, _: &[u8]) -> Result<Option<Vec<u8>>, ()> {
|
||||||
|
panic!("storage_changes_root: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, _: ChildStorageKey, _: ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
panic!("next_child_storage_key: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, _: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
panic!("next_storage_key: unsupported feature for parachain validation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sp_externalities::ExtensionStore for ValidationExternalities {
|
||||||
|
fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> {
|
||||||
|
if type_id == TypeId::of::<ParachainExt>() {
|
||||||
|
Some(&mut self.0)
|
||||||
} else {
|
} else {
|
||||||
len_offset - len
|
None
|
||||||
};
|
}
|
||||||
|
|
||||||
memory.with_direct_access(|mem| {
|
|
||||||
if mem.len() < return_offset + len {
|
|
||||||
return Err(Error::BadReturn);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidationResult::decode(&mut &mem[return_offset..][..len])
|
|
||||||
.map_err(|_| Error::BadReturn.into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => Err(Error::BadReturn),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
|
|
||||||
#![cfg(not(target_os = "unknown"))]
|
#![cfg(not(target_os = "unknown"))]
|
||||||
|
|
||||||
use std::{process, env, sync::Arc, sync::atomic};
|
use std::{process, env, sync::Arc, sync::atomic, mem};
|
||||||
use crate::codec::{Decode, Encode};
|
use codec::{Decode, Encode, EncodeAppend};
|
||||||
use crate::{ValidationParams, ValidationResult, MessageRef,
|
use crate::{ValidationParams, ValidationResult, UpwardMessage, TargetedMessage};
|
||||||
UpwardMessageRef, UpwardMessage, IncomingMessage};
|
use super::{validate_candidate_internal, Error, Externalities};
|
||||||
use super::{validate_candidate_internal, Error, Externalities, WorkerExternalities};
|
|
||||||
use super::{MAX_CODE_MEM, MAX_RUNTIME_MEM};
|
use super::{MAX_CODE_MEM, MAX_RUNTIME_MEM};
|
||||||
use shared_memory::{SharedMem, SharedMemConf, EventState, WriteLockable, EventWait, EventSet};
|
use shared_memory::{SharedMem, SharedMemConf, EventState, WriteLockable, EventWait, EventSet};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -39,6 +38,37 @@ const NUM_HOSTS: usize = 8;
|
|||||||
/// Execution timeout in seconds;
|
/// Execution timeout in seconds;
|
||||||
pub const EXECUTION_TIMEOUT_SEC: u64 = 5;
|
pub const EXECUTION_TIMEOUT_SEC: u64 = 5;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct WorkerExternalitiesInner {
|
||||||
|
egress_data: Vec<u8>,
|
||||||
|
up_data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
struct WorkerExternalities {
|
||||||
|
inner: Arc<Mutex<WorkerExternalitiesInner>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Externalities for WorkerExternalities {
|
||||||
|
fn post_message(&mut self, message: TargetedMessage) -> Result<(), String> {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.egress_data = <Vec::<TargetedMessage> as EncodeAppend>::append_or_new(
|
||||||
|
mem::replace(&mut inner.egress_data, Vec::new()),
|
||||||
|
std::iter::once(message),
|
||||||
|
).map_err(|e| e.what())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String> {
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
inner.up_data = <Vec::<UpwardMessage> as EncodeAppend>::append_or_new(
|
||||||
|
mem::replace(&mut inner.up_data, Vec::new()),
|
||||||
|
std::iter::once(message),
|
||||||
|
).map_err(|e| e.what())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum Event {
|
enum Event {
|
||||||
CandidateReady = 0,
|
CandidateReady = 0,
|
||||||
ResultReady = 1,
|
ResultReady = 1,
|
||||||
@@ -59,7 +89,8 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
|
|||||||
return Err(format!("Error opening shared memory: {:?}", e));
|
return Err(format!("Error opening shared memory: {:?}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut externalities = WorkerExternalities::default();
|
|
||||||
|
let worker_ext = WorkerExternalities::default();
|
||||||
|
|
||||||
let exit = Arc::new(atomic::AtomicBool::new(false));
|
let exit = Arc::new(atomic::AtomicBool::new(false));
|
||||||
// spawn parent monitor thread
|
// spawn parent monitor thread
|
||||||
@@ -67,7 +98,8 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
|
|||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
let mut in_data = Vec::new();
|
let mut in_data = Vec::new();
|
||||||
std::io::stdin().read_to_end(&mut in_data).ok(); // pipe terminates when parent process exits
|
// pipe terminates when parent process exits
|
||||||
|
std::io::stdin().read_to_end(&mut in_data).ok();
|
||||||
debug!("Parent process is dead. Exiting");
|
debug!("Parent process is dead. Exiting");
|
||||||
exit.store(true, atomic::Ordering::Relaxed);
|
exit.store(true, atomic::Ordering::Relaxed);
|
||||||
});
|
});
|
||||||
@@ -109,23 +141,25 @@ pub fn run_worker(mem_id: &str) -> Result<(), String> {
|
|||||||
let (call_data, _) = call_data.split_at_mut(header.params_size as usize);
|
let (call_data, _) = call_data.split_at_mut(header.params_size as usize);
|
||||||
let message_data = rest;
|
let message_data = rest;
|
||||||
|
|
||||||
let result = validate_candidate_internal(code, call_data, &mut externalities);
|
let result = validate_candidate_internal(code, call_data, worker_ext.clone());
|
||||||
debug!("Candidate validated: {:?}", result);
|
debug!("Candidate validated: {:?}", result);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
if externalities.egress_data.len() + externalities.up_data.len() > MAX_MESSAGE_MEM {
|
let inner = worker_ext.inner.lock();
|
||||||
|
let egress_data = &inner.egress_data;
|
||||||
|
let e_len = egress_data.len();
|
||||||
|
let up_data = &inner.up_data;
|
||||||
|
let up_len = up_data.len();
|
||||||
|
|
||||||
|
if e_len + up_len > MAX_MESSAGE_MEM {
|
||||||
ValidationResultHeader::Error("Message data is too large".into())
|
ValidationResultHeader::Error("Message data is too large".into())
|
||||||
} else {
|
} else {
|
||||||
let e_len = externalities.egress_data.len();
|
message_data[0..e_len].copy_from_slice(egress_data);
|
||||||
let up_len = externalities.up_data.len();
|
|
||||||
message_data[0..e_len].copy_from_slice(&externalities.egress_data);
|
message_data[e_len..(e_len + up_len)].copy_from_slice(&up_data);
|
||||||
message_data[e_len..(e_len + up_len)].copy_from_slice(&externalities.up_data);
|
|
||||||
ValidationResultHeader::Ok {
|
ValidationResultHeader::Ok(r)
|
||||||
result: r,
|
|
||||||
egress_message_count: externalities.egress_message_count as u64,
|
|
||||||
up_message_count: externalities.up_message_count as u64,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => ValidationResultHeader::Error(e.to_string()),
|
Err(e) => ValidationResultHeader::Error(e.to_string()),
|
||||||
@@ -150,11 +184,7 @@ struct ValidationHeader {
|
|||||||
|
|
||||||
#[derive(Encode, Decode, Debug)]
|
#[derive(Encode, Decode, Debug)]
|
||||||
pub enum ValidationResultHeader {
|
pub enum ValidationResultHeader {
|
||||||
Ok {
|
Ok(ValidationResult),
|
||||||
result: ValidationResult,
|
|
||||||
egress_message_count: u64,
|
|
||||||
up_message_count: u64,
|
|
||||||
},
|
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,14 +196,13 @@ struct ValidationHost {
|
|||||||
memory: Option<SharedMem>,
|
memory: Option<SharedMem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Validate a candidate under the given validation code.
|
/// Validate a candidate under the given validation code.
|
||||||
///
|
///
|
||||||
/// This will fail if the validation code is not a proper parachain validation module.
|
/// This will fail if the validation code is not a proper parachain validation module.
|
||||||
pub fn validate_candidate<E: Externalities>(
|
pub fn validate_candidate<E: Externalities>(
|
||||||
validation_code: &[u8],
|
validation_code: &[u8],
|
||||||
params: ValidationParams,
|
params: ValidationParams,
|
||||||
externalities: &mut E,
|
externalities: E,
|
||||||
test_mode: bool,
|
test_mode: bool,
|
||||||
) -> Result<ValidationResult, Error> {
|
) -> Result<ValidationResult, Error> {
|
||||||
for host in HOSTS.iter() {
|
for host in HOSTS.iter() {
|
||||||
@@ -197,7 +226,7 @@ impl Drop for ValidationHost {
|
|||||||
impl ValidationHost {
|
impl ValidationHost {
|
||||||
fn create_memory() -> Result<SharedMem, Error> {
|
fn create_memory() -> Result<SharedMem, Error> {
|
||||||
let mem_size = MAX_RUNTIME_MEM + MAX_CODE_MEM + MAX_MESSAGE_MEM + 1024;
|
let mem_size = MAX_RUNTIME_MEM + MAX_CODE_MEM + MAX_MESSAGE_MEM + 1024;
|
||||||
let mem_config = SharedMemConf::new()
|
let mem_config = SharedMemConf::default()
|
||||||
.set_size(mem_size)
|
.set_size(mem_size)
|
||||||
.add_lock(shared_memory::LockType::Mutex, 0, mem_size)?
|
.add_lock(shared_memory::LockType::Mutex, 0, mem_size)?
|
||||||
.add_event(shared_memory::EventType::Auto)? // Event::CandidateReady
|
.add_event(shared_memory::EventType::Auto)? // Event::CandidateReady
|
||||||
@@ -226,7 +255,10 @@ impl ValidationHost {
|
|||||||
.spawn()?;
|
.spawn()?;
|
||||||
self.worker = Some(worker);
|
self.worker = Some(worker);
|
||||||
|
|
||||||
memory.wait(Event::WorkerReady as usize, shared_memory::Timeout::Sec(EXECUTION_TIMEOUT_SEC as usize))?;
|
memory.wait(
|
||||||
|
Event::WorkerReady as usize,
|
||||||
|
shared_memory::Timeout::Sec(EXECUTION_TIMEOUT_SEC as usize),
|
||||||
|
)?;
|
||||||
self.memory = Some(memory);
|
self.memory = Some(memory);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -238,7 +270,7 @@ impl ValidationHost {
|
|||||||
&mut self,
|
&mut self,
|
||||||
validation_code: &[u8],
|
validation_code: &[u8],
|
||||||
params: ValidationParams,
|
params: ValidationParams,
|
||||||
externalities: &mut E,
|
mut externalities: E,
|
||||||
test_mode: bool,
|
test_mode: bool,
|
||||||
) -> Result<ValidationResult, Error> {
|
) -> Result<ValidationResult, Error> {
|
||||||
if validation_code.len() > MAX_CODE_MEM {
|
if validation_code.len() > MAX_CODE_MEM {
|
||||||
@@ -246,7 +278,8 @@ impl ValidationHost {
|
|||||||
}
|
}
|
||||||
// First, check if need to spawn the child process
|
// First, check if need to spawn the child process
|
||||||
self.start_worker(test_mode)?;
|
self.start_worker(test_mode)?;
|
||||||
let memory = self.memory.as_mut().expect("memory is always `Some` after `start_worker` completes successfully");
|
let memory = self.memory.as_mut()
|
||||||
|
.expect("memory is always `Some` after `start_worker` completes successfully");
|
||||||
{
|
{
|
||||||
// Put data in shared mem
|
// Put data in shared mem
|
||||||
let data: &mut[u8] = &mut **memory.wlock_as_slice(0)?;
|
let data: &mut[u8] = &mut **memory.wlock_as_slice(0)?;
|
||||||
@@ -293,23 +326,23 @@ impl ValidationHost {
|
|||||||
let mut message_data: &[u8] = message_data;
|
let mut message_data: &[u8] = message_data;
|
||||||
let header = ValidationResultHeader::decode(&mut header_buf).unwrap();
|
let header = ValidationResultHeader::decode(&mut header_buf).unwrap();
|
||||||
match header {
|
match header {
|
||||||
ValidationResultHeader::Ok { result, egress_message_count, up_message_count } => {
|
ValidationResultHeader::Ok(result) => {
|
||||||
for _ in 0 .. egress_message_count {
|
let egress = Vec::<TargetedMessage>::decode(&mut message_data)
|
||||||
let message = IncomingMessage::decode(&mut message_data).unwrap();
|
.map_err(|e|
|
||||||
let message_ref = MessageRef {
|
Error::External(
|
||||||
target: message.source,
|
format!("Could not decode egress messages: {}", e.what())
|
||||||
data: &message.data,
|
)
|
||||||
};
|
)?;
|
||||||
externalities.post_message(message_ref)?;
|
egress.into_iter().try_for_each(|msg| externalities.post_message(msg))?;
|
||||||
}
|
|
||||||
for _ in 0 .. up_message_count {
|
let upwards = Vec::<UpwardMessage>::decode(&mut message_data)
|
||||||
let message = UpwardMessage::decode(&mut message_data).unwrap();
|
.map_err(|e|
|
||||||
let message_ref = UpwardMessageRef {
|
Error::External(
|
||||||
origin: message.origin,
|
format!("Could not decode upward messages: {}", e.what())
|
||||||
data: &message.data,
|
)
|
||||||
};
|
)?;
|
||||||
externalities.post_upward_message(message_ref)?;
|
upwards.into_iter().try_for_each(|msg| externalities.post_upward_message(msg))?;
|
||||||
}
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
ValidationResultHeader::Error(message) => {
|
ValidationResultHeader::Error(message) => {
|
||||||
|
|||||||
@@ -18,8 +18,7 @@
|
|||||||
|
|
||||||
use polkadot_parachain as parachain;
|
use polkadot_parachain as parachain;
|
||||||
|
|
||||||
use crate::parachain::{IncomingMessage, ValidationParams};
|
use crate::{DummyExt, parachain::{IncomingMessage, ValidationParams}};
|
||||||
use crate::DummyExt;
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
|
|
||||||
/// Head data for this parachain.
|
/// Head data for this parachain.
|
||||||
@@ -78,7 +77,7 @@ pub fn execute_good_on_parent() {
|
|||||||
block_data: block_data.encode(),
|
block_data: block_data.encode(),
|
||||||
ingress: Vec::new(),
|
ingress: Vec::new(),
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ fn execute_good_chain_on_parent() {
|
|||||||
block_data: block_data.encode(),
|
block_data: block_data.encode(),
|
||||||
ingress: Vec::new(),
|
ingress: Vec::new(),
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
@@ -150,7 +149,7 @@ fn execute_bad_on_parent() {
|
|||||||
block_data: block_data.encode(),
|
block_data: block_data.encode(),
|
||||||
ingress: Vec::new(),
|
ingress: Vec::new(),
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
).unwrap_err();
|
).unwrap_err();
|
||||||
}
|
}
|
||||||
@@ -182,7 +181,7 @@ fn processes_messages() {
|
|||||||
IncomingMessage { source: 3.into(), data: (AddMessage { amount: 256 }).encode() },
|
IncomingMessage { source: 3.into(), data: (AddMessage { amount: 256 }).encode() },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,15 @@ mod wasm_executor;
|
|||||||
|
|
||||||
use polkadot_parachain as parachain;
|
use polkadot_parachain as parachain;
|
||||||
use crate::parachain::{
|
use crate::parachain::{
|
||||||
MessageRef, UpwardMessageRef,
|
TargetedMessage, UpwardMessage, wasm_executor::{Externalities, run_worker},
|
||||||
wasm_executor::{Externalities, ExternalitiesError, run_worker},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DummyExt;
|
struct DummyExt;
|
||||||
impl Externalities for DummyExt {
|
impl Externalities for DummyExt {
|
||||||
fn post_message(&mut self, _message: MessageRef) -> Result<(), ExternalitiesError> {
|
fn post_message(&mut self, _: TargetedMessage) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn post_upward_message(&mut self, _message: UpwardMessageRef) -> Result<(), ExternalitiesError> {
|
fn post_upward_message(&mut self, _: UpwardMessage) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ fn terminates_on_timeout() {
|
|||||||
block_data: Vec::new(),
|
block_data: Vec::new(),
|
||||||
ingress: Vec::new(),
|
ingress: Vec::new(),
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
);
|
);
|
||||||
match result {
|
match result {
|
||||||
@@ -55,7 +55,7 @@ fn parallel_execution() {
|
|||||||
block_data: Vec::new(),
|
block_data: Vec::new(),
|
||||||
ingress: Vec::new(),
|
ingress: Vec::new(),
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
).ok());
|
).ok());
|
||||||
let _ = parachain::wasm_executor::validate_candidate(
|
let _ = parachain::wasm_executor::validate_candidate(
|
||||||
@@ -65,7 +65,7 @@ fn parallel_execution() {
|
|||||||
block_data: Vec::new(),
|
block_data: Vec::new(),
|
||||||
ingress: Vec::new(),
|
ingress: Vec::new(),
|
||||||
},
|
},
|
||||||
&mut DummyExt,
|
DummyExt,
|
||||||
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
parachain::wasm_executor::ExecutionMode::RemoteTest,
|
||||||
);
|
);
|
||||||
thread.join().unwrap();
|
thread.join().unwrap();
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ use application_crypto::KeyTypeId;
|
|||||||
use trie::TrieConfiguration;
|
use trie::TrieConfiguration;
|
||||||
|
|
||||||
pub use polkadot_parachain::{
|
pub use polkadot_parachain::{
|
||||||
Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage,
|
Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage, TargetedMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The key type ID for a collator key.
|
/// The key type ID for a collator key.
|
||||||
@@ -164,36 +164,6 @@ pub struct DutyRoster {
|
|||||||
pub validator_duty: Vec<Chain>,
|
pub validator_duty: Vec<Chain>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A message targeted to a specific parachain.
|
|
||||||
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
|
||||||
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
|
|
||||||
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
|
|
||||||
pub struct TargetedMessage {
|
|
||||||
/// The target parachain.
|
|
||||||
pub target: Id,
|
|
||||||
/// The message data.
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<[u8]> for TargetedMessage {
|
|
||||||
fn as_ref(&self) -> &[u8] {
|
|
||||||
&self.data[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for TargetedMessage {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.target.cmp(&other.target))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for TargetedMessage {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
self.target.cmp(&other.target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Outgoing message data for a parachain candidate.
|
/// Outgoing message data for a parachain candidate.
|
||||||
///
|
///
|
||||||
/// This is data produced by evaluating the candidate. It contains
|
/// This is data produced by evaluating the candidate. It contains
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ fn main() {
|
|||||||
build_current_project_with_rustflags(
|
build_current_project_with_rustflags(
|
||||||
"wasm_binary.rs",
|
"wasm_binary.rs",
|
||||||
WasmBuilderSource::Crates("1.0.7"),
|
WasmBuilderSource::Crates("1.0.7"),
|
||||||
"-C link-arg=--import-memory",
|
"-C link-arg=--export=__heap_base",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ primitives = { package = "polkadot-primitives", path = "../../../primitives" }
|
|||||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
|
||||||
client = { package = "sc-client", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
|
client = { package = "sc-client", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
|
||||||
client-api = { package = "sc-client-api", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
|
client-api = { package = "sc-client-api", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" }
|
||||||
parking_lot = "0.9.0"
|
parking_lot = "0.10.0"
|
||||||
|
codec = { package = "parity-scale-codec", version = "1.1.0" }
|
||||||
ctrlc = { version = "3.1.3", features = ["termination"] }
|
ctrlc = { version = "3.1.3", features = ["termination"] }
|
||||||
futures = "0.3.1"
|
futures = "0.3.1"
|
||||||
exit-future = "0.2.0"
|
exit-future = "0.2.0"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use adder::{HeadData as AdderHead, BlockData as AdderBody};
|
use adder::{HeadData as AdderHead, BlockData as AdderBody};
|
||||||
use sp_core::{Pair, Blake2Hasher};
|
use sp_core::{Pair, Blake2Hasher};
|
||||||
use parachain::codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use primitives::{
|
use primitives::{
|
||||||
Hash, Block,
|
Hash, Block,
|
||||||
parachain::{
|
parachain::{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use crate::{HeadData, BlockData};
|
use crate::{HeadData, BlockData};
|
||||||
use core::{intrinsics, panic};
|
use core::{intrinsics, panic};
|
||||||
use parachain::ValidationResult;
|
use parachain::ValidationResult;
|
||||||
use parachain::codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -38,8 +38,8 @@ pub fn oom(_: core::alloc::Layout) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn validate_block(params: *const u8, len: usize) -> usize {
|
pub extern fn validate_block(params: *const u8, len: usize) -> u64 {
|
||||||
let params = unsafe { parachain::wasm_api::load_params(params, len) };
|
let params = unsafe { parachain::load_params(params, len) };
|
||||||
let parent_head = HeadData::decode(&mut ¶ms.parent_head[..])
|
let parent_head = HeadData::decode(&mut ¶ms.parent_head[..])
|
||||||
.expect("invalid parent head format.");
|
.expect("invalid parent head format.");
|
||||||
|
|
||||||
@@ -55,8 +55,8 @@ pub extern fn validate_block(params: *const u8, len: usize) -> usize {
|
|||||||
);
|
);
|
||||||
|
|
||||||
match crate::execute(parent_hash, parent_head, &block_data, from_messages) {
|
match crate::execute(parent_hash, parent_head, &block_data, from_messages) {
|
||||||
Ok(new_head) => parachain::wasm_api::write_result(
|
Ok(new_head) => parachain::write_result(
|
||||||
ValidationResult { head_data: new_head.encode() }
|
&ValidationResult { head_data: new_head.encode() }
|
||||||
),
|
),
|
||||||
Err(_) => panic!("execution failure"),
|
Err(_) => panic!("execution failure"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ fn main() {
|
|||||||
build_current_project_with_rustflags(
|
build_current_project_with_rustflags(
|
||||||
"wasm_binary.rs",
|
"wasm_binary.rs",
|
||||||
WasmBuilderSource::Crates("1.0.7"),
|
WasmBuilderSource::Crates("1.0.7"),
|
||||||
"-C link-arg=--import-memory",
|
"-C link-arg=--export=__heap_base",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,17 +21,23 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use polkadot_primitives::{BlakeTwo256, Block, Hash, HashT, BlockId, Balance, parachain::{
|
use polkadot_primitives::{
|
||||||
CollatorId, ConsolidatedIngress, StructuredUnroutedIngress, CandidateReceipt, CollationInfo, ParachainHost,
|
BlakeTwo256, Block, Hash, HashT, BlockId, Balance,
|
||||||
Id as ParaId, Collation, TargetedMessage, OutgoingMessages, UpwardMessage, FeeSchedule, ErasureChunk,
|
parachain::{
|
||||||
|
CollatorId, ConsolidatedIngress, StructuredUnroutedIngress, CandidateReceipt, CollationInfo,
|
||||||
|
ParachainHost, Id as ParaId, Collation, OutgoingMessages, FeeSchedule, ErasureChunk,
|
||||||
HeadData, PoVBlock,
|
HeadData, PoVBlock,
|
||||||
}};
|
},
|
||||||
use polkadot_erasure_coding::{self as erasure};
|
};
|
||||||
|
use polkadot_erasure_coding as erasure;
|
||||||
use runtime_primitives::traits::ProvideRuntimeApi;
|
use runtime_primitives::traits::ProvideRuntimeApi;
|
||||||
use parachain::{wasm_executor::{self, ExternalitiesError, ExecutionMode}, MessageRef, UpwardMessageRef};
|
use parachain::{
|
||||||
|
wasm_executor::{self, ExecutionMode}, TargetedMessage, UpwardMessage,
|
||||||
|
};
|
||||||
use trie::TrieConfiguration;
|
use trie::TrieConfiguration;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
/// Encapsulates connections to collators and allows collation on any parachain.
|
/// Encapsulates connections to collators and allows collation on any parachain.
|
||||||
///
|
///
|
||||||
@@ -239,7 +245,7 @@ fn check_egress(
|
|||||||
Ok(OutgoingMessages { outgoing_messages: outgoing })
|
Ok(OutgoingMessages { outgoing_messages: outgoing })
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Externalities {
|
struct ExternalitiesInner {
|
||||||
parachain_index: ParaId,
|
parachain_index: ParaId,
|
||||||
outgoing: Vec<TargetedMessage>,
|
outgoing: Vec<TargetedMessage>,
|
||||||
upward: Vec<UpwardMessage>,
|
upward: Vec<UpwardMessage>,
|
||||||
@@ -248,41 +254,44 @@ struct Externalities {
|
|||||||
fee_schedule: FeeSchedule,
|
fee_schedule: FeeSchedule,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl wasm_executor::Externalities for Externalities {
|
impl wasm_executor::Externalities for ExternalitiesInner {
|
||||||
fn post_message(&mut self, message: MessageRef) -> Result<(), ExternalitiesError> {
|
fn post_message(&mut self, message: TargetedMessage) -> Result<(), String> {
|
||||||
let target: ParaId = message.target.into();
|
if message.target == self.parachain_index {
|
||||||
if target == self.parachain_index {
|
return Err("posted message to self".into())
|
||||||
return Err(ExternalitiesError::CannotPostMessage("posted message to self"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.apply_message_fee(message.data.len())?;
|
self.apply_message_fee(message.data.len())?;
|
||||||
self.outgoing.push(TargetedMessage {
|
self.outgoing.push(message);
|
||||||
target,
|
|
||||||
data: message.data.to_vec(),
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_upward_message(&mut self, message: UpwardMessageRef)
|
fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String> {
|
||||||
-> Result<(), ExternalitiesError>
|
|
||||||
{
|
|
||||||
self.apply_message_fee(message.data.len())?;
|
self.apply_message_fee(message.data.len())?;
|
||||||
|
|
||||||
self.upward.push(UpwardMessage {
|
self.upward.push(message);
|
||||||
origin: message.origin,
|
|
||||||
data: message.data.to_vec(),
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Externalities {
|
impl ExternalitiesInner {
|
||||||
fn apply_message_fee(&mut self, message_len: usize) -> Result<(), ExternalitiesError> {
|
fn new(parachain_index: ParaId, free_balance: Balance, fee_schedule: FeeSchedule) -> Self {
|
||||||
|
Self {
|
||||||
|
parachain_index,
|
||||||
|
free_balance,
|
||||||
|
fee_schedule,
|
||||||
|
fees_charged: 0,
|
||||||
|
upward: Vec::new(),
|
||||||
|
outgoing: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_message_fee(&mut self, message_len: usize) -> Result<(), String> {
|
||||||
let fee = self.fee_schedule.compute_fee(message_len);
|
let fee = self.fee_schedule.compute_fee(message_len);
|
||||||
let new_fees_charged = self.fees_charged.saturating_add(fee);
|
let new_fees_charged = self.fees_charged.saturating_add(fee);
|
||||||
if new_fees_charged > self.free_balance {
|
if new_fees_charged > self.free_balance {
|
||||||
Err(ExternalitiesError::CannotPostMessage("could not cover fee."))
|
Err("could not cover fee.".into())
|
||||||
} else {
|
} else {
|
||||||
self.fees_charged = new_fees_charged;
|
self.fees_charged = new_fees_charged;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -291,7 +300,7 @@ impl Externalities {
|
|||||||
|
|
||||||
// Performs final checks of validity, producing the outgoing message data.
|
// Performs final checks of validity, producing the outgoing message data.
|
||||||
fn final_checks(
|
fn final_checks(
|
||||||
self,
|
&mut self,
|
||||||
upward_messages: &[UpwardMessage],
|
upward_messages: &[UpwardMessage],
|
||||||
egress_queue_roots: &[(ParaId, Hash)],
|
egress_queue_roots: &[(ParaId, Hash)],
|
||||||
fees_charged: Option<Balance>,
|
fees_charged: Option<Balance>,
|
||||||
@@ -313,7 +322,7 @@ impl Externalities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let messages = check_egress(
|
let messages = check_egress(
|
||||||
self.outgoing,
|
std::mem::replace(&mut self.outgoing, Vec::new()),
|
||||||
&egress_queue_roots[..],
|
&egress_queue_roots[..],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -321,6 +330,27 @@ impl Externalities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Externalities(Arc<Mutex<ExternalitiesInner>>);
|
||||||
|
|
||||||
|
impl Externalities {
|
||||||
|
fn new(parachain_index: ParaId, free_balance: Balance, fee_schedule: FeeSchedule) -> Self {
|
||||||
|
Self(Arc::new(Mutex::new(
|
||||||
|
ExternalitiesInner::new(parachain_index, free_balance, fee_schedule)
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl wasm_executor::Externalities for Externalities {
|
||||||
|
fn post_message(&mut self, message: TargetedMessage) -> Result<(), String> {
|
||||||
|
self.0.lock().post_message(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_upward_message(&mut self, message: UpwardMessage) -> Result<(), String> {
|
||||||
|
self.0.lock().post_upward_message(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Validate an erasure chunk against an expected root.
|
/// Validate an erasure chunk against an expected root.
|
||||||
pub fn validate_chunk(
|
pub fn validate_chunk(
|
||||||
root: &Hash,
|
root: &Hash,
|
||||||
@@ -425,19 +455,17 @@ fn do_validation<P>(
|
|||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ext = Externalities {
|
let ext = Externalities::new(para_id.clone(), chain_status.balance, chain_status.fee_schedule);
|
||||||
parachain_index: para_id.clone(),
|
|
||||||
outgoing: Vec::new(),
|
|
||||||
upward: Vec::new(),
|
|
||||||
free_balance: chain_status.balance,
|
|
||||||
fee_schedule: chain_status.fee_schedule,
|
|
||||||
fees_charged: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
match wasm_executor::validate_candidate(&validation_code, params, &mut ext, ExecutionMode::Remote) {
|
match wasm_executor::validate_candidate(
|
||||||
|
&validation_code,
|
||||||
|
params,
|
||||||
|
ext.clone(),
|
||||||
|
ExecutionMode::Remote,
|
||||||
|
) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if result.head_data == head_data.0 {
|
if result.head_data == head_data.0 {
|
||||||
let (messages, fees) = ext.final_checks(
|
let (messages, fees) = ext.0.lock().final_checks(
|
||||||
upward_messages,
|
upward_messages,
|
||||||
queue_roots,
|
queue_roots,
|
||||||
fees_charged
|
fees_charged
|
||||||
@@ -634,7 +662,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ext_rejects_local_message() {
|
fn ext_rejects_local_message() {
|
||||||
let mut ext = Externalities {
|
let mut ext = ExternalitiesInner {
|
||||||
parachain_index: 5.into(),
|
parachain_index: 5.into(),
|
||||||
outgoing: Vec::new(),
|
outgoing: Vec::new(),
|
||||||
upward: Vec::new(),
|
upward: Vec::new(),
|
||||||
@@ -646,13 +674,13 @@ mod tests {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(ext.post_message(MessageRef { target: 1.into(), data: &[] }).is_ok());
|
assert!(ext.post_message(TargetedMessage { target: 1.into(), data: Vec::new() }).is_ok());
|
||||||
assert!(ext.post_message(MessageRef { target: 5.into(), data: &[] }).is_err());
|
assert!(ext.post_message(TargetedMessage { target: 5.into(), data: Vec::new() }).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ext_checks_upward_messages() {
|
fn ext_checks_upward_messages() {
|
||||||
let ext = || Externalities {
|
let ext = || ExternalitiesInner {
|
||||||
parachain_index: 5.into(),
|
parachain_index: 5.into(),
|
||||||
outgoing: Vec::new(),
|
outgoing: Vec::new(),
|
||||||
upward: vec![
|
upward: vec![
|
||||||
@@ -742,7 +770,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ext_checks_fees_and_updates_correctly() {
|
fn ext_checks_fees_and_updates_correctly() {
|
||||||
let mut ext = Externalities {
|
let mut ext = ExternalitiesInner {
|
||||||
parachain_index: 5.into(),
|
parachain_index: 5.into(),
|
||||||
outgoing: Vec::new(),
|
outgoing: Vec::new(),
|
||||||
upward: vec![
|
upward: vec![
|
||||||
@@ -759,15 +787,15 @@ mod tests {
|
|||||||
ext.apply_message_fee(100).unwrap();
|
ext.apply_message_fee(100).unwrap();
|
||||||
assert_eq!(ext.fees_charged, 2000);
|
assert_eq!(ext.fees_charged, 2000);
|
||||||
|
|
||||||
ext.post_message(MessageRef {
|
ext.post_message(TargetedMessage {
|
||||||
target: 1.into(),
|
target: 1.into(),
|
||||||
data: &[0u8; 100],
|
data: vec![0u8; 100],
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
assert_eq!(ext.fees_charged, 4000);
|
assert_eq!(ext.fees_charged, 4000);
|
||||||
|
|
||||||
ext.post_upward_message(UpwardMessageRef {
|
ext.post_upward_message(UpwardMessage {
|
||||||
origin: ParachainDispatchOrigin::Signed,
|
origin: ParachainDispatchOrigin::Signed,
|
||||||
data: &[0u8; 100],
|
data: vec![0u8; 100],
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
assert_eq!(ext.fees_charged, 6000);
|
assert_eq!(ext.fees_charged, 6000);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user