diff --git a/Cargo.lock b/Cargo.lock index b7ca706c5004d..9c3a33de4337a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,9 +133,9 @@ checksum = "a3c5a28f166629752f2e7246b813cdea3243cca59aab2d4264b1fd68392c10eb" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-primitives", + "alloy-primitives 1.1.2", "alloy-rlp", - "alloy-sol-types", + "alloy-sol-types 1.1.2", ] [[package]] @@ -145,9 +145,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18cc14d832bc3331ca22a1c7819de1ede99f58f61a7d123952af7dde8de124a6" dependencies = [ "alloy-json-abi", - "alloy-primitives", + "alloy-primitives 1.1.2", "alloy-sol-type-parser", - "alloy-sol-types", + "alloy-sol-types 1.1.2", "itoa", "serde", "serde_json", @@ -160,12 +160,29 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.1.2", "alloy-sol-type-parser", "serde", "serde_json", ] +[[package]] +name = "alloy-primitives" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 0.99.17", + "hex-literal", + "itoa", + "ruint", + "tiny-keccak", +] + [[package]] name = "alloy-primitives" version = "1.1.2" @@ -204,6 +221,23 @@ dependencies = [ "smol_str", ] +[[package]] +name = "alloy-sol-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a98ad1696a2e17f010ae8e43e9f2a1e930ed176a8e3ff77acfeff6dfb07b42c" +dependencies = [ + "const-hex", + "dunce", + "heck 0.4.1", + "proc-macro-error", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.98", + "syn-solidity 0.4.2", + "tiny-keccak", +] + [[package]] name = "alloy-sol-macro" version = "1.1.2" @@ -213,7 +247,7 @@ dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -229,10 +263,10 @@ dependencies = [ "heck 0.5.0", "indexmap 2.9.0", "proc-macro-error2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", - "syn-solidity", + "syn-solidity 1.1.2", "tiny-keccak", ] @@ -246,10 +280,10 @@ dependencies = [ "dunce", "heck 0.5.0", "macro-string", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", - "syn-solidity", + "syn-solidity 1.1.2", ] [[package]] @@ -262,6 +296,17 @@ dependencies = [ "winnow 0.7.10", ] +[[package]] +name = "alloy-sol-types" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d7107bed88e8f09f0ddcc3335622d87bfb6821f3e0c7473329fb1cfad5e015" +dependencies = [ + "alloy-primitives 0.4.2", + "alloy-sol-macro 0.4.2", + "const-hex", +] + [[package]] name = "alloy-sol-types" version = "1.1.2" @@ -269,8 +314,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387" dependencies = [ "alloy-json-abi", - "alloy-primitives", - "alloy-sol-macro", + "alloy-primitives 1.1.2", + "alloy-sol-macro 1.1.2", "serde", ] @@ -373,7 +418,7 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -684,7 +729,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -697,7 +742,7 @@ checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -812,7 +857,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -823,7 +868,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -974,7 +1019,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "synstructure 0.13.1", @@ -986,7 +1031,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "synstructure 0.13.1", @@ -998,7 +1043,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -1621,7 +1666,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -1638,7 +1683,7 @@ version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -1708,7 +1753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -1832,7 +1877,7 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "rustc-hash 1.1.0", @@ -2088,6 +2133,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32ed0a820ed50891d36358e997d27741a6142e382242df40ff01c89bcdcc7a2b" dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bounded-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee8eddd066a8825ec5570528e6880471210fd5d88cb6abbe1cfdd51ca249c33" +dependencies = [ + "jam-codec", "log", "parity-scale-codec", "scale-info", @@ -3220,7 +3278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -3252,7 +3310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb844bd05be34d91eb67101329aeba9d3337094c04fd8507d821db7ebb488eaf" dependencies = [ "proc-macro-error2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -3426,7 +3484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -3493,7 +3551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a54b9c40054eb8999c5d1d36fdc90e4e5f7ff0d1d9621706f360b3cbc8beb828" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -3505,7 +3563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5437e327e861081c91270becff184859f706e3e50f5301a9d4dc8eb50752c3" dependencies = [ "convert_case 0.6.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -3588,7 +3646,7 @@ version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "unicode-xid 0.2.4", ] @@ -4603,8 +4661,8 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -4673,7 +4731,7 @@ name = "cumulus-pallet-xcmp-queue" version = "0.21.0" dependencies = [ "approx", - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "bp-xcm-bridge-hub-router", "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -5225,7 +5283,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5264,7 +5322,7 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scratch", "syn 2.0.98", @@ -5282,7 +5340,7 @@ version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5305,7 +5363,7 @@ checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "strsim", "syn 2.0.98", @@ -5424,7 +5482,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -5435,7 +5493,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5446,7 +5504,7 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5457,7 +5515,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5469,7 +5527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "rustc_version 0.4.0", "syn 1.0.109", @@ -5499,7 +5557,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "unicode-xid 0.2.4", @@ -5511,7 +5569,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "unicode-xid 0.2.4", @@ -5616,7 +5674,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5660,7 +5718,7 @@ dependencies = [ "common-path", "derive-syn-parse", "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "syn 2.0.98", @@ -5734,7 +5792,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -5830,7 +5888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5927,7 +5985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5947,7 +6005,7 @@ version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5967,7 +6025,7 @@ version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -5978,7 +6036,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -6189,7 +6247,7 @@ dependencies = [ "file-guard", "fs-err", "prettyplease", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -6293,8 +6351,8 @@ checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ "expander", "indexmap 2.9.0", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -6685,8 +6743,8 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "sp-arithmetic 27.0.0", @@ -6934,7 +6992,7 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "proc-macro-warning", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "scale-info", @@ -6950,8 +7008,8 @@ name = "frame-support-procedural-tools" version = "13.0.1" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -6960,7 +7018,7 @@ dependencies = [ name = "frame-support-procedural-tools-derive" version = "12.0.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -7224,7 +7282,7 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -8030,7 +8088,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.5.9", "tokio", "tower-service", "tracing", @@ -8277,7 +8335,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -8429,7 +8487,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -8449,7 +8507,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", ] @@ -8674,6 +8732,34 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jam-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb948eace373d99de60501a02fb17125d30ac632570de20dccc74370cdd611b9" +dependencies = [ + "arrayvec 0.7.6", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "jam-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "jam-codec-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319af585c4c8a6b5552a52b7787a1ab3e4d59df7614190b1f85b9b842488789d" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.98", +] + [[package]] name = "jni" version = "0.19.0" @@ -8849,8 +8935,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -9593,7 +9679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -10013,7 +10099,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -10039,7 +10125,7 @@ dependencies = [ "const-random", "derive-syn-parse", "macro_magic_core_macros", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -10050,7 +10136,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -10363,7 +10449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" dependencies = [ "cfg-if", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -10503,7 +10589,7 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", "synstructure 0.12.6", @@ -10551,7 +10637,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -10965,7 +11051,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -11144,7 +11230,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -11200,8 +11286,8 @@ dependencies = [ "indexmap 2.9.0", "itertools 0.11.0", "petgraph", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -11958,7 +12044,7 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "23.0.3" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -13123,7 +13209,7 @@ dependencies = [ name = "pallet-revive-proc-macro" version = "0.3.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -13666,8 +13752,8 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "12.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "sp-runtime 42.0.0", "syn 2.0.98", @@ -13966,7 +14052,7 @@ dependencies = [ name = "pallet-xcm" version = "20.1.3" dependencies = [ - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "frame-benchmarking", "frame-support", "frame-system", @@ -14177,7 +14263,7 @@ checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" dependencies = [ "bitcoin_hashes 0.13.0", "rand 0.8.5", - "rand_core 0.5.1", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -14231,8 +14317,8 @@ version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -14671,7 +14757,7 @@ checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -14712,7 +14798,7 @@ version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -15888,7 +15974,7 @@ dependencies = [ name = "polkadot-parachain-primitives" version = "17.0.0" dependencies = [ - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "derive_more 0.99.17", "parity-scale-codec", "polkadot-core-primitives", @@ -15904,7 +15990,7 @@ name = "polkadot-primitives" version = "19.0.0" dependencies = [ "bitvec", - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "hex-literal", "log", "parity-scale-codec", @@ -17174,7 +17260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common 0.9.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17186,7 +17272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24fd6c6215450c3e57511df5c38a82eb4bde208de15ee15046ac33852f3c3eaa" dependencies = [ "polkavm-common 0.21.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17198,7 +17284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5a21844afdfcc10c92b9ef288ccb926211af27478d1730fcd55e4aec710179d" dependencies = [ "polkavm-common 0.24.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17427,7 +17513,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "syn 2.0.98", ] @@ -17487,11 +17573,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.21.0", + "toml_edit 0.23.5", ] [[package]] @@ -17501,7 +17587,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", "version_check", @@ -17513,7 +17599,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "version_check", ] @@ -17524,7 +17610,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", ] @@ -17535,7 +17621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ "proc-macro-error-attr2", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17552,7 +17638,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17568,9 +17654,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -17633,7 +17719,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17708,7 +17794,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -17729,7 +17815,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -17742,7 +17828,7 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17754,8 +17840,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.12.1", - "proc-macro2 1.0.95", + "itertools 0.13.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -17947,7 +18033,7 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", ] [[package]] @@ -18185,7 +18271,7 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -18763,7 +18849,7 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "regex", "relative-path", @@ -19308,8 +19394,8 @@ dependencies = [ name = "sc-chain-spec-derive" version = "12.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -19335,6 +19421,7 @@ dependencies = [ "rpassword", "sc-client-api", "sc-client-db", + "sc-executor 0.43.0", "sc-keystore", "sc-mixnet", "sc-network", @@ -19351,6 +19438,8 @@ dependencies = [ "sp-keystore 0.43.0", "sp-panic-handler 13.0.2", "sp-runtime 42.0.0", + "sp-state-machine 0.46.0", + "sp-storage 22.0.0", "sp-tracing 17.1.0", "sp-version 40.0.0", "tempfile", @@ -19808,6 +19897,7 @@ dependencies = [ "array-bytes 6.2.2", "assert_matches", "criterion", + "log", "num_cpus", "parity-scale-codec", "parking_lot 0.12.3", @@ -19857,6 +19947,7 @@ dependencies = [ name = "sc-executor-common" version = "0.39.0" dependencies = [ + "parity-scale-codec", "polkavm 0.24.0", "sc-allocator 32.0.0", "sp-maybe-compressed-blob 11.0.0", @@ -19912,6 +20003,8 @@ version = "0.39.0" dependencies = [ "anyhow", "cargo_metadata", + "cfg-if", + "libc", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -20661,8 +20754,8 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "11.1.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -20801,7 +20894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ed9401effa946b493f9f84dc03714cca98119b230497df6f3df6b84a2b03648" dependencies = [ "darling", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -20813,7 +20906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f4b54a1211260718b92832b661025d1f1a4b6930fbadd6908e00edd265fa5f7" dependencies = [ "darling", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -20855,8 +20948,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "102fbc6236de6c53906c0b262f12c7aa69c2bdc604862c12728f5f4d370bc137" dependencies = [ "darling", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -20868,8 +20961,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78a3993a13b4eafa89350604672c8757b7ea84c7c5947d4b3691e3169c96379b" dependencies = [ "darling", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -20894,8 +20987,8 @@ version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -20916,7 +21009,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc4c70c7fea2eef1740f0081d3fe385d8bee1eef11e9272d3bec7dc8e5438e0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "syn 2.0.98", @@ -20929,7 +21022,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05c61b6b706a3eaad63b506ab50a1d2319f817ae01cf753adcc3f055f9f0fcd6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "syn 2.0.98", @@ -21002,7 +21095,7 @@ version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "serde_derive_internals", "syn 1.0.109", @@ -21259,10 +21352,11 @@ checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ + "serde_core", "serde_derive", ] @@ -21294,13 +21388,22 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -21311,7 +21414,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -21382,7 +21485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -21953,9 +22056,12 @@ name = "snowbridge-inbound-queue-primitives" version = "0.3.0" dependencies = [ "alloy-core", + "alloy-primitives 0.4.2", + "alloy-sol-types 0.4.2", "frame-support", "frame-system", "hex-literal", + "impl-trait-for-tuples", "log", "parity-scale-codec", "scale-info", @@ -22592,8 +22698,8 @@ dependencies = [ "Inflector", "blake2 0.10.6", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -22606,8 +22712,8 @@ dependencies = [ "assert_matches", "blake2 0.10.6", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -23030,11 +23136,10 @@ dependencies = [ name = "sp-core" version = "37.0.0" dependencies = [ - "ark-vrf", "array-bytes 6.2.2", "bitflags 1.3.2", "blake2 0.10.6", - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "bs58", "criterion", "dyn-clonable", @@ -23179,7 +23284,7 @@ dependencies = [ name = "sp-debug-derive" version = "14.0.0" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -23190,7 +23295,7 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -23655,8 +23760,8 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -23667,8 +23772,8 @@ version = "19.0.0" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -24056,7 +24161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aee8f6730641a65fcf0c8f9b1e448af4b3bb083d08058b47528188bccc7b7a7" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -24067,7 +24172,7 @@ version = "15.0.0" dependencies = [ "parity-scale-codec", "proc-macro-warning", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "sp-version 40.0.0", "syn 2.0.98", @@ -24116,7 +24221,7 @@ dependencies = [ name = "sp-weights" version = "32.0.0" dependencies = [ - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "parity-scale-codec", "scale-info", "schemars", @@ -24230,7 +24335,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "sqlx-core", "sqlx-macros-core", @@ -24248,7 +24353,7 @@ dependencies = [ "heck 0.5.0", "hex", "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "serde", "serde_json", @@ -24374,7 +24479,7 @@ checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "serde", "serde_json", @@ -24399,7 +24504,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -24500,7 +24605,7 @@ name = "staging-xcm" version = "17.0.0" dependencies = [ "array-bytes 6.2.2", - "bounded-collections 0.2.3", + "bounded-collections 0.3.2", "derive-where", "environmental", "frame-support", @@ -24598,7 +24703,7 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases 0.1.1", "memchr", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -24656,7 +24761,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "rustversion", "syn 1.0.109", @@ -24669,7 +24774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "rustversion", "syn 2.0.98", @@ -25218,7 +25323,7 @@ checksum = "3cfcfb7d9589f3df0ac87c4988661cf3fb370761fcb19f2fd33104cc59daf22a" dependencies = [ "heck 0.5.0", "parity-scale-codec", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "scale-typegen 0.9.0", @@ -25235,7 +25340,7 @@ checksum = "324c52c09919fec8c22a4b572a466878322e99fe14a9e3d50d6c3700a226ec25" dependencies = [ "heck 0.5.0", "parity-scale-codec", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "scale-info", "scale-typegen 0.11.1", @@ -25611,7 +25716,7 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "unicode-ident", ] @@ -25622,11 +25727,23 @@ version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" +dependencies = [ + "paste", + "proc-macro2 1.0.101", + "quote 1.0.40", + "syn 2.0.98", +] + [[package]] name = "syn-solidity" version = "1.1.2" @@ -25634,7 +25751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e" dependencies = [ "paste", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -25654,7 +25771,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", "unicode-xid 0.2.4", @@ -25666,7 +25783,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -25837,7 +25954,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -25985,7 +26102,7 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 1.0.109", ] @@ -25996,7 +26113,7 @@ version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -26007,7 +26124,7 @@ version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -26179,7 +26296,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -26311,7 +26428,7 @@ checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.8", "toml_edit 0.22.22", ] @@ -26325,24 +26442,22 @@ dependencies = [ ] [[package]] -name = "toml_edit" -version = "0.19.15" +name = "toml_datetime" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "a197c0ec7d131bfc6f7e82c8442ba1595aeab35da7adbf05b6b73cd06a16b6be" dependencies = [ - "indexmap 2.9.0", - "toml_datetime", - "winnow 0.5.15", + "serde_core", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.9.0", - "toml_datetime", + "toml_datetime 0.6.8", "winnow 0.5.15", ] @@ -26355,10 +26470,31 @@ dependencies = [ "indexmap 2.9.0", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.8", "winnow 0.6.18", ] +[[package]] +name = "toml_edit" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ad0b7ae9cfeef5605163839cb9221f453399f15cfb5c10be9885fcf56611f9" +dependencies = [ + "indexmap 2.9.0", + "toml_datetime 0.7.1", + "toml_parser", + "winnow 0.7.10", +] + +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow 0.7.10", +] + [[package]] name = "tower" version = "0.4.13" @@ -26443,7 +26579,7 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -26484,8 +26620,8 @@ version = "5.0.0" dependencies = [ "assert_matches", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.95", + "proc-macro-crate 3.4.0", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -27143,7 +27279,7 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "wasm-bindgen-shared", @@ -27177,7 +27313,7 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "wasm-bindgen-backend", @@ -27936,7 +28072,7 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -27947,7 +28083,7 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -28369,6 +28505,8 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-parachains", "sp-arithmetic 27.0.0", + "sp-consensus-aura", + "sp-consensus-slots", "sp-core 37.0.0", "sp-crypto-hashing 0.1.0", "sp-io 41.0.1", @@ -28409,7 +28547,7 @@ version = "11.0.2" dependencies = [ "Inflector", "frame-support", - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "staging-xcm", "syn 2.0.98", @@ -28658,7 +28796,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "synstructure 0.13.1", @@ -28688,7 +28826,7 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -28699,7 +28837,7 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -28719,7 +28857,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", "synstructure 0.13.1", @@ -28740,7 +28878,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] @@ -28762,7 +28900,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ - "proc-macro2 1.0.95", + "proc-macro2 1.0.101", "quote 1.0.40", "syn 2.0.98", ] diff --git a/Cargo.toml b/Cargo.toml index 5bbccd58af1b5..fc36197050f2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -626,6 +626,10 @@ Inflector = { version = "0.11.4" } aes-gcm = { version = "0.10" } ahash = { version = "0.8.2" } alloy-core = { version = "1.1.0", default-features = false } +# TODO: remove alloy-primitives and alloy-sol-types, they are re-exported in alloy-core +# but the version is different so it doesnt compile +alloy-primitives = { version = "0.4.2", default-features = false } +alloy-sol-types = { version = "0.4.2", default-features = false } always-assert = { version = "0.1" } anyhow = { version = "1.0.81", default-features = false } approx = { version = "0.5.1" } @@ -643,7 +647,6 @@ ark-ed-on-bls12-377-ext = { version = "0.4.1", default-features = false } ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0", default-features = false } ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.4.1", default-features = false } ark-scale = { version = "0.0.12", default-features = false } -ark-vrf = { version = "0.1.0", default-features = false } array-bytes = { version = "6.2.2", default-features = false } arrayvec = { version = "0.7.4" } assert_cmd = { version = "2.0.14" } @@ -671,7 +674,7 @@ blake2 = { version = "0.10.4", default-features = false } blake2b_simd = { version = "1.0.2", default-features = false } blake3 = { version = "1.5" } bn = { package = "substrate-bn", version = "0.6", default-features = false } -bounded-collections = { version = "0.2.3", default-features = false } +bounded-collections = { version = "0.3.2", default-features = false } bounded-vec = { version = "0.7" } bp-asset-hub-rococo = { path = "cumulus/parachains/runtimes/assets/asset-hub-rococo/bridge-primitives", default-features = false } bp-asset-hub-westend = { path = "cumulus/parachains/runtimes/assets/asset-hub-westend/bridge-primitives", default-features = false } @@ -1499,7 +1502,6 @@ overflow-checks = true # # This list is ordered alphabetically. [profile.dev.package] -ark-vrf = { opt-level = 3 } blake2 = { opt-level = 3 } blake2b_simd = { opt-level = 3 } chacha20poly1305 = { opt-level = 3 } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index 6ec613840abf7..ddd080d36933c 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -26,7 +26,7 @@ pub mod weights; #[cfg(any(test, feature = "fuzzing"))] pub mod mock; -#[cfg(test)] +#[cfg(any(test, feature = "fuzzing"))] pub mod mock_electra; #[cfg(test)] diff --git a/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs b/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs index d694436d9cff3..e32047a9433c0 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs @@ -16,12 +16,7 @@ mod benchmarks { fn submit() -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); - let create_message = make_register_token_message(); - - T::Helper::initialize_storage( - create_message.finalized_header, - create_message.block_roots_root, - ); + let create_message = T::Helper::initialize_storage(); let sovereign_account = sibling_sovereign_account::(1000u32.into()); diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 440572958adc1..0613b729b2e69 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -23,8 +23,6 @@ //! parachain. #![cfg_attr(not(feature = "std"), no_std)] -mod envelope; - #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -35,10 +33,11 @@ mod mock; #[cfg(test)] mod test; +pub mod xcm_message_processor; -use codec::{Decode, DecodeAll, Encode}; -use envelope::Envelope; +use codec::{Decode, Encode}; use frame_support::{ + pallet_prelude::DispatchResult, traits::{ fungible::{Inspect, Mutate}, tokens::{Fortitude, Preservation}, @@ -48,7 +47,7 @@ use frame_support::{ }; use frame_system::ensure_signed; use scale_info::TypeInfo; -use sp_core::H160; +use sp_core::{H160, H256}; use sp_runtime::traits::Zero; use sp_std::vec; use xcm::prelude::{ @@ -61,16 +60,20 @@ use snowbridge_core::{ StaticLookup, }; use snowbridge_inbound_queue_primitives::{ - v1::{ConvertMessage, ConvertMessageError, VersionedMessage}, + v1::{ConvertMessage, ConvertMessageError, VersionedXcmMessage}, EventProof, VerificationError, Verifier, }; use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError}; +use snowbridge_inbound_queue_primitives::v1::{Envelope, MessageProcessor}; + pub use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] use snowbridge_beacon_primitives::BeaconHeader; +#[cfg(feature = "runtime-benchmarks")] +use snowbridge_inbound_queue_primitives::EventFixture; type BalanceOf = <::Token as Inspect<::AccountId>>::Balance; @@ -79,20 +82,54 @@ pub use pallet::*; pub const LOG_TARGET: &str = "snowbridge-inbound-queue"; +pub trait RewardProcessor { + fn process_reward(who: T::AccountId, channel: Channel, message: EventProof) -> DispatchResult; +} + +impl RewardProcessor for () { + fn process_reward( + _who: T::AccountId, + _channel: Channel, + _message: EventProof, + ) -> DispatchResult { + Ok(()) + } +} + +pub struct RewardThroughSovereign(sp_std::marker::PhantomData); + +impl RewardProcessor for RewardThroughSovereign { + fn process_reward(who: T::AccountId, channel: Channel, event: EventProof) -> DispatchResult { + let length = event.encode().len() as u32; + let delivery_cost = pallet::Pallet::::calculate_delivery_cost(length); + let sovereign_account: T::AccountId = sibling_sovereign_account::(channel.para_id); + + let amount = T::Token::reducible_balance( + &sovereign_account, + Preservation::Preserve, + Fortitude::Polite, + ) + .min(delivery_cost); + if !amount.is_zero() { + T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; + } + + Ok(()) + } +} #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use sp_core::H256; #[pallet::pallet] pub struct Pallet(_); #[cfg(feature = "runtime-benchmarks")] pub trait BenchmarkHelper { - fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256); + fn initialize_storage() -> EventFixture; } #[pallet::config] @@ -141,6 +178,12 @@ pub mod pallet { /// To withdraw and deposit an asset. type AssetTransactor: TransactAsset; + + /// Process the message that was submitted + type MessageProcessor: MessageProcessor; + + /// Process the reward to the relayer + type RewardProcessor: RewardProcessor; } #[pallet::hooks] @@ -265,48 +308,8 @@ pub mod pallet { } })?; - // Reward relayer from the sovereign account of the destination parachain, only if funds - // are available - let sovereign_account = sibling_sovereign_account::(channel.para_id); - let delivery_cost = Self::calculate_delivery_cost(event.encode().len() as u32); - let amount = T::Token::reducible_balance( - &sovereign_account, - Preservation::Preserve, - Fortitude::Polite, - ) - .min(delivery_cost); - if !amount.is_zero() { - T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; - } - - // Decode payload into `VersionedMessage` - let message = VersionedMessage::decode_all(&mut envelope.payload.as_ref()) - .map_err(|_| Error::::InvalidPayload)?; - - // Decode message into XCM - let (xcm, fee) = Self::do_convert(envelope.message_id, message.clone())?; - - log::info!( - target: LOG_TARGET, - "💫 xcm decoded as {:?} with fee {:?}", - xcm, - fee - ); - - // Burning fees for teleport - Self::burn_fees(channel.para_id, fee)?; - - // Attempt to send XCM to a dest parachain - let message_id = Self::send_xcm(xcm, channel.para_id)?; - - Self::deposit_event(Event::MessageReceived { - channel_id: envelope.channel_id, - nonce: envelope.nonce, - message_id, - fee_burned: fee, - }); - - Ok(()) + T::RewardProcessor::process_reward(who, channel.clone(), event)?; + T::MessageProcessor::process_message(channel, envelope) } /// Halt or resume all pallet operations. May only be called by root. @@ -326,7 +329,7 @@ pub mod pallet { impl Pallet { pub fn do_convert( message_id: H256, - message: VersionedMessage, + message: VersionedXcmMessage, ) -> Result<(Xcm<()>, BalanceOf), Error> { let (xcm, fee) = T::MessageConverter::convert(message_id, message) .map_err(|e| Error::::ConvertMessage(e))?; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 4a81e4243c12d..970e42f77acbf 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -2,7 +2,19 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; -use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::IdentityFee}; +use crate::{ + xcm_message_processor::XcmMessageProcessor, + {self as inbound_queue}, +}; +use frame_support::{ + derive_impl, parameter_types, + storage::Key, + traits::{ + tokens::{Fortitude, Preservation}, + ConstU32, + }, + weights::IdentityFee, +}; use hex_literal::hex; use snowbridge_beacon_primitives::{ types::deneb, BeaconHeader, ExecutionProof, Fork, ForkVersions, VersionedExecutionPayloadHeader, @@ -11,10 +23,11 @@ use snowbridge_core::{ gwei, meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, TokenId, }; use snowbridge_inbound_queue_primitives::{v1::MessageToXcm, Log, Proof, VerificationError}; -use sp_core::{H160, H256}; +use sp_core::{Get, H160, H256}; +use sp_keyring::AccountKeyring as Keyring; use sp_runtime::{ - traits::{IdentifyAccount, IdentityLookup, MaybeConvert, Verify}, - BuildStorage, FixedU128, MultiSignature, + traits::{IdentifyAccount, IdentityLookup, MaybeConvert, MaybeEquivalence, Verify, Zero}, + BuildStorage, DispatchError, FixedU128, MultiSignature, }; use sp_std::{convert::From, default::Default}; use xcm::{ @@ -23,8 +36,6 @@ use xcm::{ }; use xcm_executor::AssetsInHolding; -use crate::{self as inbound_queue}; - type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( @@ -220,6 +231,30 @@ impl MaybeConvert for MockTokenIdConvert { } } +pub struct DummyPrefix; + +impl MessageProcessor for DummyPrefix { + fn can_process_message(_channel: &Channel, _envelope: &Envelope) -> bool { + false + } + + fn process_message(_channel: Channel, _envelope: Envelope) -> Result<(), DispatchError> { + panic!("DummyPrefix::process_message shouldn't be called"); + } +} + +pub struct DummySuffix; + +impl MessageProcessor for DummySuffix { + fn can_process_message(_channel: &Channel, _envelope: &Envelope) -> bool { + true + } + + fn process_message(_channel: Channel, _envelope: Envelope) -> Result<(), DispatchError> { + panic!("DummySuffix::process_message shouldn't be called"); + } +} + impl inbound_queue::Config for Test { type RuntimeEvent = RuntimeEvent; type Verifier = MockVerifier; @@ -245,6 +280,9 @@ impl inbound_queue::Config for Test { type LengthToFee = IdentityFee; type MaxMessageSize = ConstU32<1024>; type AssetTransactor = SuccessfulTransactor; + type MessageProcessor = (DummyPrefix, XcmMessageProcessor, DummySuffix); // We are passively testing if implementation of MessageProcessor trait works correctly for + // tuple + type RewardProcessor = RewardThroughSovereign; } pub fn setup() { diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 60065ccb15b24..ef4ae7261bbc4 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -22,8 +22,8 @@ fn test_submit_happy_path() { let origin = RuntimeOrigin::signed(relayer.clone()); - // Submit event proof - let event = EventProof { + // Submit message + let message = Message { event_log: mock_event_log(), proof: Proof { receipt_proof: Default::default(), @@ -72,8 +72,8 @@ fn test_submit_xcm_invalid_channel() { println!("account: {}", sovereign_account); let _ = Balances::mint_into(&sovereign_account, 10000); - // Submit event proof - let event = EventProof { + // Submit message + let message = Message { event_log: mock_event_log_invalid_channel(), proof: Proof { receipt_proof: Default::default(), @@ -97,8 +97,8 @@ fn test_submit_with_invalid_gateway() { let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); let _ = Balances::mint_into(&sovereign_account, 10000); - // Submit event proof - let event = EventProof { + // Submit message + let message = Message { event_log: mock_event_log_invalid_gateway(), proof: Proof { receipt_proof: Default::default(), @@ -237,7 +237,7 @@ fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { execution_proof: mock_execution_proof(), }, }; - assert_ok!(InboundQueue::submit(origin.clone(), event.clone())); + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); // Check balance of sovereign account as ED does not change let amount = Balances::balance(&sovereign_account); assert_eq!(amount, ExistentialDeposit::get()); diff --git a/bridges/snowbridge/pallets/inbound-queue/src/xcm_message_processor.rs b/bridges/snowbridge/pallets/inbound-queue/src/xcm_message_processor.rs new file mode 100644 index 0000000000000..17519f66be6ec --- /dev/null +++ b/bridges/snowbridge/pallets/inbound-queue/src/xcm_message_processor.rs @@ -0,0 +1,47 @@ +use crate::{Error, Event, LOG_TARGET}; +use codec::DecodeAll; +use core::marker::PhantomData; +use snowbridge_core::Channel; +use snowbridge_inbound_queue_primitives::v1::{Envelope, MessageProcessor, VersionedXcmMessage}; +use sp_runtime::DispatchError; + +pub struct XcmMessageProcessor(PhantomData); + +impl MessageProcessor for XcmMessageProcessor +where + T: crate::Config, +{ + fn can_process_message(_channel: &Channel, envelope: &Envelope) -> bool { + VersionedXcmMessage::decode_all(&mut envelope.payload.as_ref()).is_ok() + } + + fn process_message(channel: Channel, envelope: Envelope) -> Result<(), DispatchError> { + // Decode message into XCM + let (xcm, fee) = match VersionedXcmMessage::decode_all(&mut envelope.payload.as_ref()) { + Ok(message) => crate::Pallet::::do_convert(envelope.message_id, message)?, + Err(_) => return Err(Error::::InvalidPayload.into()), + }; + + log::info!( + target: LOG_TARGET, + "💫 xcm decoded as {:?} with fee {:?}", + xcm, + fee + ); + + // Burning fees for teleport + crate::Pallet::::burn_fees(channel.para_id, fee)?; + + // Attempt to send XCM to a dest parachain + let message_id = crate::Pallet::::send_xcm(xcm, channel.para_id)?; + + crate::Pallet::::deposit_event(Event::MessageReceived { + channel_id: envelope.channel_id, + nonce: envelope.nonce, + message_id, + fee_burned: fee, + }); + + Ok(()) + } +} diff --git a/bridges/snowbridge/pallets/outbound-queue/src/benchmarking.rs b/bridges/snowbridge/pallets/outbound-queue/src/benchmarking.rs index 1ff8df5793581..c3d0347438af0 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/benchmarking.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/benchmarking.rs @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; -use bridge_hub_common::AggregateMessageOrigin; use codec::Encode; use frame_benchmarking::v2::*; use snowbridge_core::ChannelId; @@ -34,7 +33,7 @@ mod benchmarks { }), }, }; - let origin = AggregateMessageOrigin::Snowbridge([1; 32].into()); + let origin = T::GetAggregateMessageOrigin::convert([1; 32].into()); let encoded_enqueued_message = enqueued_message.encode(); #[block] diff --git a/bridges/snowbridge/pallets/outbound-queue/src/lib.rs b/bridges/snowbridge/pallets/outbound-queue/src/lib.rs index aeae2cd3f245b..746b273b3127f 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/lib.rs @@ -103,8 +103,8 @@ mod mock; #[cfg(test)] mod test; -use bridge_hub_common::{AggregateMessageOrigin, CustomDigestItem}; -use codec::Decode; +use bridge_hub_common::CustomDigestItem; +use codec::{Decode, FullCodec}; use frame_support::{ storage::StorageStreamIter, traits::{tokens::Balance, Contains, Defensive, EnqueueMessage, Get, ProcessMessageError}, @@ -117,11 +117,11 @@ use snowbridge_outbound_queue_primitives::v1::{ }; use sp_core::{H256, U256}; use sp_runtime::{ - traits::{CheckedDiv, Hash}, + traits::{CheckedDiv, Convert, Debug, Hash}, DigestItem, Saturating, }; use sp_std::prelude::*; -pub use types::{CommittedMessage, ProcessMessageOriginOf}; +pub use types::{CommittedMessage, OnNewCommitment, ProcessMessageOriginOf}; pub use weights::WeightInfo; pub use pallet::*; @@ -144,7 +144,15 @@ pub mod pallet { type Hashing: Hash; - type MessageQueue: EnqueueMessage; + type AggregateMessageOrigin: FullCodec + + MaxEncodedLen + + Clone + + Eq + + PartialEq + + TypeInfo + + Debug; + type GetAggregateMessageOrigin: Convert; + type MessageQueue: EnqueueMessage; /// Measures the maximum gas used to execute a command on Ethereum type GasMeter: GasMeter; @@ -168,6 +176,8 @@ pub mod pallet { type PricingParameters: Get>; + type OnNewCommitment: OnNewCommitment; + /// Convert a weight value into a deductible fee based. type WeightToFee: WeightToFee; @@ -176,7 +186,7 @@ pub mod pallet { } #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[pallet::generate_deposit(pub fn deposit_event)] pub enum Event { /// Message has been queued and will be processed in the future MessageQueued { @@ -220,7 +230,7 @@ pub mod pallet { /// Inspired by the `frame_system::Pallet::Events` storage value #[pallet::storage] #[pallet::unbounded] - pub(super) type Messages = StorageValue<_, Vec, ValueQuery>; + pub type Messages = StorageValue<_, Vec, ValueQuery>; /// Hashes of the ABI-encoded messages in the [`Messages`] storage value. Used to generate a /// merkle root during `on_finalize`. This storage value is killed in @@ -228,7 +238,7 @@ pub mod pallet { #[pallet::storage] #[pallet::unbounded] #[pallet::getter(fn message_leaves)] - pub(super) type MessageLeaves = StorageValue<_, Vec, ValueQuery>; + pub type MessageLeaves = StorageValue<_, Vec, ValueQuery>; /// The current nonce for each message origin #[pallet::storage] @@ -289,6 +299,8 @@ pub mod pallet { // Create merkle root of messages let root = merkle_root::<::Hashing, _>(MessageLeaves::::stream_iter()); + T::OnNewCommitment::on_new_commitment(root); + let digest_item: DigestItem = CustomDigestItem::Snowbridge(root).into(); // Insert merkle root into the header digest diff --git a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index 236cca7d83817..93dca69018f1c 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -92,6 +92,7 @@ impl crate::Config for Test { type PricingParameters = Parameters; type Channels = Everything; type WeightToFee = IdentityFee; + type OnNewCommitment = (); type WeightInfo = (); } diff --git a/bridges/snowbridge/pallets/outbound-queue/src/process_message_impl.rs b/bridges/snowbridge/pallets/outbound-queue/src/process_message_impl.rs index 731aa6fa6d5ca..b9f4032d3de30 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/process_message_impl.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/process_message_impl.rs @@ -9,7 +9,7 @@ use frame_support::{ }; impl ProcessMessage for Pallet { - type Origin = AggregateMessageOrigin; + type Origin = T::AggregateMessageOrigin; fn process_message( message: &[u8], origin: Self::Origin, diff --git a/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs b/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs index 6d13703d864eb..f799aeec7d430 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/send_message_impl.rs @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: 2023 Snowfork //! Implementation for [`snowbridge_outbound_queue_primitives::v1::SendMessage`] use super::*; -use bridge_hub_common::AggregateMessageOrigin; use codec::Encode; use frame_support::{ ensure, @@ -19,8 +18,9 @@ use sp_core::H256; use sp_runtime::BoundedVec; /// The maximal length of an enqueued message, as determined by the MessageQueue pallet -pub type MaxEnqueuedMessageSizeOf = - <::MessageQueue as EnqueueMessage>::MaxMessageLen; +pub type MaxEnqueuedMessageSizeOf = <::MessageQueue as EnqueueMessage< + ::AggregateMessageOrigin, +>>::MaxMessageLen; #[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound)] pub struct Ticket @@ -74,7 +74,7 @@ where } fn deliver(ticket: Self::Ticket) -> Result { - let origin = AggregateMessageOrigin::Snowbridge(ticket.channel_id); + let origin = T::GetAggregateMessageOrigin::convert(ticket.channel_id); if ticket.channel_id != PRIMARY_GOVERNANCE_CHANNEL { ensure!(!Self::operating_mode().is_halted(), SendError::Halted); diff --git a/bridges/snowbridge/pallets/outbound-queue/src/types.rs b/bridges/snowbridge/pallets/outbound-queue/src/types.rs index 76d32fab462a4..181894499243d 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/types.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/types.rs @@ -55,3 +55,12 @@ impl From for Token { ]) } } + +/// Hook that will be called when new message commitment is constructed +pub trait OnNewCommitment { + fn on_new_commitment(commitment: H256); +} + +impl OnNewCommitment for () { + fn on_new_commitment(_commitment: H256) {} +} diff --git a/bridges/snowbridge/pallets/system/src/benchmarking.rs b/bridges/snowbridge/pallets/system/src/benchmarking.rs index cba1483a193cd..80910e5f3f245 100644 --- a/bridges/snowbridge/pallets/system/src/benchmarking.rs +++ b/bridges/snowbridge/pallets/system/src/benchmarking.rs @@ -7,11 +7,19 @@ use super::*; use crate::Pallet as SnowbridgeControl; use frame_benchmarking::v2::*; use frame_system::RawOrigin; -use snowbridge_core::eth; +use snowbridge_core::{eth, sibling_sovereign_account}; use snowbridge_outbound_queue_primitives::OperatingMode; use sp_runtime::SaturatedConversion; use xcm::prelude::*; +#[allow(clippy::result_large_err)] +fn fund_sovereign_account(para_id: ParaId) -> Result<(), BenchmarkError> { + let amount: BalanceOf = (10_000_000_000_000_u64).saturated_into::().saturated_into(); + let sovereign_account = sibling_sovereign_account::(para_id); + T::Token::mint_into(&sovereign_account, amount)?; + Ok(()) +} + #[benchmarks] mod benchmarks { use super::*; @@ -53,6 +61,43 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn force_update_channel() -> Result<(), BenchmarkError> { + let origin_para_id = 2000; + let origin_location = Location::new(1, [Parachain(origin_para_id)]); + let origin = T::Helper::make_xcm_origin(origin_location.clone()); + let channel_id: ChannelId = ParaId::from(origin_para_id).into(); + + fund_sovereign_account::(origin_para_id.into())?; + let (para_id, agent_id) = ensure_sibling::(&origin_location)?; + Agents::::insert(agent_id, ()); + let channel_id: ChannelId = para_id.into(); + let channel = Channel { agent_id, para_id }; + Channels::::insert(channel_id, channel); + + #[extrinsic_call] + _(RawOrigin::Root, channel_id, OperatingMode::RejectingOutboundMessages); + + Ok(()) + } + + #[benchmark] + fn force_transfer_native_from_agent() -> Result<(), BenchmarkError> { + let origin_para_id = 2000; + let origin_location = Location::new(1, [Parachain(origin_para_id)]); + let origin = T::Helper::make_xcm_origin(origin_location.clone()); + fund_sovereign_account::(origin_para_id.into())?; + let (para_id, agent_id) = ensure_sibling::(&origin_location)?; + Agents::::insert(agent_id, ()); + + let versioned_location: VersionedLocation = origin_location.into(); + + #[extrinsic_call] + _(RawOrigin::Root, Box::new(versioned_location), H160::default(), 1); + + Ok(()) + } + #[benchmark] fn set_token_transfer_fees() -> Result<(), BenchmarkError> { #[extrinsic_call] diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs index d277186bd5b9d..ece0c7a5f0874 100644 --- a/bridges/snowbridge/pallets/system/src/lib.rs +++ b/bridges/snowbridge/pallets/system/src/lib.rs @@ -52,7 +52,10 @@ use snowbridge_outbound_queue_primitives::{ }; use sp_core::{RuntimeDebug, H160, H256}; use sp_io::hashing::blake2_256; -use sp_runtime::{traits::MaybeConvert, DispatchError, SaturatedConversion}; +use sp_runtime::{ + traits::{BadOrigin, MaybeConvert}, + DispatchError, SaturatedConversion, +}; use sp_std::prelude::*; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -67,6 +70,20 @@ pub type BalanceOf = pub type AccountIdOf = ::AccountId; pub type PricingParametersOf = PricingParametersRecord>; +/// Ensure origin location is a sibling +fn ensure_sibling(location: &Location) -> Result<(ParaId, H256), DispatchError> +where + T: Config, +{ + match location.unpack() { + (1, [Parachain(para_id)]) => { + let agent_id = agent_id_of::(location)?; + Ok(((*para_id).into(), agent_id)) + }, + _ => Err(BadOrigin.into()), + } +} + /// Hash the location to produce an agent id pub fn agent_id_of(location: &Location) -> Result { T::AgentIdOf::convert_location(location).ok_or(Error::::LocationConversionFailed.into()) @@ -333,6 +350,69 @@ pub mod pallet { Ok(()) } + /// Sends a message to the Gateway contract to update an arbitrary channel + /// + /// Fee required: No + /// + /// - `origin`: Must be root + /// - `channel_id`: ID of channel + /// - `mode`: Initial operating mode of the channel + /// - `outbound_fee`: Fee charged to users for sending outbound messages to Polkadot + #[pallet::call_index(6)] + #[pallet::weight(T::WeightInfo::force_update_channel())] + pub fn force_update_channel( + origin: OriginFor, + channel_id: ChannelId, + mode: OperatingMode, + ) -> DispatchResult { + ensure_root(origin)?; + + ensure!(Channels::::contains_key(channel_id), Error::::NoChannel); + + let command = Command::UpdateChannel { channel_id, mode }; + Self::send(PRIMARY_GOVERNANCE_CHANNEL, command, PaysFee::::No)?; + + Self::deposit_event(Event::::UpdateChannel { channel_id, mode }); + Ok(()) + } + + /// Sends a message to the Gateway contract to transfer ether from an agent to `recipient`. + /// + /// Privileged. Can only be called by root. + /// + /// Fee required: No + /// + /// - `origin`: Must be root + /// - `location`: Location used to resolve the agent + /// - `recipient`: Recipient of funds + /// - `amount`: Amount to transfer + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::force_transfer_native_from_agent())] + pub fn force_transfer_native_from_agent( + origin: OriginFor, + location: Box, + recipient: H160, + amount: u128, + ) -> DispatchResult { + ensure_root(origin)?; + + // Ensure that location is some consensus system on a sibling parachain + let location: Location = + (*location).try_into().map_err(|_| Error::::UnsupportedLocationVersion)?; + let (_, agent_id) = + ensure_sibling::(&location).map_err(|_| Error::::InvalidLocation)?; + + let pays_fee = PaysFee::::No; + + Self::do_transfer_native_from_agent( + agent_id, + PRIMARY_GOVERNANCE_CHANNEL, + recipient, + amount, + pays_fee, + ) + } + /// Sends a message to the Gateway contract to update fee related parameters for /// token transfers. /// @@ -433,6 +513,28 @@ pub mod pallet { Ok(()) } + /// Issue a `Command::TransferNativeFromAgent` command. The command will be sent on the + /// channel `channel_id` + pub fn do_transfer_native_from_agent( + agent_id: H256, + channel_id: ChannelId, + recipient: H160, + amount: u128, + pays_fee: PaysFee, + ) -> DispatchResult { + ensure!(Agents::::contains_key(agent_id), Error::::NoAgent); + + let command = Command::TransferNativeFromAgent { agent_id, recipient, amount }; + Self::send(channel_id, command, pays_fee)?; + + Self::deposit_event(Event::::TransferNativeFromAgent { + agent_id, + recipient, + amount, + }); + Ok(()) + } + /// Initializes agents and channels. pub fn initialize(para_id: ParaId, asset_hub_para_id: ParaId) -> Result<(), DispatchError> { // Asset Hub diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs index 311981a873b01..54f7e680597ad 100644 --- a/bridges/snowbridge/pallets/system/src/mock.rs +++ b/bridges/snowbridge/pallets/system/src/mock.rs @@ -171,6 +171,7 @@ impl snowbridge_pallet_outbound_queue::Config for Test { type PricingParameters = EthereumSystem; type Channels = EthereumSystem; type WeightToFee = IdentityFee; + type OnNewCommitment = (); type WeightInfo = (); } diff --git a/bridges/snowbridge/pallets/system/src/weights.rs b/bridges/snowbridge/pallets/system/src/weights.rs index 7b2513775601e..6d56a6a71cda9 100644 --- a/bridges/snowbridge/pallets/system/src/weights.rs +++ b/bridges/snowbridge/pallets/system/src/weights.rs @@ -37,6 +37,8 @@ pub trait WeightInfo { fn set_token_transfer_fees() -> Weight; fn set_pricing_parameters() -> Weight; fn register_token() -> Weight; + fn force_update_channel() -> Weight; + fn force_transfer_native_from_agent() -> Weight; } // For backwards compatibility and tests. @@ -60,6 +62,25 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } + /// Storage: EthereumSystem Channels (r:1 w:0) + /// Proof: EthereumSystem Channels (max_values: None, max_size: Some(12), added: 2487, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_update_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(41_000_000, 6044) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } /// Storage: ParachainInfo ParachainId (r:1 w:0) /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) @@ -79,6 +100,25 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } + /// Storage: EthereumSystem Agents (r:1 w:0) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_transfer_native_from_agent() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `6044` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(42_000_000, 6044) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } /// Storage: ParachainInfo ParachainId (r:1 w:0) /// Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) diff --git a/bridges/snowbridge/primitives/inbound-queue/Cargo.toml b/bridges/snowbridge/primitives/inbound-queue/Cargo.toml index 3e36331435f79..7d5282011edba 100644 --- a/bridges/snowbridge/primitives/inbound-queue/Cargo.toml +++ b/bridges/snowbridge/primitives/inbound-queue/Cargo.toml @@ -15,12 +15,15 @@ workspace = true exclude-from-umbrella = true [dependencies] +alloy-primitives = { features = ["rlp"], workspace = true } +alloy-sol-types = { workspace = true } alloy-core = { workspace = true, features = ["sol-types"] } codec = { workspace = true } frame-support.workspace = true frame-system.workspace = true log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +impl-trait-for-tuples = { workspace = true } snowbridge-beacon-primitives.workspace = true snowbridge-core.workspace = true snowbridge-verification-primitives.workspace = true diff --git a/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs b/bridges/snowbridge/primitives/inbound-queue/src/envelope.rs similarity index 91% rename from bridges/snowbridge/pallets/inbound-queue/src/envelope.rs rename to bridges/snowbridge/primitives/inbound-queue/src/envelope.rs index 2ba779b410709..ad778ea1749fc 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs +++ b/bridges/snowbridge/primitives/inbound-queue/src/envelope.rs @@ -1,12 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use snowbridge_core::ChannelId; -use snowbridge_inbound_queue_primitives::Log; +use snowbridge_verification_primitives::Log; use sp_core::{RuntimeDebug, H160, H256}; use sp_std::prelude::*; -use alloy_core::{primitives::B256, sol, sol_types::SolEvent}; +use alloy_primitives::B256; +use alloy_sol_types::{sol, SolEvent}; sol! { event OutboundMessageAccepted(bytes32 indexed channel_id, uint64 nonce, bytes32 indexed message_id, bytes payload); @@ -44,7 +45,7 @@ impl TryFrom<&Log> for Envelope { channel_id: ChannelId::from(event.channel_id.as_ref()), nonce: event.nonce, message_id: H256::from(event.message_id.as_ref()), - payload: event.payload.into(), + payload: event.payload, }) } } diff --git a/bridges/snowbridge/primitives/inbound-queue/src/v1.rs b/bridges/snowbridge/primitives/inbound-queue/src/v1.rs index 6eba682f72f74..b58eb0d0a82a0 100644 --- a/bridges/snowbridge/primitives/inbound-queue/src/v1.rs +++ b/bridges/snowbridge/primitives/inbound-queue/src/v1.rs @@ -3,13 +3,16 @@ //! Converts messages from Ethereum to XCM messages use crate::{CallIndex, EthereumLocationsConverterFor}; +use alloy_primitives::B256; +use alloy_sol_types::{sol, SolEvent}; use codec::{Decode, DecodeWithMemTracking, Encode}; use core::marker::PhantomData; use frame_support::{traits::tokens::Balance as BalanceT, PalletError}; use scale_info::TypeInfo; -use snowbridge_core::TokenId; +use snowbridge_core::{Channel, ChannelId, TokenId}; +use snowbridge_verification_primitives::Log; use sp_core::{Get, RuntimeDebug, H160, H256}; -use sp_runtime::{traits::MaybeConvert, MultiAddress}; +use sp_runtime::{traits::MaybeConvert, DispatchError, MultiAddress}; use sp_std::prelude::*; use xcm::prelude::{Junction::AccountKey20, *}; @@ -19,7 +22,7 @@ const MINIMUM_DEPOSIT: u128 = 1; /// we may want to evolve the protocol so that the ethereum side sends XCM messages directly. /// Instead having BridgeHub transcode the messages into XCM. #[derive(Clone, Encode, Decode, RuntimeDebug)] -pub enum VersionedMessage { +pub enum VersionedXcmMessage { V1(MessageV1), } @@ -141,7 +144,7 @@ pub trait ConvertMessage { /// Converts a versioned message into an XCM message and an optional topicID fn convert( message_id: H256, - message: VersionedMessage, + message: VersionedXcmMessage, ) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError>; } @@ -180,10 +183,10 @@ where fn convert( message_id: H256, - message: VersionedMessage, + message: VersionedXcmMessage, ) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError> { use Command::*; - use VersionedMessage::*; + use VersionedXcmMessage::*; match message { V1(MessageV1 { chain_id, command: RegisterToken { token, fee } }) => Ok(Self::convert_register_token(message_id, chain_id, token, fee)), @@ -456,6 +459,47 @@ where } } +sol! { + event OutboundMessageAccepted(bytes32 indexed channel_id, uint64 nonce, bytes32 indexed message_id, bytes payload); +} + +/// An inbound message that has had its outer envelope decoded. +#[derive(Clone, RuntimeDebug)] +pub struct Envelope { + /// The address of the outbound queue on Ethereum that emitted this message as an event log + pub gateway: H160, + /// The message Channel + pub channel_id: ChannelId, + /// A nonce for enforcing replay protection and ordering. + pub nonce: u64, + /// An id for tracing the message on its route (has no role in bridge consensus) + pub message_id: H256, + /// The inner payload generated from the source application. + pub payload: Vec, +} + +#[derive(Copy, Clone, RuntimeDebug)] +pub struct EnvelopeDecodeError; + +impl TryFrom<&Log> for Envelope { + type Error = EnvelopeDecodeError; + + fn try_from(log: &Log) -> Result { + let topics: Vec = log.topics.iter().map(|x| B256::from_slice(x.as_ref())).collect(); + + let event = OutboundMessageAccepted::decode_log(topics, &log.data, true) + .map_err(|_| EnvelopeDecodeError)?; + + Ok(Self { + gateway: log.address, + channel_id: ChannelId::from(event.channel_id.as_ref()), + nonce: event.nonce, + message_id: H256::from(event.message_id.as_ref()), + payload: event.payload, + }) + } +} + #[cfg(test)] mod tests { use crate::{ @@ -671,3 +715,38 @@ mod tests { assert_eq!(actual_assets, Some(expected_assets)) } } +pub trait MessageProcessor { + /// Lightweight function to check if this processor can handle the message + fn can_process_message(channel: &Channel, envelope: &Envelope) -> bool; + /// Process the message + fn process_message(channel: Channel, envelope: Envelope) -> Result<(), DispatchError>; +} + +#[impl_trait_for_tuples::impl_for_tuples(10)] +impl MessageProcessor for Tuple { + fn can_process_message(channel: &Channel, envelope: &Envelope) -> bool { + for_tuples!( #( + match Tuple::can_process_message(&channel, &envelope) { + true => { + return true; + }, + _ => {} + } + )* ); + + false + } + + fn process_message(channel: Channel, envelope: Envelope) -> Result<(), DispatchError> { + for_tuples!( #( + match Tuple::can_process_message(&channel, &envelope) { + true => { + return Tuple::process_message(channel, envelope) + }, + _ => {} + } + )* ); + + Err(DispatchError::Other("No handler for message found")) + } +} diff --git a/bridges/snowbridge/primitives/outbound-queue/src/v1/message.rs b/bridges/snowbridge/primitives/outbound-queue/src/v1/message.rs index c5a1ebb391072..fcc7cf8d5b8b3 100644 --- a/bridges/snowbridge/primitives/outbound-queue/src/v1/message.rs +++ b/bridges/snowbridge/primitives/outbound-queue/src/v1/message.rs @@ -6,7 +6,7 @@ use crate::{OperatingMode, SendError, SendMessageFeeProvider}; use codec::{Decode, DecodeWithMemTracking, Encode}; use ethabi::Token; use scale_info::TypeInfo; -use snowbridge_core::{pricing::UD60x18, ChannelId}; +use snowbridge_core::{pricing::UD60x18, AgentId, ChannelId}; use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; use sp_core::{RuntimeDebug, H160, H256, U256}; use sp_std::{borrow::ToOwned, vec, vec::Vec}; @@ -74,11 +74,15 @@ pub enum Command { /// Optionally invoke an initializer in the implementation contract initializer: Option, }, + /// An UpdateChannel message was sent to the Gateway + UpdateChannel { channel_id: ChannelId, mode: OperatingMode }, /// Set the global operating mode of the Gateway contract SetOperatingMode { /// The new operating mode mode: OperatingMode, }, + /// An TransferNativeFromAgent message was sent to the Gateway + TransferNativeFromAgent { agent_id: AgentId, recipient: H160, amount: u128 }, /// Set token fees of the Gateway contract SetTokenTransferFees { /// The fee(DOT) for the cost of creating asset on AssetHub @@ -136,7 +140,9 @@ impl Command { match self { Command::AgentExecute { .. } => 0, Command::Upgrade { .. } => 1, + Command::UpdateChannel { .. } => 4, Command::SetOperatingMode { .. } => 5, + Command::TransferNativeFromAgent { .. } => 6, Command::SetTokenTransferFees { .. } => 7, Command::SetPricingParameters { .. } => 8, Command::UnlockNativeToken { .. } => 9, @@ -158,8 +164,18 @@ impl Command { Token::FixedBytes(impl_code_hash.as_bytes().to_owned()), initializer.clone().map_or(Token::Bytes(vec![]), |i| Token::Bytes(i.params)), ])]), + Command::UpdateChannel { channel_id, mode } => ethabi::encode(&[Token::Tuple(vec![ + Token::FixedBytes(channel_id.as_ref().to_owned()), + Token::Uint(U256::from((*mode) as u64)), + ])]), Command::SetOperatingMode { mode } => ethabi::encode(&[Token::Tuple(vec![Token::Uint(U256::from((*mode) as u64))])]), + Command::TransferNativeFromAgent { agent_id, recipient, amount } => + ethabi::encode(&[Token::Tuple(vec![ + Token::FixedBytes(agent_id.as_bytes().to_owned()), + Token::Address(*recipient), + Token::Uint(U256::from(*amount)), + ])]), Command::SetTokenTransferFees { create_asset_xcm, transfer_asset_xcm, @@ -360,6 +376,8 @@ impl GasMeter for ConstantGasMeter { // the the initializer is called. 50_000 + initializer_max_gas }, + Command::UpdateChannel { .. } => 50_000, + Command::TransferNativeFromAgent { .. } => 60_000, Command::SetTokenTransferFees { .. } => 60_000, Command::SetPricingParameters { .. } => 60_000, Command::UnlockNativeToken { .. } => 200_000, diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index ceb4d23c294f6..052d7eb074475 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -43,6 +43,7 @@ decl_test_parachains! { ParachainInfo: asset_hub_rococo_runtime::ParachainInfo, MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, DigestProvider: (), + AdditionalInherentCode: (), }, pallets = { PolkadotXcm: asset_hub_rococo_runtime::PolkadotXcm, diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 0ae7067025fa4..6465e4fece3fd 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -43,6 +43,7 @@ decl_test_parachains! { ParachainInfo: asset_hub_westend_runtime::ParachainInfo, MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, DigestProvider: (), + AdditionalInherentCode: (), }, pallets = { PolkadotXcm: asset_hub_westend_runtime::PolkadotXcm, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs new file mode 100644 index 0000000000000..7125a4e8b60ee --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -0,0 +1,892 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use crate::imports::*; +use ahr_xcm_config::UniversalLocation as AssetHubRococoUniversalLocation; +use codec::{Decode, Encode}; +use emulated_integration_tests_common::xcm_emulator::ConvertLocation; +use frame_support::pallet_prelude::TypeInfo; +use hex_literal::hex; +use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender; +use snowbridge_inbound_queue_primitives::{ + v1::{Command, Destination, MessageV1, VersionedMessage}, + EventFixture, +}; +use snowbridge_inbound_queue_primitives::{ + v1::{ConvertMessage, ConvertMessageError, VersionedMessage}, + EventProof, VerificationError, Verifier, +}; +use snowbridge_outbound_queue_primitives::OperatingMode; +use snowbridge_pallet_inbound_queue_fixtures::{ + register_token::make_register_token_message, send_native_eth::make_send_native_eth_message, + send_token::make_send_token_message, send_token_to_penpal::make_send_token_to_penpal_message, +}; +use snowbridge_pallet_system; +use sp_core::H256; +use sp_runtime::{DispatchError::Token, TokenError::FundsUnavailable}; +use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; + +const INITIAL_FUND: u128 = 5_000_000_000 * ROCOCO_ED; +pub const CHAIN_ID: u64 = 11155111; +const TREASURY_ACCOUNT: [u8; 32] = + hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000"); +pub const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); +const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); +const INSUFFICIENT_XCM_FEE: u128 = 1000; +const XCM_FEE: u128 = 4_000_000_000; + +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum ControlCall { + #[codec(index = 3)] + CreateAgent, + #[codec(index = 4)] + CreateChannel { mode: OperatingMode }, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum SnowbridgeControl { + #[codec(index = 83)] + Control(ControlCall), +} + +pub fn send_inbound_message(fixture: EventFixture) -> DispatchResult { + EthereumBeaconClient::store_finalized_header( + fixture.finalized_header, + fixture.block_roots_root, + ) + .unwrap(); + EthereumInboundQueue::submit( + BridgeHubRococoRuntimeOrigin::signed(BridgeHubRococoSender::get()), + fixture.event, + ) +} + +/// Create an agent on Ethereum. An agent is a representation of an entity in the Polkadot +/// ecosystem (like a parachain) on Ethereum. +#[test] +#[ignore] +fn create_agent() { + let origin_para: u32 = 1001; + // Fund the origin parachain sovereign account so that it can pay execution fees. + BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND); + + let sudo_origin = ::RuntimeOrigin::root(); + let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into(); + + let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); + // Construct XCM to create an agent for para 1001 + let remote_xcm = VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + DescendOrigin(Parachain(origin_para).into()), + Transact { + origin_kind: OriginKind::Xcm, + call: create_agent_call.encode().into(), + fallback_max_weight: None, + }, + ])); + + // Rococo Global Consensus + // Send XCM message from Relay Chain to Bridge Hub source Parachain + Rococo::execute_with(|| { + assert_ok!(::XcmPallet::send( + sudo_origin, + bx!(destination), + bx!(remote_xcm), + )); + + type RuntimeEvent = ::RuntimeEvent; + // Check that the Transact message was sent + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + // Check that a message was sent to Ethereum to create the agent + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::EthereumSystem(snowbridge_pallet_system::Event::CreateAgent { + .. + }) => {}, + ] + ); + }); +} + +/// Create a channel for a consensus system. A channel is a bidirectional messaging channel +/// between BridgeHub and Ethereum. +#[test] +#[ignore] +fn create_channel() { + let origin_para: u32 = 1001; + // Fund AssetHub sovereign account so that it can pay execution fees. + BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND); + + let sudo_origin = ::RuntimeOrigin::root(); + let destination: VersionedLocation = + Rococo::child_location_of(BridgeHubRococo::para_id()).into(); + + let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); + // Construct XCM to create an agent for para 1001 + let create_agent_xcm = VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + DescendOrigin(Parachain(origin_para).into()), + Transact { + origin_kind: OriginKind::Xcm, + call: create_agent_call.encode().into(), + fallback_max_weight: None, + }, + ])); + + let create_channel_call = + SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal }); + // Construct XCM to create a channel for para 1001 + let create_channel_xcm = VersionedXcm::from(Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + DescendOrigin(Parachain(origin_para).into()), + Transact { + origin_kind: OriginKind::Xcm, + call: create_channel_call.encode().into(), + fallback_max_weight: None, + }, + ])); + + // Rococo Global Consensus + // Send XCM message from Relay Chain to Bridge Hub source Parachain + Rococo::execute_with(|| { + assert_ok!(::XcmPallet::send( + sudo_origin.clone(), + bx!(destination.clone()), + bx!(create_agent_xcm), + )); + + assert_ok!(::XcmPallet::send( + sudo_origin, + bx!(destination), + bx!(create_channel_xcm), + )); + + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the Channel was created + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::EthereumSystem(snowbridge_pallet_system::Event::CreateChannel { + .. + }) => {}, + ] + ); + }); +} + +/// Tests the registering of a token as an asset on AssetHub. +#[test] +fn register_weth_token_from_ethereum_to_asset_hub() { + // Fund AssetHub sovereign account so that it can pay execution fees. + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); + // Fund ethereum sovereign on AssetHub to satisfy ED + AssetHubRococo::fund_accounts(vec![(snowbridge_sovereign(), INITIAL_FUND)]); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Construct RegisterToken message and sent to inbound queue + let register_token_message = make_register_token_message(); + assert_ok!(send_inbound_message(register_token_message.clone())); + + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { .. }) => {}, + ] + ); + }); +} + +/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending +/// a token from Ethereum to AssetHub. +#[test] +fn send_weth_token_from_ethereum_to_asset_hub() { + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); + // Fund ethereum sovereign and receiver on AssetHub to satisfy ED + AssetHubRococo::fund_accounts(vec![ + (snowbridge_sovereign(), INITIAL_FUND), + (AssetHubRococoReceiver::get(), INITIAL_FUND), + ]); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Construct RegisterToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_register_token_message())); + + // Construct SendToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_send_token_message())); + + // Check that the message was sent + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +/// Tests sending a token to a 3rd party parachain, called PenPal. The token reserve is +/// still located on AssetHub. +#[test] +fn send_weth_from_ethereum_to_penpal() { + let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( + 1, + [Parachain(AssetHubRococo::para_id().into())], + )); + // Fund AssetHub sovereign account so it can pay execution fees for the asset transfer + BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); + + // Fund PenPal receiver (covering ED) + let native_id: Location = Parent.into(); + let receiver: AccountId = [ + 28, 189, 45, 67, 83, 10, 68, 112, 90, 208, 136, 175, 49, 62, 24, 248, 11, 83, 239, 22, 179, + 97, 119, 205, 75, 119, 184, 70, 242, 165, 240, 124, + ] + .into(); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + native_id, + receiver, + penpal_runtime::EXISTENTIAL_DEPOSIT, + ); + + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]).encode(), + )], + )); + }); + + let ethereum_network_v5: NetworkId = EthereumNetwork::get().into(); + + // The Weth asset location, identified by the contract address on Ethereum + let weth_asset_location: Location = + (Parent, Parent, ethereum_network_v5, AccountKey20 { network: None, key: WETH }).into(); + + let origin_location = (Parent, Parent, ethereum_network_v5).into(); + + // Fund ethereum sovereign on AssetHub + let ethereum_sovereign: AccountId = + GlobalConsensusEthereumConvertsFor::::convert_location(&origin_location) + .unwrap(); + AssetHubRococo::fund_accounts(vec![(ethereum_sovereign.clone(), INITIAL_FUND)]); + + // Create asset on the Penpal parachain. + PenpalA::execute_with(|| { + assert_ok!(::ForeignAssets::force_create( + ::RuntimeOrigin::root(), + weth_asset_location.clone(), + asset_hub_sovereign.into(), + false, + 1000, + )); + + assert!(::ForeignAssets::asset_exists(weth_asset_location)); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Construct RegisterToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_register_token_message())); + + // Construct SendToken message to AssetHub(only for increase the nonce as the same order in + // smoke test) + assert_ok!(send_inbound_message(make_send_token_message())); + + // Construct SendToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_send_token_to_penpal_message())); + + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + // Check that the assets were issued on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + PenpalA::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + // Check that the assets were issued on PenPal + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +/// Tests the full cycle of token transfers: +/// - registering a token on AssetHub +/// - sending a token to AssetHub +/// - returning the token to Ethereum +#[test] +fn send_weth_asset_from_asset_hub_to_ethereum() { + use ahr_xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; + let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); + let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location); + + AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION)); + AssetHubRococo::force_xcm_version( + Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]), + XCM_VERSION, + ); + + BridgeHubRococo::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); + AssetHubRococo::fund_accounts(vec![ + (AssetHubRococoReceiver::get(), INITIAL_FUND), + (snowbridge_sovereign(), INITIAL_FUND), + ]); + + const WETH_AMOUNT: u128 = 1_000_000_000; + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Construct RegisterToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_register_token_message())); + + // Check that the register token message was sent using xcm + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + + // Construct SendToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_send_token_message())); + + // Check that the send token message was sent using xcm + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeOrigin = ::RuntimeOrigin; + + // Check that AssetHub has issued the foreign asset + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + let assets = vec![Asset { + id: AssetId(Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: WETH }, + ], + )), + fun: Fungible(WETH_AMOUNT), + }]; + let multi_assets = VersionedAssets::from(Assets::from(assets)); + + let destination = VersionedLocation::from(Location::new( + 2, + [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })], + )); + + let beneficiary = VersionedLocation::from(Location::new( + 0, + [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], + )); + + let free_balance_before = ::Balances::free_balance( + AssetHubRococoReceiver::get(), + ); + // Send the Weth back to Ethereum + ::PolkadotXcm::limited_reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubRococoReceiver::get()), + Box::new(destination), + Box::new(beneficiary), + Box::new(multi_assets), + 0, + Unlimited, + ) + .unwrap(); + let free_balance_after = ::Balances::free_balance( + AssetHubRococoReceiver::get(), + ); + // Assert at least DefaultBridgeHubEthereumBaseFee charged from the sender + let free_balance_diff = free_balance_before - free_balance_after; + assert!(free_balance_diff > DefaultBridgeHubEthereumBaseFee::get()); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + // Check that the transfer token back to Ethereum message was queue in the Ethereum + // Outbound Queue + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued {..}) => {}, + ] + ); + let events = BridgeHubRococo::events(); + // Check that the local fee was credited to the Snowbridge sovereign account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount: _amount }) + if *who == TREASURY_ACCOUNT.into() + )), + "Snowbridge sovereign takes local fee." + ); + // Check that the remote fee was credited to the AssetHub sovereign account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount: _amount }) + if *who == assethub_sovereign + )), + "AssetHub sovereign takes remote fee." + ); + }); +} + +/// Tests the full cycle of eth transfers: +/// - sending a token to AssetHub +/// - returning the token to Ethereum +#[test] +fn send_eth_asset_from_asset_hub_to_ethereum_and_back() { + let ethereum_network: NetworkId = EthereumNetwork::get().into(); + let origin_location = (Parent, Parent, ethereum_network).into(); + + use ahr_xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; + let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); + let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location); + let ethereum_sovereign: AccountId = AssetHubRococo::execute_with(|| { + ExternalConsensusLocationsConverterFor::< + AssetHubRococoUniversalLocation, + AccountId, + >::convert_location(&origin_location) + .unwrap() + }); + + AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION)); + AssetHubRococo::force_xcm_version(origin_location.clone(), XCM_VERSION); + + BridgeHubRococo::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); + AssetHubRococo::fund_accounts(vec![ + (AssetHubRococoReceiver::get(), INITIAL_FUND), + (ethereum_sovereign.clone(), INITIAL_FUND), + ]); + + const ETH_AMOUNT: u128 = 1_000_000_000_000_000_000; + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeOrigin = ::RuntimeOrigin; + + // Set the gateway. This is needed because new fixtures use a different gateway address. + assert_ok!(::System::set_storage( + RuntimeOrigin::root(), + vec![( + EthereumGatewayAddress::key().to_vec(), + sp_core::H160(hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d")).encode(), + )], + )); + + // Construct SendToken message and sent to inbound queue + assert_ok!(send_inbound_message(make_send_native_eth_message())); + + // Check that the send token message was sent using xcm + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeOrigin = ::RuntimeOrigin; + + let _issued_event = RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { + asset_id: origin_location.clone(), + owner: AssetHubRococoReceiver::get().into(), + amount: ETH_AMOUNT, + }); + // Check that AssetHub has issued the foreign asset + assert_expected_events!( + AssetHubRococo, + vec![ + _issued_event => {}, + ] + ); + let assets = + vec![Asset { id: AssetId(origin_location.clone()), fun: Fungible(ETH_AMOUNT) }]; + let multi_assets = VersionedAssets::from(Assets::from(assets)); + + let destination = origin_location.clone().into(); + + let beneficiary = VersionedLocation::from(Location::new( + 0, + [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], + )); + + let free_balance_before = ::Balances::free_balance( + AssetHubRococoReceiver::get(), + ); + // Send the Weth back to Ethereum + ::PolkadotXcm::limited_reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubRococoReceiver::get()), + Box::new(destination), + Box::new(beneficiary), + Box::new(multi_assets), + 0, + Unlimited, + ) + .unwrap(); + + let _burned_event = RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { + asset_id: origin_location.clone(), + owner: AssetHubRococoReceiver::get().into(), + balance: ETH_AMOUNT, + }); + // Check that AssetHub has issued the foreign asset + let _destination = origin_location.clone(); + assert_expected_events!( + AssetHubRococo, + vec![ + _burned_event => {}, + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { + destination: _destination, .. + }) => {}, + ] + ); + + let free_balance_after = ::Balances::free_balance( + AssetHubRococoReceiver::get(), + ); + // Assert at least DefaultBridgeHubEthereumBaseFee charged from the sender + let free_balance_diff = free_balance_before - free_balance_after; + assert!(free_balance_diff > DefaultBridgeHubEthereumBaseFee::get()); + }); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + // Check that the transfer token back to Ethereum message was queue in the Ethereum + // Outbound Queue + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageAccepted {..}) => {}, + RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued {..}) => {}, + ] + ); + + let events = BridgeHubRococo::events(); + // Check that the local fee was credited to the Snowbridge sovereign account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount: _amount }) + if *who == TREASURY_ACCOUNT.into() + )), + "Snowbridge sovereign takes local fee." + ); + // Check that the remote fee was credited to the AssetHub sovereign account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount: _amount }) + if *who == assethub_sovereign + )), + "AssetHub sovereign takes remote fee." + ); + }); +} + +#[test] +fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { + // Insufficient fund + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), 1_000); + + BridgeHubRococo::execute_with(|| { + assert_err!(send_inbound_message(make_register_token_message()), Token(FundsUnavailable)); + }); +} + +#[test] +fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type EthereumInboundQueue = + ::EthereumInboundQueue; + let message_id: H256 = [0; 32].into(); + let message = VersionedXcmMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { + token: WETH.into(), + // Insufficient fee which should trigger the trap + fee: INSUFFICIENT_XCM_FEE, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); + + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, + ] + ); + }); +} + +fn send_weth_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) { + let ethereum_network_v5: NetworkId = EthereumNetwork::get().into(); + let weth_asset_location: Location = + Location::new(2, [ethereum_network_v5.into(), AccountKey20 { network: None, key: WETH }]); + // Fund asset hub sovereign on bridge hub + let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( + 1, + [Parachain(AssetHubRococo::para_id().into())], + )); + BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); + + // Register WETH + AssetHubRococo::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_ok!(::ForeignAssets::force_create( + RuntimeOrigin::root(), + weth_asset_location.clone().try_into().unwrap(), + asset_hub_sovereign.into(), + false, + 1, + )); + + assert!(::ForeignAssets::asset_exists( + weth_asset_location.clone().try_into().unwrap(), + )); + }); + + // Send WETH to an existent account on asset hub + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + type EthereumInboundQueue = + ::EthereumInboundQueue; + let message_id: H256 = [0; 32].into(); + let message = VersionedXcmMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: account_id }, + amount: 1_000_000, + fee, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + assert_ok!(EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into())); + + // Check that the message was sent + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_weth_from_ethereum_to_existent_account_on_asset_hub() { + send_weth_from_ethereum_to_asset_hub_with_fee(AssetHubRococoSender::get().into(), XCM_FEE); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_weth_from_ethereum_to_non_existent_account_on_asset_hub() { + send_weth_from_ethereum_to_asset_hub_with_fee([1; 32], XCM_FEE); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_weth_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficient_fee() { + send_weth_from_ethereum_to_asset_hub_with_fee([1; 32], INSUFFICIENT_XCM_FEE); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the message was not processed successfully due to insufficient fee + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_weth_from_ethereum_to_non_existent_account_on_asset_hub_with_sufficient_fee_but_do_not_satisfy_ed( +) { + // On AH the xcm fee is 26_789_690 and the ED is 3_300_000 + send_weth_from_ethereum_to_asset_hub_with_fee([1; 32], 30_000_000); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the message was not processed successfully due to insufficient ED + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, + ] + ); + }); +} + +#[test] +fn create_foreign_asset_deposit_is_equal_to_asset_hub_foreign_asset_pallet_deposit() { + let asset_hub_deposit = asset_hub_rococo_runtime::ForeignAssetsAssetDeposit::get(); + let bridge_hub_deposit = bp_asset_hub_rococo::CreateForeignAssetDeposit::get(); + assert!( + bridge_hub_deposit >= + asset_hub_deposit, + "The BridgeHub asset creation deposit must be equal to or larger than the asset creation deposit configured on BridgeHub" + ); +} + +pub fn snowbridge_sovereign() -> sp_runtime::AccountId32 { + use asset_hub_rococo_runtime::xcm_config::UniversalLocation as AssetHubWestendUniversalLocation; + let ethereum_sovereign: AccountId = AssetHubRococo::execute_with(|| { + ExternalConsensusLocationsConverterFor::< + AssetHubWestendUniversalLocation, + [u8; 32], + >::convert_location(&Location::new( + 2, + [xcm::v5::Junction::GlobalConsensus(EthereumNetwork::get())], + )) + .unwrap() + .into() + }); + + ethereum_sovereign +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index eea61e217c6ba..0af90f70cb103 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -17,34 +17,35 @@ #[cfg(not(feature = "runtime-benchmarks"))] use crate::XcmRouter; use crate::{ - xcm_config, xcm_config::UniversalLocation, Balances, EthereumInboundQueue, - EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, RuntimeEvent, TransactionByteFee, - TreasuryAccount, + xcm_config, + xcm_config::{RelayNetwork, UniversalLocation}, + Balances, EthereumInboundQueue, EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, + RuntimeEvent, TransactionByteFee, TreasuryAccount, }; +use bridge_hub_common::AggregateMessageOrigin; +use frame_support::{parameter_types, weights::ConstantMultiplier}; +use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards}; +use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; use snowbridge_inbound_queue_primitives::v1::MessageToXcm; use snowbridge_outbound_queue_primitives::v1::EthereumBlobExporter; -use sp_core::H160; -use testnet_parachains_constants::rococo::{ - currency::*, - fee::WeightToFee, - snowbridge::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, -}; - -use crate::xcm_config::RelayNetwork; #[cfg(feature = "runtime-benchmarks")] use benchmark_helpers::DoNothingRouter; use bp_asset_hub_rococo::CreateForeignAssetDeposit; -use frame_support::{parameter_types, weights::ConstantMultiplier}; use hex_literal::hex; -use pallet_xcm::EnsureXcm; +use snowbridge_pallet_inbound_queue::RewardThroughSovereign; +use sp_core::H160; use sp_runtime::{ - traits::{ConstU32, ConstU8, Keccak256}, + traits::{ConstU32, ConstU8, Convert, Keccak256}, FixedU128, }; +use testnet_parachains_constants::rococo::{ + currency::*, + fee::WeightToFee, + snowbridge::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; use xcm::prelude::{GlobalConsensus, InteriorLocation, Location, Parachain}; /// Exports message to the Ethereum Gateway contract. @@ -101,6 +102,17 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type AssetTransactor = ::AssetTransactor; + type MessageProcessor = + snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; + type RewardProcessor = RewardThroughSovereign; +} + +pub struct GetAggregateMessageOrigin; + +impl Convert for GetAggregateMessageOrigin { + fn convert(channel_id: ChannelId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Snowbridge(channel_id) + } } impl snowbridge_pallet_outbound_queue::Config for Runtime { @@ -116,6 +128,9 @@ impl snowbridge_pallet_outbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type Channels = EthereumSystem; + type AggregateMessageOrigin = AggregateMessageOrigin; + type GetAggregateMessageOrigin = GetAggregateMessageOrigin; + type OnNewCommitment = (); } #[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))] @@ -209,13 +224,16 @@ pub mod benchmark_helpers { use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; use codec::Encode; use snowbridge_beacon_primitives::BeaconHeader; + use snowbridge_inbound_queue_primitives::EventFixture; use snowbridge_pallet_inbound_queue::BenchmarkHelper; use sp_core::H256; use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; impl BenchmarkHelper for Runtime { - fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { - EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); + fn initialize_storage() -> EventFixture { + //EthereumBeaconClient::store_finalized_header(beacon_header, + // block_roots_root).unwrap(); + todo!() } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs index 1ce2329a97618..a1df98bde966f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs @@ -70,6 +70,26 @@ impl snowbridge_pallet_system::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: EthereumSystem Channels (r:1 w:0) + /// Proof: EthereumSystem Channels (max_values: None, max_size: Some(12), added: 2487, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_update_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(41_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `EthereumSystem::Channels` (r:1 w:0) /// Proof: `EthereumSystem::Channels` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`) /// Storage: `EthereumSystem::PricingParameters` (r:1 w:0) @@ -90,6 +110,26 @@ impl snowbridge_pallet_system::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: EthereumSystem Agents (r:1 w:0) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_transfer_native_from_agent() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `6044` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(42_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `EthereumSystem::Channels` (r:1 w:0) /// Proof: `EthereumSystem::Channels` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`) /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs index dc14c050f60f7..71a093ceffa47 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -22,20 +22,24 @@ use crate::{ EthereumOutboundQueueV2, EthereumSystem, EthereumSystemV2, MessageQueue, Runtime, RuntimeEvent, TransactionByteFee, }; +#[cfg(feature = "runtime-benchmarks")] +use benchmark_helpers::DoNothingRouter; use bp_asset_hub_westend::CreateForeignAssetDeposit; +use bridge_hub_common::AggregateMessageOrigin; use frame_support::{parameter_types, traits::Contains, weights::ConstantMultiplier}; use frame_system::EnsureRootWithSuccess; use pallet_xcm::EnsureXcm; use parachains_common::{AccountId, Balance}; use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards}; +use snowbridge_core::{gwei, meth, AllowSiblingsOnly, ChannelId, PricingParameters, Rewards}; use snowbridge_outbound_queue_primitives::{ v1::{ConstantGasMeter, EthereumBlobExporter}, v2::{ConstantGasMeter as ConstantGasMeterV2, EthereumBlobExporter as EthereumBlobExporterV2}, }; +use snowbridge_pallet_inbound_queue::RewardThroughSovereign; use sp_core::H160; use sp_runtime::{ - traits::{ConstU32, ConstU8, Keccak256}, + traits::{ConstU32, ConstU8, Convert, Keccak256}, FixedU128, }; use testnet_parachains_constants::westend::{ @@ -121,6 +125,9 @@ impl snowbridge_pallet_inbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type AssetTransactor = ::AssetTransactor; + type MessageProcessor = + snowbridge_pallet_inbound_queue::xcm_message_processor::XcmMessageProcessor; + type RewardProcessor = RewardThroughSovereign; } impl snowbridge_pallet_inbound_queue_v2::Config for Runtime { @@ -156,6 +163,13 @@ impl snowbridge_pallet_inbound_queue_v2::Config for Runtime { type DefaultRewardKind = SnowbridgeReward; type RewardPayment = BridgeRelayers; } +pub struct GetAggregateMessageOrigin; + +impl Convert for GetAggregateMessageOrigin { + fn convert(channel_id: ChannelId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Snowbridge(channel_id) + } +} impl snowbridge_pallet_outbound_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -170,6 +184,9 @@ impl snowbridge_pallet_outbound_queue::Config for Runtime { type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo; type PricingParameters = EthereumSystem; type Channels = EthereumSystem; + type AggregateMessageOrigin = AggregateMessageOrigin; + type GetAggregateMessageOrigin = GetAggregateMessageOrigin; + type OnNewCommitment = (); } impl snowbridge_pallet_outbound_queue_v2::Config for Runtime { @@ -312,6 +329,7 @@ pub mod benchmark_helpers { use codec::Encode; use hex_literal::hex; use snowbridge_beacon_primitives::BeaconHeader; + use snowbridge_inbound_queue_primitives::EventFixture; use snowbridge_pallet_inbound_queue::BenchmarkHelper; use snowbridge_pallet_inbound_queue_v2::BenchmarkHelper as InboundQueueBenchmarkHelperV2; use snowbridge_pallet_outbound_queue_v2::BenchmarkHelper as OutboundQueueBenchmarkHelperV2; @@ -319,7 +337,8 @@ pub mod benchmark_helpers { use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; impl BenchmarkHelper for Runtime { - fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { + fn initialize_storage() -> EventFixture { + /* EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); System::set_storage( RuntimeOrigin::root(), @@ -329,6 +348,8 @@ pub mod benchmark_helpers { )], ) .unwrap(); + */ + todo!() } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs index fd1080de5a794..3513cd92b6918 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs @@ -70,6 +70,26 @@ impl snowbridge_pallet_system::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: EthereumSystem Channels (r:1 w:0) + /// Proof: EthereumSystem Channels (max_values: None, max_size: Some(12), added: 2487, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_update_channel() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 41_000_000 picoseconds. + Weight::from_parts(41_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `EthereumSystem::Channels` (r:1 w:0) /// Proof: `EthereumSystem::Channels` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`) /// Storage: `EthereumSystem::PricingParameters` (r:1 w:0) @@ -90,6 +110,26 @@ impl snowbridge_pallet_system::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: EthereumSystem Agents (r:1 w:0) + /// Proof: EthereumSystem Agents (max_values: None, max_size: Some(40), added: 2515, mode: MaxEncodedLen) + /// Storage: EthereumOutboundQueue PalletOperatingMode (r:1 w:0) + /// Proof: EthereumOutboundQueue PalletOperatingMode (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: MessageQueue BookStateFor (r:2 w:2) + /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + /// Storage: MessageQueue ServiceHead (r:1 w:0) + /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen) + /// Storage: MessageQueue Pages (r:0 w:1) + /// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen) + fn force_transfer_native_from_agent() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `6044` + // Minimum execution time: 42_000_000 picoseconds. + Weight::from_parts(42_000_000, 0) + .saturating_add(Weight::from_parts(0, 6044)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `EthereumSystem::Channels` (r:1 w:0) /// Proof: `EthereumSystem::Channels` (`max_values`: None, `max_size`: Some(76), added: 2551, mode: `MaxEncodedLen`) /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index cd9658f191d59..a6c1bff7d8cea 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -45,6 +45,8 @@ polkadot-runtime-parachains.default-features = true polkadot-runtime-parachains.workspace = true sp-arithmetic.default-features = true sp-arithmetic.workspace = true +sp-consensus-slots = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } sp-core.default-features = true sp-core.workspace = true sp-crypto-hashing.default-features = true diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index d5a1d6ed5992d..080e4a912f784 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -52,14 +52,14 @@ pub use frame_system::{ }; pub use pallet_balances::AccountData; pub use pallet_message_queue; -pub use pallet_timestamp::Call as TimestampCall; +pub use pallet_timestamp::{Call as TimestampCall, Config as TimestampConfig}; pub use sp_arithmetic::traits::Bounded; pub use sp_core::{ crypto::get_public_from_string_or_panic, parameter_types, sr25519, storage::Storage, Pair, }; pub use sp_crypto_hashing::blake2_256; pub use sp_io::TestExternalities; -pub use sp_runtime::BoundedSlice; +pub use sp_runtime::{traits::Convert, BoundedSlice}; pub use sp_tracing; // Cumulus @@ -75,7 +75,7 @@ pub use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; pub use pallet_message_queue::{Config as MessageQueueConfig, Pallet as MessageQueuePallet}; pub use parachains_common::{AccountId, Balance}; pub use polkadot_primitives; -pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; +pub use polkadot_runtime_parachains::inclusion::{Config as InclusionConfig, UmpQueueId}; // Polkadot pub use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; @@ -142,6 +142,16 @@ where } } +// Implement optional inherent code to be executed +// This will be executed after on-initialize and before on-finalize +pub trait AdditionalInherentCode { + fn on_new_block() -> DispatchResult { + Ok(()) + } +} + +impl AdditionalInherentCode for () {} + pub trait TestExt { fn build_new_ext(storage: Storage) -> TestExternalities; fn new_ext() -> TestExternalities; @@ -269,6 +279,7 @@ pub trait Parachain: Chain { type ParachainSystem; type MessageProcessor: ProcessMessage + ServiceQueues; type DigestProvider: Convert, Digest>; + type AdditionalInherentCode: AdditionalInherentCode; fn init(); @@ -604,7 +615,8 @@ macro_rules! decl_test_parachains { LocationToAccountId: $location_to_account:path, ParachainInfo: $parachain_info:path, MessageOrigin: $message_origin:path, - $( DigestProvider: $digest_provider:ty, )? + $( DigestProvider: $digest_provider:ty,)? + $( AdditionalInherentCode: $additional_inherent_code:ty,)? }, pallets = { $($pallet_name:ident: $pallet_path:path,)* @@ -646,6 +658,7 @@ macro_rules! decl_test_parachains { type ParachainInfo = $parachain_info; type MessageProcessor = $crate::DefaultParaMessageProcessor<$name, $message_origin>; $crate::decl_test_parachains!(@inner_digest_provider $($digest_provider)?); + $crate::decl_test_parachains!(@inner_additional_inherent_code $($additional_inherent_code)?); // We run an empty block during initialisation to open HRMP channels // and have them ready for the next block @@ -666,7 +679,7 @@ macro_rules! decl_test_parachains { fn new_block() { use $crate::{ - Dispatchable, Chain, Convert, TestExt, Zero, + Dispatchable, Chain, Convert, TestExt, Zero, TimestampConfig, AdditionalInherentCode }; let para_id = Self::para_id().into(); @@ -705,14 +718,19 @@ macro_rules! decl_test_parachains { set_validation_data.dispatch(::RuntimeOrigin::none()) ); + let timestamp: u64 = (relay_block_number*6000).into(); + // 2. inherent: pallet_timestamp::Call::set (we expect the parachain has `pallet_timestamp`) let timestamp_set: ::RuntimeCall = $crate::TimestampCall::set { // We need to satisfy `pallet_timestamp::on_finalize`. - now: Zero::zero(), + now: timestamp, }.into(); $crate::assert_ok!( timestamp_set.dispatch(::RuntimeOrigin::none()) ); + $crate::assert_ok!( + ::AdditionalInherentCode::on_new_block() + ); }); } @@ -775,6 +793,8 @@ macro_rules! decl_test_parachains { }; ( @inner_digest_provider $digest_provider:ty ) => { type DigestProvider = $digest_provider; }; ( @inner_digest_provider /* none */ ) => { type DigestProvider = (); }; + ( @inner_additional_inherent_code $additional_inherent_code:ty ) => { type AdditionalInherentCode = $additional_inherent_code; }; + ( @inner_additional_inherent_code /* none */ ) => { type AdditionalInherentCode = (); }; } #[macro_export] @@ -1450,15 +1470,17 @@ where } } +type GenericAMO = <::Runtime as InclusionConfig>::AggregateMessageOrigin; + pub struct DefaultRelayMessageProcessor(PhantomData); // Process UMP messages on the relay impl ProcessMessage for DefaultRelayMessageProcessor where T: RelayChain, - T::Runtime: MessageQueueConfig, + T::Runtime: MessageQueueConfig + InclusionConfig, <::MessageProcessor as ProcessMessage>::Origin: - PartialEq, - MessageQueuePallet: EnqueueMessage + ServiceQueues, + PartialEq>, + MessageQueuePallet: EnqueueMessage> + ServiceQueues, { type Origin = ParaId; @@ -1470,7 +1492,9 @@ where ) -> Result { MessageQueuePallet::::enqueue_message( msg.try_into().expect("Message too long"), - AggregateMessageOrigin::Ump(UmpQueueId::Para(para)), + ::GetAggregateMessageOrigin::convert(UmpQueueId::Para( + para, + )), ); MessageQueuePallet::::service_queues(Weight::MAX); @@ -1481,10 +1505,10 @@ where impl ServiceQueues for DefaultRelayMessageProcessor where T: RelayChain, - T::Runtime: MessageQueueConfig, + T::Runtime: MessageQueueConfig + InclusionConfig, <::MessageProcessor as ProcessMessage>::Origin: - PartialEq, - MessageQueuePallet: EnqueueMessage + ServiceQueues, + PartialEq>, + MessageQueuePallet: EnqueueMessage> + ServiceQueues, { type OverweightMessageAddress = (); diff --git a/polkadot/node/core/pvf/common/src/executor_interface.rs b/polkadot/node/core/pvf/common/src/executor_interface.rs index 47f9ed1604e78..c02db118b7e49 100644 --- a/polkadot/node/core/pvf/common/src/executor_interface.rs +++ b/polkadot/node/core/pvf/common/src/executor_interface.rs @@ -191,7 +191,7 @@ pub fn prepare( executor_params: &ExecutorParams, ) -> Result, sc_executor_common::error::WasmError> { let (semantics, _) = params_to_wasmtime_semantics(executor_params); - sc_executor_wasmtime::prepare_runtime_artifact(blob, &semantics) + sc_executor_wasmtime::prepare_runtime_artifact(blob, Default::default(), &semantics) } /// Available host functions. We leave out: diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 6bca327984d80..00904ab4ff7dd 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -33,7 +33,7 @@ use alloc::{ vec::Vec, }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; -use codec::{Decode, DecodeWithMemTracking, Encode}; +use codec::{Decode, DecodeWithMemTracking, Encode, FullCodec}; use core::fmt; use frame_support::{ defensive, @@ -55,7 +55,10 @@ use polkadot_primitives::{ ValidatorIndex, ValidityAttestation, }; use scale_info::TypeInfo; -use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; +use sp_runtime::{ + traits::{Convert, Debug, One}, + DispatchError, SaturatedConversion, Saturating, +}; pub use pallet::*; @@ -263,8 +266,9 @@ impl From for AggregateMessageOrigin { } /// The maximal length of a UMP message. -pub type MaxUmpMessageLenOf = - <::MessageQueue as EnqueueMessage>::MaxMessageLen; +pub type MaxUmpMessageLenOf = <::MessageQueue as EnqueueMessage< + ::AggregateMessageOrigin, +>>::MaxMessageLen; #[frame_support::pallet] pub mod pallet { @@ -291,13 +295,25 @@ pub mod pallet { type DisputesHandler: disputes::DisputesHandler>; type RewardValidators: RewardValidators; + type AggregateMessageOrigin: FullCodec + + MaxEncodedLen + + Clone + + Eq + + PartialEq + + TypeInfo + + Debug; + type GetAggregateMessageOrigin: Convert; + type GetParaFromAggregateMessageOrigin: Convert; /// The system message queue. /// /// The message queue provides general queueing and processing functionality. Currently it /// replaces the old `UMP` dispatch queue. Other use-cases can be implemented as well by /// adding new variants to `AggregateMessageOrigin`. - type MessageQueue: EnqueueMessage - + QueueFootprintQuery>; + type MessageQueue: EnqueueMessage + + QueueFootprintQuery< + Self::AggregateMessageOrigin, + MaxMessageLen = MaxUmpMessageLenOf, + >; /// Weight info for the calls of this pallet. type WeightInfo: WeightInfo; @@ -494,7 +510,7 @@ impl Pallet { } pub(crate) fn cleanup_outgoing_ump_dispatch_queue(para: ParaId) { - T::MessageQueue::sweep_queue(AggregateMessageOrigin::Ump(UmpQueueId::Para(para))); + T::MessageQueue::sweep_queue(T::GetAggregateMessageOrigin::convert(UmpQueueId::Para(para))); } pub(crate) fn get_occupied_cores( @@ -922,7 +938,9 @@ impl Pallet { } pub(crate) fn relay_dispatch_queue_size(para_id: ParaId) -> (u32, u32) { - let fp = T::MessageQueue::footprint(AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id))); + let fp = T::MessageQueue::footprint(T::GetAggregateMessageOrigin::convert( + UmpQueueId::Para(para_id), + )); (fp.storage.count as u32, fp.storage.size as u32) } @@ -1011,7 +1029,7 @@ impl Pallet { T::MessageQueue::enqueue_messages( messages.into_iter(), - AggregateMessageOrigin::Ump(UmpQueueId::Para(para)), + T::GetAggregateMessageOrigin::convert(UmpQueueId::Para(para)), ); Self::deposit_event(Event::UpwardMessagesReceived { from: para, count }); } @@ -1191,12 +1209,10 @@ impl AcceptanceCheckErr { } } -impl OnQueueChanged for Pallet { +impl OnQueueChanged for Pallet { // Write back the remaining queue capacity into `relay_dispatch_queue_remaining_capacity`. - fn on_queue_changed(origin: AggregateMessageOrigin, fp: QueueFootprint) { - let para = match origin { - AggregateMessageOrigin::Ump(UmpQueueId::Para(p)) => p, - }; + fn on_queue_changed(origin: T::AggregateMessageOrigin, fp: QueueFootprint) { + let para = T::GetParaFromAggregateMessageOrigin::convert(origin); let QueueFootprint { storage: Footprint { count, size }, .. } = fp; let (count, size) = (count.saturated_into(), size.saturated_into()); // TODO paritytech/polkadot#6283: Remove all usages of `relay_dispatch_queue_size` @@ -1403,6 +1419,8 @@ impl QueueFootprinter for Pallet { type Origin = UmpQueueId; fn message_count(origin: Self::Origin) -> u64 { - T::MessageQueue::footprint(AggregateMessageOrigin::Ump(origin)).storage.count + T::MessageQueue::footprint(T::GetAggregateMessageOrigin::convert(origin)) + .storage + .count } } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 0ecc929c7ce8d..289679c5a3f74 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -115,8 +115,8 @@ use sp_core::{ConstU128, ConstU8, ConstUint, Get, OpaqueMetadata, H256}; use sp_runtime::{ generic, impl_opaque_keys, traits::{ - AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, IdentityLookup, - Keccak256, OpaqueKeys, SaturatedConversion, Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, Convert, ConvertInto, + IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, @@ -1040,10 +1040,31 @@ impl polkadot_runtime_parachains::inclusion::RewardValidators for RewardValidato fn reward_bitfields(_: impl IntoIterator) {} } +pub struct GetAggregateMessageOrigin; + +impl Convert for GetAggregateMessageOrigin { + fn convert(queue_id: UmpQueueId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Ump(queue_id) + } +} + +pub struct GetParaFromAggregateMessageOrigin; + +impl Convert for GetParaFromAggregateMessageOrigin { + fn convert(x: AggregateMessageOrigin) -> ParaId { + match x { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id)) => para_id, + } + } +} + impl parachains_inclusion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type DisputesHandler = ParasDisputes; type RewardValidators = RewardValidators; + type AggregateMessageOrigin = AggregateMessageOrigin; + type GetAggregateMessageOrigin = GetAggregateMessageOrigin; + type GetParaFromAggregateMessageOrigin = GetParaFromAggregateMessageOrigin; type MessageQueue = MessageQueue; type WeightInfo = weights::polkadot_runtime_parachains_inclusion::WeightInfo; } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index c3071c48985fc..3ed63b4d60704 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -36,6 +36,7 @@ use polkadot_runtime_parachains::{ coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, + inclusion::{AggregateMessageOrigin, UmpQueueId}, initializer as parachains_initializer, on_demand as parachains_on_demand, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, @@ -85,8 +86,8 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - BlakeTwo256, Block as BlockT, ConvertInto, OpaqueKeys, SaturatedConversion, StaticLookup, - Verify, + BlakeTwo256, Block as BlockT, Convert, ConvertInto, Extrinsic as ExtrinsicT, OpaqueKeys, + SaturatedConversion, StaticLookup, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, @@ -552,10 +553,31 @@ impl parachains_shared::Config for Runtime { type DisabledValidators = Session; } +pub struct GetAggregateMessageOrigin; + +impl Convert for GetAggregateMessageOrigin { + fn convert(queue_id: UmpQueueId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Ump(queue_id) + } +} + +pub struct GetParaFromAggregateMessageOrigin; + +impl Convert for GetParaFromAggregateMessageOrigin { + fn convert(x: AggregateMessageOrigin) -> ParaId { + match x { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id)) => para_id, + } + } +} + impl parachains_inclusion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type DisputesHandler = ParasDisputes; type RewardValidators = RewardValidatorsWithEraPoints; + type AggregateMessageOrigin = AggregateMessageOrigin; + type GetAggregateMessageOrigin = GetAggregateMessageOrigin; + type GetParaFromAggregateMessageOrigin = GetParaFromAggregateMessageOrigin; type MessageQueue = (); type WeightInfo = (); } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 2c5e7c75341ad..e04b8177456de 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -103,8 +103,8 @@ use sp_core::{ConstBool, ConstU8, ConstUint, OpaqueMetadata, RuntimeDebug, H256} use sp_runtime::{ generic, impl_opaque_keys, traits::{ - AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, IdentityLookup, Keccak256, - OpaqueKeys, SaturatedConversion, Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, Convert, ConvertInto, IdentityLookup, + Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, MultiSignature, MultiSigner, Percent, Permill, @@ -1385,11 +1385,32 @@ impl parachains_session_info::Config for Runtime { type ValidatorSet = Historical; } +pub struct GetAggregateMessageOrigin; + +impl Convert for GetAggregateMessageOrigin { + fn convert(queue_id: UmpQueueId) -> AggregateMessageOrigin { + AggregateMessageOrigin::Ump(queue_id) + } +} + +pub struct GetParaFromAggregateMessageOrigin; + +impl Convert for GetParaFromAggregateMessageOrigin { + fn convert(x: AggregateMessageOrigin) -> ParaId { + match x { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id)) => para_id, + } + } +} + impl parachains_inclusion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type DisputesHandler = ParasDisputes; type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; + type AggregateMessageOrigin = AggregateMessageOrigin; + type GetAggregateMessageOrigin = GetAggregateMessageOrigin; + type GetParaFromAggregateMessageOrigin = GetParaFromAggregateMessageOrigin; type MessageQueue = MessageQueue; type WeightInfo = weights::polkadot_runtime_parachains_inclusion::WeightInfo; } diff --git a/prdoc/pr_8809.prdoc b/prdoc/pr_8809.prdoc new file mode 100644 index 0000000000000..eebbd8675a285 --- /dev/null +++ b/prdoc/pr_8809.prdoc @@ -0,0 +1,10 @@ +title: Add possibility of executing or mocking additional inherents in xcm-emulator +doc: +- audience: Runtime Dev + description: |- + This extends the `decl_test_parachains` macro to accept a `AdditionalInherentCode` type. This type needs to + implement the `AdditionalInherentCode` trait and will be called after `on_initialize` and before `on_finalize`. + It can be used to mock additional inherents. +crates: +- name: xcm-emulator + bump: minor diff --git a/prdoc/pr_9004.prdoc b/prdoc/pr_9004.prdoc new file mode 100644 index 0000000000000..58f8314395fd6 --- /dev/null +++ b/prdoc/pr_9004.prdoc @@ -0,0 +1,22 @@ +title: 'chore: Bump bounded-collections dep' +doc: +- audience: Runtime Dev + description: |- + # Description + + Bump bounded-collections dep from `0.2.3` to `0.3.2` based on the latest [release](https://crates.io/crates/bounded-collections/0.3.2) +crates: +- name: sp-core + bump: minor +- name: sp-weights + bump: minor +- name: polkadot-parachain-primitives + bump: minor +- name: polkadot-primitives + bump: minor +- name: staging-xcm + bump: minor +- name: pallet-xcm + bump: minor +- name: cumulus-pallet-xcmp-queue + bump: minor diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index c5a8663337157..b17fdba1f937f 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -109,6 +109,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { announce_block: true, data_path: base_path.path().into(), base_path, + wasmtime_precompiled: None, wasm_runtime_overrides: None, }; diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index 12d1340c0ba0a..24d089b08e519 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -95,6 +95,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { announce_block: true, data_path: base_path.path().into(), base_path, + wasmtime_precompiled: None, wasm_runtime_overrides: None, }; diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs index c2187e77e7f1b..0539b94524e50 100644 --- a/substrate/bin/node/cli/src/cli.rs +++ b/substrate/bin/node/cli/src/cli.rs @@ -108,4 +108,7 @@ pub enum Subcommand { /// Db meta columns information. ChainInfo(sc_cli::ChainInfoCmd), + + /// Precompile the WASM runtime into native code + PrecompileWasm(sc_cli::PrecompileWasmCmd), } diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index 5f3be4d8b2159..e20f0da7a8b54 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -234,5 +234,12 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run::(&config)) }, + Some(Subcommand::PrecompileWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { task_manager, backend, .. } = new_partial(&config, None)?; + Ok((cmd.run(backend, config.chain_spec), task_manager)) + }) + }, } } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 1a3c24aa20d4c..89ca08c99a7d1 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -68,6 +68,9 @@ sp-version.default-features = true sp-version.workspace = true thiserror = { workspace = true } tokio = { features = ["parking_lot", "rt-multi-thread", "signal"], workspace = true, default-features = true } +sc-executor = { workspace = true } +sp-storage = { workspace = true, default-features = true } +sp-state-machine = { workspace = true, default-features = true } [dev-dependencies] futures-timer = { workspace = true } diff --git a/substrate/client/cli/src/commands/mod.rs b/substrate/client/cli/src/commands/mod.rs index b63fb1d904234..27137a1f22143 100644 --- a/substrate/client/cli/src/commands/mod.rs +++ b/substrate/client/cli/src/commands/mod.rs @@ -31,6 +31,7 @@ mod insert_key; mod inspect_key; mod inspect_node_key; mod key; +mod precompile_wasm_cmd; mod purge_chain_cmd; mod revert_cmd; mod run_cmd; @@ -46,6 +47,6 @@ pub use self::{ export_state_cmd::ExportStateCmd, generate::GenerateCmd, generate_node_key::GenerateKeyCmdCommon, import_blocks_cmd::ImportBlocksCmd, insert_key::InsertKeyCmd, inspect_key::InspectKeyCmd, inspect_node_key::InspectNodeKeyCmd, - key::KeySubcommand, purge_chain_cmd::PurgeChainCmd, revert_cmd::RevertCmd, run_cmd::RunCmd, - sign::SignCmd, vanity::VanityCmd, verify::VerifyCmd, + key::KeySubcommand, precompile_wasm_cmd::PrecompileWasmCmd, purge_chain_cmd::PurgeChainCmd, + revert_cmd::RevertCmd, run_cmd::RunCmd, sign::SignCmd, vanity::VanityCmd, verify::VerifyCmd, }; diff --git a/substrate/client/cli/src/commands/precompile_wasm_cmd.rs b/substrate/client/cli/src/commands/precompile_wasm_cmd.rs new file mode 100644 index 0000000000000..ba2948a449953 --- /dev/null +++ b/substrate/client/cli/src/commands/precompile_wasm_cmd.rs @@ -0,0 +1,148 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{ + arg_enums::{ + execution_method_from_cli, WasmExecutionMethod, WasmtimeInstantiationStrategy, + DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + }, + error::{self, Error}, + params::{DatabaseParams, PruningParams, SharedParams}, + CliConfiguration, +}; + +use clap::Parser; +use sc_client_api::{Backend, HeaderBackend, TrieCacheContext}; +use sc_executor::{ + precompile_and_serialize_versioned_wasm_runtime, HeapAllocStrategy, DEFAULT_HEAP_ALLOC_PAGES, +}; +use sc_service::ChainSpec; +use sp_core::traits::RuntimeCode; +use sp_runtime::traits::Block as BlockT; +use sp_state_machine::backend::BackendRuntimeCode; +use std::{fmt::Debug, path::PathBuf, sync::Arc}; + +/// The `precompile-wasm` command used to serialize a precompiled WASM module. +#[derive(Debug, Parser)] +pub struct PrecompileWasmCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub database_params: DatabaseParams, + + /// The default number of 64KB pages to ever allocate for Wasm execution. + /// Don't alter this unless you know what you're doing. + #[arg(long, value_name = "COUNT")] + pub default_heap_pages: Option, + + /// path to the directory where precompiled artifact will be written + #[arg()] + pub output_dir: PathBuf, + + #[allow(missing_docs)] + #[clap(flatten)] + pub pruning_params: PruningParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + /// The WASM instantiation method to use. + /// Only has an effect when `wasm-execution` is set to `compiled`. + /// The copy-on-write strategies are only supported on Linux. + /// If the copy-on-write variant of a strategy is unsupported + /// the executor will fall back to the non-CoW equivalent. + /// The fastest (and the default) strategy available is `pooling-copy-on-write`. + /// The `legacy-instance-reuse` strategy is deprecated and will + /// be removed in the future. It should only be used in case of + /// issues with the default instantiation strategy. + #[arg( + long, + value_name = "STRATEGY", + default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, + value_enum, + )] + pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, +} + +impl PrecompileWasmCmd { + /// Run the precompile-wasm command + pub async fn run(&self, backend: Arc, spec: Box) -> error::Result<()> + where + B: BlockT, + BA: Backend, + { + let heap_pages = self.default_heap_pages.unwrap_or(DEFAULT_HEAP_ALLOC_PAGES); + + let blockchain_info = backend.blockchain().info(); + + if backend.have_state_at(blockchain_info.finalized_hash, blockchain_info.finalized_number) { + let state = backend.state_at( + backend.blockchain().info().finalized_hash, + TrieCacheContext::Untrusted, + )?; + + precompile_and_serialize_versioned_wasm_runtime( + HeapAllocStrategy::Static { extra_pages: heap_pages }, + &BackendRuntimeCode::new(&state).runtime_code()?, + execution_method_from_cli( + WasmExecutionMethod::Compiled, + self.wasmtime_instantiation_strategy, + ), + &self.output_dir, + ) + .map_err(|e| Error::Application(Box::new(e)))?; + } else { + let storage = spec.as_storage_builder().build_storage()?; + if let Some(wasm_bytecode) = storage.top.get(sp_storage::well_known_keys::CODE) { + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode( + wasm_bytecode.as_slice().into(), + ), + hash: sp_core::blake2_256(&wasm_bytecode).to_vec(), + heap_pages: Some(heap_pages as u64), + }; + precompile_and_serialize_versioned_wasm_runtime( + HeapAllocStrategy::Static { extra_pages: heap_pages }, + &runtime_code, + execution_method_from_cli( + WasmExecutionMethod::Compiled, + self.wasmtime_instantiation_strategy, + ), + &self.output_dir, + ) + .map_err(|e| Error::Application(Box::new(e)))?; + } + } + + Ok(()) + } +} + +impl CliConfiguration for PrecompileWasmCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } + + fn pruning_params(&self) -> Option<&PruningParams> { + Some(&self.pruning_params) + } + + fn database_params(&self) -> Option<&DatabaseParams> { + Some(&self.database_params) + } +} diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index d456a4072d0e0..5e1abc7e8a1ed 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -304,6 +304,13 @@ pub trait CliConfiguration: Sized { Ok(self.import_params().map(|x| x.wasm_method()).unwrap_or_default()) } + /// Get the path where WASM precompiled artifacts live. + /// + /// By default this is `None`. + fn wasmtime_precompiled(&self) -> Option { + self.import_params().map(|x| x.wasmtime_precompiled()).unwrap_or_default() + } + /// Get the path where WASM overrides live. /// /// By default this is `None`. @@ -543,6 +550,7 @@ pub trait CliConfiguration: Sized { blocks_pruning: self.blocks_pruning()?, executor: ExecutorConfiguration { wasm_method: self.wasm_method()?, + wasmtime_precompiled: self.wasmtime_precompiled(), default_heap_pages: self.default_heap_pages()?, max_runtime_instances, runtime_cache_size, diff --git a/substrate/client/cli/src/params/import_params.rs b/substrate/client/cli/src/params/import_params.rs index 236907957df67..4efe78322eba7 100644 --- a/substrate/client/cli/src/params/import_params.rs +++ b/substrate/client/cli/src/params/import_params.rs @@ -65,6 +65,16 @@ pub struct ImportParams { )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, + /// Specify the path where local precompiled WASM runtimes are stored. + /// Only has an effect when `wasm-execution` is set to `compiled`. + /// + /// The precompiled runtimes must have been generated using the `precompile-runtimes` + /// subcommand with the same version of wasmtime and the exact same configuration. + /// The file name must end with the hash of the configuration. This hash must match, otherwise + /// the runtime will be recompiled. + #[arg(long, value_name = "PATH")] + pub wasmtime_precompiled: Option, + /// Specify the path where local WASM runtimes are stored. /// /// These runtimes will override on-chain runtimes when the version matches. @@ -136,6 +146,12 @@ impl ImportParams { crate::execution_method_from_cli(self.wasm_method, self.wasmtime_instantiation_strategy) } + /// Enable using precompiled WASM module with locally-stored artifacts + /// by specifying the path where artifacts are stored. + pub fn wasmtime_precompiled(&self) -> Option { + self.wasmtime_precompiled.clone() + } + /// Enable overriding on-chain WASM with locally-stored WASM /// by specifying the path where local WASM is stored. pub fn wasm_runtime_overrides(&self) -> Option { diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs index 2cc55f2fccd01..6c8dce4349079 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -267,6 +267,7 @@ mod tests { .build(), ), executor: ExecutorConfiguration::default(), + wasmtime_precompiled: None, wasm_runtime_overrides: None, rpc: RpcConfiguration { addr: None, diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 04132bbdeac85..85a680015c144 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -21,6 +21,7 @@ name = "bench" harness = false [dependencies] +log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } schnellru = { workspace = true } tracing = { workspace = true, default-features = true } diff --git a/substrate/client/executor/benches/bench.rs b/substrate/client/executor/benches/bench.rs index 8e460955396c4..6baeab03358f5 100644 --- a/substrate/client/executor/benches/bench.rs +++ b/substrate/client/executor/benches/bench.rs @@ -67,13 +67,17 @@ fn initialize( wasm_bulk_memory: false, wasm_reference_types: false, wasm_simd: false, + module_version_strategy: Default::default(), }, }; if precompile { - let precompiled_blob = - sc_executor_wasmtime::prepare_runtime_artifact(blob, &config.semantics) - .unwrap(); + let precompiled_blob = sc_executor_wasmtime::prepare_runtime_artifact( + blob, + Default::default(), + &config.semantics, + ) + .unwrap(); // Create a fresh temporary directory to make absolutely sure // we'll use the right module. @@ -85,7 +89,7 @@ fn initialize( unsafe { sc_executor_wasmtime::create_runtime_from_artifact::< sp_io::SubstrateHostFunctions, - >(&path, config) + >(&path, Default::defaut(), config) } } else { sc_executor_wasmtime::create_runtime::(blob, config) diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index b6776ba2a98b6..eead785dcde8e 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -24,6 +24,7 @@ sp-maybe-compressed-blob.default-features = true sp-maybe-compressed-blob.workspace = true sp-wasm-interface.default-features = true sp-wasm-interface.workspace = true +codec = { features = ["derive"], workspace = true } thiserror = { workspace = true } wasm-instrument = { workspace = true, default-features = true } diff --git a/substrate/client/executor/common/src/wasm_runtime.rs b/substrate/client/executor/common/src/wasm_runtime.rs index e8f429a3dbb2a..778731c964c40 100644 --- a/substrate/client/executor/common/src/wasm_runtime.rs +++ b/substrate/client/executor/common/src/wasm_runtime.rs @@ -74,7 +74,7 @@ pub trait WasmInstance: Send { /// Defines the heap pages allocation strategy the wasm runtime should use. /// /// A heap page is defined as 64KiB of memory. -#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, codec::Encode)] pub enum HeapAllocStrategy { /// Allocate a static number of heap pages. /// diff --git a/substrate/client/executor/src/executor.rs b/substrate/client/executor/src/executor.rs index 198a2a31ab8db..b59bbb7ff0633 100644 --- a/substrate/client/executor/src/executor.rs +++ b/substrate/client/executor/src/executor.rs @@ -92,6 +92,7 @@ pub struct WasmExecutorBuilder { max_runtime_instances: usize, cache_path: Option, allow_missing_host_functions: bool, + wasmtime_precompiled_path: Option, runtime_cache_size: u8, } @@ -110,6 +111,7 @@ impl WasmExecutorBuilder { runtime_cache_size: 4, allow_missing_host_functions: false, cache_path: None, + wasmtime_precompiled_path: None, } } @@ -193,6 +195,20 @@ impl WasmExecutorBuilder { self } + /// Create the wasm executor with the given `wasmtime_precompiled_path`. + /// + /// The `wasmtime_precompiled_path` is a path to a directory where the executor load precompiled + /// wasmtime modules. + /// + /// By default there is no `wasmtime_precompiled_path` given. + pub fn with_wasmtime_precompiled_path( + mut self, + wasmtime_precompiled_path: impl Into, + ) -> Self { + self.wasmtime_precompiled_path = Some(wasmtime_precompiled_path.into()); + self + } + /// Build the configured [`WasmExecutor`]. pub fn build(self) -> WasmExecutor { WasmExecutor { @@ -211,6 +227,7 @@ impl WasmExecutorBuilder { )), cache_path: self.cache_path, allow_missing_host_functions: self.allow_missing_host_functions, + wasmtime_precompiled_path: self.wasmtime_precompiled_path, phantom: PhantomData, } } @@ -234,6 +251,8 @@ pub struct WasmExecutor { cache_path: Option, /// Ignore missing function imports. allow_missing_host_functions: bool, + /// TODO + wasmtime_precompiled_path: Option, phantom: PhantomData, } @@ -247,6 +266,7 @@ impl Clone for WasmExecutor { cache: self.cache.clone(), cache_path: self.cache_path.clone(), allow_missing_host_functions: self.allow_missing_host_functions, + wasmtime_precompiled_path: self.wasmtime_precompiled_path.clone(), phantom: self.phantom, } } @@ -301,6 +321,7 @@ impl WasmExecutor { )), cache_path, allow_missing_host_functions: false, + wasmtime_precompiled_path: None, phantom: PhantomData, } } @@ -353,6 +374,7 @@ where runtime_code, ext, self.method, + self.wasmtime_precompiled_path.as_deref(), heap_alloc_strategy, self.allow_missing_host_functions, |module, instance, version, ext| { @@ -430,6 +452,8 @@ where runtime_blob, allow_missing_host_functions, self.cache_path.as_deref(), + None, + &[], ) .map_err(|e| format!("Failed to create module: {}", e))?; diff --git a/substrate/client/executor/src/lib.rs b/substrate/client/executor/src/lib.rs index 204f1ff22d74d..ab713a4aafb5c 100644 --- a/substrate/client/executor/src/lib.rs +++ b/substrate/client/executor/src/lib.rs @@ -36,17 +36,22 @@ mod executor; mod integration_tests; mod wasm_runtime; -pub use codec::Codec; #[allow(deprecated)] -pub use executor::NativeElseWasmExecutor; -pub use executor::{with_externalities_safe, NativeExecutionDispatch, WasmExecutor}; +pub use self::{ + executor::{ + with_externalities_safe, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor, + }, + wasm_runtime::{ + precompile_and_serialize_versioned_wasm_runtime, read_embedded_version, WasmExecutionMethod, + }, +}; +pub use codec::Codec; #[doc(hidden)] pub use sp_core::traits::Externalities; pub use sp_version::{NativeVersion, RuntimeVersion}; #[doc(hidden)] pub use sp_wasm_interface; pub use sp_wasm_interface::HostFunctions; -pub use wasm_runtime::{read_embedded_version, WasmExecutionMethod}; pub use sc_executor_common::{ error, diff --git a/substrate/client/executor/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index 8f189ca92388a..31e4192e078e9 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -23,7 +23,7 @@ use crate::error::{Error, WasmError}; -use codec::Decode; +use codec::{Decode, Encode}; use parking_lot::Mutex; use sc_executor_common::{ runtime_blob::RuntimeBlob, @@ -35,6 +35,7 @@ use sp_version::RuntimeVersion; use sp_wasm_interface::HostFunctions; use std::{ + io::Write, panic::AssertUnwindSafe, path::{Path, PathBuf}, sync::Arc, @@ -220,6 +221,7 @@ impl RuntimeCache { runtime_code: &'c RuntimeCode<'c>, ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, + wasmtime_precompiled: Option<&Path>, heap_alloc_strategy: HeapAllocStrategy, allow_missing_func_imports: bool, f: F, @@ -255,6 +257,8 @@ impl RuntimeCache { allow_missing_func_imports, self.max_runtime_instances, self.cache_path.as_deref(), + wasmtime_precompiled, + code_hash, ); match result { @@ -293,6 +297,8 @@ pub fn create_wasm_runtime_with_code( blob: RuntimeBlob, allow_missing_func_imports: bool, cache_path: Option<&Path>, + wasmtime_precompiled_path: Option<&Path>, + code_hash: &[u8], ) -> Result, WasmError> where H: HostFunctions, @@ -302,29 +308,200 @@ where } match wasm_method { - WasmExecutionMethod::Compiled { instantiation_strategy } => - sc_executor_wasmtime::create_runtime::( - blob, - sc_executor_wasmtime::Config { - allow_missing_func_imports, - cache_path: cache_path.map(ToOwned::to_owned), - semantics: sc_executor_wasmtime::Semantics { - heap_alloc_strategy, - instantiation_strategy, - deterministic_stack_limit: None, - canonicalize_nans: false, - parallel_compilation: true, - wasm_multi_value: false, - wasm_bulk_memory: false, - wasm_reference_types: false, - wasm_simd: false, + WasmExecutionMethod::Compiled { instantiation_strategy } => { + let semantics = sc_executor_wasmtime::Semantics { + heap_alloc_strategy, + instantiation_strategy, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, + }; + if let Some(wasmtime_precompiled_dir) = wasmtime_precompiled_path { + if !wasmtime_precompiled_dir.is_dir() { + return Err(WasmError::Instantiation(format!( + "--wasmtime-precompiled is not a directory: {}", + wasmtime_precompiled_dir.display() + ))); + } + let handle_err = |e: std::io::Error| -> WasmError { + return WasmError::Instantiation(format!( + "Io error when loading wasmtime precompiled folder ({}): {}", + wasmtime_precompiled_dir.display(), + e + )); + }; + let mut maybe_compiled_artifact = None; + + let artifact_version = + compute_artifact_version(allow_missing_func_imports, code_hash, &semantics); + log::debug!( + target: "wasmtime-runtime", + "Searching for wasm hash: {}", + artifact_version.clone() + ); + + for entry in std::fs::read_dir(wasmtime_precompiled_dir).map_err(handle_err)? { + let entry = entry.map_err(handle_err)?; + if let Some(file_name) = entry.file_name().to_str() { + // We check that the artifact was generated for this specific artifact + // version and with the same wasm interface version and configuration. + if file_name.contains(&artifact_version.clone()) { + log::info!( + target: "wasmtime-runtime", + "Found precompiled wasm: {}", + file_name + ); + // We change the version check strategy to make sure that the file + // content was serialized with the exact same config as well + maybe_compiled_artifact = Some(( + entry.path(), + sc_executor_wasmtime::ModuleVersionStrategy::Custom( + artifact_version.clone(), + ), + )); + } + } else { + return Err(WasmError::Instantiation( + "wasmtime precompiled folder contain a file with invalid utf8 name" + .to_owned(), + )); + } + } + + if let Some((compiled_artifact_path, module_version_strategy)) = + maybe_compiled_artifact + { + // # Safety + // + // The file name of the artifact was checked before, + // so if the user has not renamed nor modified the file, + // it's certain that the file has been generated by + // `prepare_runtime_artifact` and with the same wasmtime + // version and configuration. + unsafe { + sc_executor_wasmtime::create_runtime_from_artifact::( + &compiled_artifact_path, + module_version_strategy, + sc_executor_wasmtime::Config { + allow_missing_func_imports, + cache_path: cache_path.map(ToOwned::to_owned), + semantics, + }, + ) + } + .map(|runtime| -> Box { Box::new(runtime) }) + } else { + sc_executor_wasmtime::create_runtime::( + blob, + sc_executor_wasmtime::Config { + allow_missing_func_imports, + cache_path: cache_path.map(ToOwned::to_owned), + semantics, + }, + ) + .map(|runtime| -> Box { Box::new(runtime) }) + } + } else { + sc_executor_wasmtime::create_runtime::( + blob, + sc_executor_wasmtime::Config { + allow_missing_func_imports, + cache_path: cache_path.map(ToOwned::to_owned), + semantics, }, - }, - ) - .map(|runtime| -> Box { Box::new(runtime) }), + ) + .map(|runtime| -> Box { Box::new(runtime) }) + } + }, } } +/// Create and serialize a precompiled artifact of a wasm runtime with the given `code`. +pub fn precompile_and_serialize_versioned_wasm_runtime<'c>( + heap_alloc_strategy: HeapAllocStrategy, + runtime_code: &'c RuntimeCode<'c>, + wasm_method: WasmExecutionMethod, + wasmtime_precompiled_path: &Path, +) -> Result<(), WasmError> { + let semantics = match wasm_method { + WasmExecutionMethod::Compiled { instantiation_strategy } => + sc_executor_wasmtime::Semantics { + heap_alloc_strategy, + instantiation_strategy, + deterministic_stack_limit: None, + canonicalize_nans: false, + parallel_compilation: true, + wasm_multi_value: false, + wasm_bulk_memory: false, + wasm_reference_types: false, + wasm_simd: false, + }, + }; + + let code_hash = &runtime_code.hash; + + let artifact_version = compute_artifact_version(false, code_hash, &semantics); + log::debug!( + target: "wasmtime-runtime", + "Generated precompiled wasm hash: {}", + artifact_version.clone() + ); + + let code = runtime_code.fetch_runtime_code().ok_or(WasmError::CodeNotFound)?; + + // The incoming code may be actually compressed. We decompress it here and then work with + // the uncompressed code from now on. + let blob = sc_executor_common::runtime_blob::RuntimeBlob::uncompress_if_needed(code.as_ref())?; + + let serialized_precompiled_wasm = sc_executor_wasmtime::prepare_runtime_artifact( + blob, + sc_executor_wasmtime::ModuleVersionStrategy::Custom(artifact_version.clone()), + &semantics, + )?; + + // Write in a file + let mut file = std::fs::File::create( + wasmtime_precompiled_path.join(format!("precompiled_wasm_{}", &artifact_version)), + ) + .map_err(|e| { + WasmError::Other(format!( + "Fail to create file 'precompiled_wasm_0x{}', I/O Error: {}", + &artifact_version, e + )) + })?; + file.write_all(&serialized_precompiled_wasm).map_err(|e| { + WasmError::Other(format!("Fail to write precompiled artifact, I/O Error: {}", e)) + })?; + + Ok(()) +} + +/// Compute a hash that aggregates all the metadata relating to the artifact that must not change +/// so that it can be reused with confidence. +fn compute_artifact_version( + allow_missing_func_imports: bool, + code_hash: &[u8], + semantics: &sc_executor_wasmtime::Semantics, +) -> String { + log::trace!( + target: "wasmtime-runtime", + "Computing wasm runtime hash [allow_missing_func_imports: {}, code_hash: {}, semantics: {:?}]", + allow_missing_func_imports, sp_core::bytes::to_hex(&code_hash, false), semantics + ); + let mut buffer = Vec::new(); + buffer.extend_from_slice(code_hash); + buffer.extend_from_slice(sp_wasm_interface::VERSION.as_bytes()); + buffer.push(allow_missing_func_imports as u8); + semantics.encode_to(&mut buffer); + + let hash = sp_core::hashing::blake2_256(&buffer); + sp_core::bytes::to_hex(&hash, false) +} + fn decode_version(mut version: &[u8]) -> Result { Decode::decode(&mut version).map_err(|_| { WasmError::Instantiation( @@ -389,6 +566,8 @@ fn create_versioned_wasm_runtime( allow_missing_func_imports: bool, max_instances: usize, cache_path: Option<&Path>, + wasmtime_precompiled: Option<&Path>, + code_hash: &[u8], ) -> Result where H: HostFunctions, @@ -408,6 +587,8 @@ where blob, allow_missing_func_imports, cache_path, + wasmtime_precompiled, + code_hash, )?; // If the runtime blob doesn't embed the runtime version then use the legacy version query diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index 34b5fcad00b51..a5b364453993e 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -17,6 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true, default-features = true } +codec = { workspace = true, default-features = true } +cfg-if = { workspace = true } +libc = { workspace = true } parking_lot = { workspace = true, default-features = true } # When bumping wasmtime do not forget to also bump rustix @@ -46,9 +49,9 @@ wasmtime = { features = [ rustix = { features = ["fs", "mm", "param", "std", "use-libc"], workspace = true } [dev-dependencies] +paste = { workspace = true, default-features = true } cargo_metadata = { workspace = true } codec = { workspace = true, default-features = true } -paste = { workspace = true, default-features = true } sc-runtime-test = { workspace = true } sp-io = { default-features = true, workspace = true } tempfile = { workspace = true } diff --git a/substrate/client/executor/wasmtime/src/lib.rs b/substrate/client/executor/wasmtime/src/lib.rs index 8e8e92017df91..0047c0ff8be4a 100644 --- a/substrate/client/executor/wasmtime/src/lib.rs +++ b/substrate/client/executor/wasmtime/src/lib.rs @@ -38,8 +38,8 @@ mod tests; pub use runtime::{ create_runtime, create_runtime_from_artifact, create_runtime_from_artifact_bytes, - prepare_runtime_artifact, Config, DeterministicStackLimit, InstantiationStrategy, Semantics, - WasmtimeRuntime, + prepare_runtime_artifact, Config, DeterministicStackLimit, InstantiationStrategy, + ModuleVersionStrategy, Semantics, WasmtimeRuntime, }; pub use sc_executor_common::{ runtime_blob::RuntimeBlob, diff --git a/substrate/client/executor/wasmtime/src/runtime.rs b/substrate/client/executor/wasmtime/src/runtime.rs index 286d134ecd171..c824c40010bf0 100644 --- a/substrate/client/executor/wasmtime/src/runtime.rs +++ b/substrate/client/executor/wasmtime/src/runtime.rs @@ -18,6 +18,8 @@ //! Defines the compiled Wasm runtime that uses Wasmtime internally. +pub use wasmtime::ModuleVersionStrategy; + use crate::{ host::HostState, instance_wrapper::{EntryPoint, InstanceWrapper, MemoryWrapper}, @@ -354,7 +356,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result { /// /// We use a `Path` here instead of simply passing a byte slice to allow `wasmtime` to /// map the runtime's linear memory on supported platforms in a copy-on-write fashion. - Precompiled(&'a Path), + Precompiled { + /// Path to the precompiled artifact + compiled_artifact_path: &'a Path, + /// Configure the strategy used for versioning check in deserializing precompiled artifact + module_version_strategy: ModuleVersionStrategy, + }, /// The runtime is instantiated using a precompiled module with the given bytes. /// @@ -527,12 +534,16 @@ where /// different configuration flags. In such case the caller will receive an `Err` deterministically. pub unsafe fn create_runtime_from_artifact( compiled_artifact_path: &Path, + module_version_strategy: ModuleVersionStrategy, config: Config, ) -> std::result::Result where H: HostFunctions, { - do_create_runtime::(CodeSupplyMode::Precompiled(compiled_artifact_path), config) + do_create_runtime::( + CodeSupplyMode::Precompiled { compiled_artifact_path, module_version_strategy }, + config, + ) } /// The same as [`create_runtime`] but takes the bytes of a precompiled artifact, @@ -574,6 +585,13 @@ where replace_strategy_if_broken(&mut config.semantics.instantiation_strategy); let mut wasmtime_config = common_config(&config.semantics)?; + + if let CodeSupplyMode::Precompiled { ref module_version_strategy, .. } = code_supply_mode { + wasmtime_config.module_version(module_version_strategy.clone()).map_err(|e| { + WasmError::Other(format!("fail to apply module_version_strategy: {:#}", e)) + })?; + } + if let Some(ref cache_path) = config.cache_path { if let Err(reason) = setup_wasmtime_caching(cache_path, &mut wasmtime_config) { log::warn!( @@ -602,7 +620,7 @@ where (module, InternalInstantiationStrategy::Builtin), } }, - CodeSupplyMode::Precompiled(compiled_artifact_path) => { + CodeSupplyMode::Precompiled { compiled_artifact_path, .. } => { // SAFETY: The unsafety of `deserialize_file` is covered by this function. The // responsibilities to maintain the invariants are passed to the caller. // @@ -661,6 +679,7 @@ fn prepare_blob_for_compilation( /// can then be used for calling [`create_runtime`] avoiding long compilation times. pub fn prepare_runtime_artifact( blob: RuntimeBlob, + module_version_strategy: ModuleVersionStrategy, semantics: &Semantics, ) -> std::result::Result, WasmError> { let mut semantics = semantics.clone(); @@ -668,7 +687,13 @@ pub fn prepare_runtime_artifact( let blob = prepare_blob_for_compilation(blob, &semantics)?; - let engine = Engine::new(&common_config(&semantics)?) + let mut wasmtime_config = common_config(&semantics)?; + + wasmtime_config + .module_version(module_version_strategy) + .map_err(|e| WasmError::Other(format!("fail to apply module_version_strategy: {:#}", e)))?; + + let engine = Engine::new(&wasmtime_config) .map_err(|e| WasmError::Other(format!("cannot create the engine: {:#}", e)))?; engine diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index 1ea1557fa6634..18effc8cbb0d0 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -146,6 +146,7 @@ impl RuntimeBuilder { wasm_bulk_memory: false, wasm_reference_types: false, wasm_simd: false, + module_version_strategy: Default::default(), }, }; @@ -156,9 +157,17 @@ impl RuntimeBuilder { // Delay the removal of the temporary directory until we're dropped. self.tmpdir = Some(dir); - let artifact = crate::prepare_runtime_artifact(blob, &config.semantics).unwrap(); + let artifact = + crate::prepare_runtime_artifact(blob, Default::default(), &config.semantics) + .unwrap(); std::fs::write(&path, artifact).unwrap(); - unsafe { crate::create_runtime_from_artifact::(&path, config) } + unsafe { + crate::create_runtime_from_artifact::( + &path, + Default::default(), + config, + ) + } } else { crate::create_runtime::(blob, config) } @@ -473,6 +482,7 @@ fn test_instances_without_reuse_are_not_leaked() { wasm_bulk_memory: false, wasm_reference_types: false, wasm_simd: false, + module_version_strategy: Default::default(), }, }, ) diff --git a/substrate/client/network/sync/src/strategy/warp.rs b/substrate/client/network/sync/src/strategy/warp.rs index a4c9c0868b794..0981fc6732c4a 100644 --- a/substrate/client/network/sync/src/strategy/warp.rs +++ b/substrate/client/network/sync/src/strategy/warp.rs @@ -46,7 +46,7 @@ use sp_runtime::{ use std::{any::Any, collections::HashMap, fmt, sync::Arc}; /// Number of peers that need to be connected before warp sync is started. -const MIN_PEERS_TO_START_WARP_SYNC: usize = 3; +const MIN_PEERS_TO_START_WARP_SYNC: usize = 1; /// Scale-encoded warp sync proof response. pub struct EncodedProof(pub Vec); diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 74d94c30cd69b..b89b6e98dcc8e 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -258,6 +258,7 @@ where ClientConfig { offchain_worker_enabled: config.offchain_worker.enabled, offchain_indexing_api: config.offchain_worker.indexing_enabled, + wasmtime_precompiled: config.executor.wasmtime_precompiled.clone(), wasm_runtime_overrides: config.wasm_runtime_overrides.clone(), no_genesis: config.no_genesis(), wasm_runtime_substitutes, @@ -364,13 +365,18 @@ pub fn new_wasm_executor(config: &ExecutorConfiguration) -> Wa let strategy = config .default_heap_pages .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |p| HeapAllocStrategy::Static { extra_pages: p as _ }); - WasmExecutor::::builder() + let mut wasm_builder = WasmExecutor::::builder() .with_execution_method(config.wasm_method) .with_onchain_heap_alloc_strategy(strategy) .with_offchain_heap_alloc_strategy(strategy) .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) - .build() + .with_runtime_cache_size(config.runtime_cache_size); + + if let Some(ref wasmtime_precompiled_path) = config.wasmtime_precompiled { + wasm_builder = wasm_builder.with_wasmtime_precompiled_path(wasmtime_precompiled_path); + } + + wasm_builder.build() } /// Create an instance of default DB-backend backend. diff --git a/substrate/client/service/src/client/call_executor.rs b/substrate/client/service/src/client/call_executor.rs index 235b2a6a07ed1..c62fb1b2bd3c5 100644 --- a/substrate/client/service/src/client/call_executor.rs +++ b/substrate/client/service/src/client/call_executor.rs @@ -30,7 +30,7 @@ use sp_runtime::{ traits::{Block as BlockT, HashingFor}, }; use sp_state_machine::{backend::AsTrieBackend, OverlayedChanges, StateMachine, StorageProof}; -use std::{cell::RefCell, sync::Arc}; +use std::{cell::RefCell, path::PathBuf, sync::Arc}; /// Call executor that executes methods locally, querying all required /// data from local backend. @@ -38,6 +38,7 @@ pub struct LocalCallExecutor { backend: Arc, executor: E, code_provider: CodeProvider, + wasmtime_precompiled_path: Option, execution_extensions: Arc>, } @@ -59,6 +60,7 @@ where backend, executor, code_provider, + wasmtime_precompiled_path: client_config.wasmtime_precompiled, execution_extensions: Arc::new(execution_extensions), }) } @@ -73,6 +75,7 @@ where backend: self.backend.clone(), executor: self.executor.clone(), code_provider: self.code_provider.clone(), + wasmtime_precompiled_path: self.wasmtime_precompiled_path.clone(), execution_extensions: self.execution_extensions.clone(), } } diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 5f55499b32f06..e9628eb400ad0 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -166,6 +166,8 @@ pub struct ClientConfig { pub wasm_runtime_substitutes: HashMap, Vec>, /// Enable recording of storage proofs during block import pub enable_import_proof_recording: bool, + /// Path where precompiled wasmtime modules exist. + pub wasmtime_precompiled: Option, } impl Default for ClientConfig { @@ -177,6 +179,7 @@ impl Default for ClientConfig { no_genesis: false, wasm_runtime_substitutes: HashMap::new(), enable_import_proof_recording: false, + wasmtime_precompiled: None, } } } diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index 74ae044bdc3f8..95ffa5048a85c 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -347,6 +347,10 @@ pub struct RpcConfiguration { pub struct ExecutorConfiguration { /// Wasm execution method. pub wasm_method: WasmExecutionMethod, + /// Directory where local WASM precompiled artifacts live. These wasm modules + /// take precedence over runtimes when the spec and wasm config matches. Set to `None` to + /// disable (default). + pub wasmtime_precompiled: Option, /// The size of the instances cache. /// /// The default value is 8. @@ -361,6 +365,7 @@ impl Default for ExecutorConfiguration { fn default() -> Self { Self { wasm_method: WasmExecutionMethod::default(), + wasmtime_precompiled: Default::default(), max_runtime_instances: 8, default_heap_pages: None, runtime_cache_size: 2, diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 484c34d7c3300..92ddda29d4a0a 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -25,7 +25,7 @@ harness = false [dependencies] bip39 = { workspace = true, default-features = false, features = ["alloc"] } bitflags = { workspace = true } -bounded-collections = { workspace = true } +bounded-collections = { workspace = true, features = ["scale-codec"] } bs58 = { optional = true, workspace = true } codec = { features = ["derive", "max-encoded-len"], workspace = true } dyn-clonable = { optional = true, workspace = true } @@ -70,9 +70,6 @@ secp256k1 = { features = ["alloc", "recovery"], optional = true, workspace = tru sha2 = { optional = true, workspace = true } w3f-bls = { optional = true, workspace = true } -# bandersnatch crypto -ark-vrf = { optional = true, workspace = true, features = ["bandersnatch", "ring"] } - [target.'cfg(not(substrate_runtime))'.dependencies] sp-externalities.workspace = true sp-externalities.default-features = false @@ -87,7 +84,6 @@ serde_json = { workspace = true, default-features = true } [features] default = ["std"] std = [ - "ark-vrf?/std", "bip39/rand", "bip39/std", "blake2/std", @@ -162,4 +158,4 @@ bls-experimental = ["sha2", "w3f-bls"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = ["ark-vrf"] +bandersnatch-experimental = [] diff --git a/substrate/primitives/wasm-interface/src/lib.rs b/substrate/primitives/wasm-interface/src/lib.rs index f6948d8cb88e9..59ab2caf3cb95 100644 --- a/substrate/primitives/wasm-interface/src/lib.rs +++ b/substrate/primitives/wasm-interface/src/lib.rs @@ -46,6 +46,8 @@ if_wasmtime_is_enabled! { pub use anyhow; } +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + /// Result type used by traits in this crate. pub type Result = core::result::Result; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs index ccf33daca55fe..fe68749fd7a3c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -521,6 +521,7 @@ impl OverheadCmd { no_genesis: false, wasm_runtime_substitutes: Default::default(), enable_import_proof_recording: chain_type.requires_proof_recording(), + wasmtime_precompiled: Default::default(), }, )?); diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index aad6d0a222666..7aa46d71b184a 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -84,19 +84,22 @@ pub fn new_partial(config: &Configuration) -> Result .default_heap_pages .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); - let executor = ParachainExecutor::builder() + let mut wasm_builder = WasmExecutor::builder() .with_execution_method(config.executor.wasm_method) .with_onchain_heap_alloc_strategy(heap_pages) .with_offchain_heap_alloc_strategy(heap_pages) .with_max_runtime_instances(config.executor.max_runtime_instances) - .with_runtime_cache_size(config.executor.runtime_cache_size) - .build(); + .with_runtime_cache_size(config.executor.runtime_cache_size); + if let Some(ref wasmtime_precompiled_path) = config.executor.wasmtime_precompiled { + wasm_builder = wasm_builder.with_wasmtime_precompiled_path(wasmtime_precompiled_path); + } + let wasm = wasm_builder.build(); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts_record_import::( config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, + wasm, true, )?; let client = Arc::new(client); diff --git a/templates/solochain/node/src/cli.rs b/templates/solochain/node/src/cli.rs index c09905c7949e7..f87c889454f38 100644 --- a/templates/solochain/node/src/cli.rs +++ b/templates/solochain/node/src/cli.rs @@ -49,4 +49,7 @@ pub enum Subcommand { /// Db meta columns information. ChainInfo(sc_cli::ChainInfoCmd), + + /// Precompile the WASM runtime into native code + PrecompileWasm(sc_cli::PrecompileWasmCmd), } diff --git a/templates/solochain/node/src/command.rs b/templates/solochain/node/src/command.rs index 57e6726178569..7449400ca4acd 100644 --- a/templates/solochain/node/src/command.rs +++ b/templates/solochain/node/src/command.rs @@ -181,6 +181,14 @@ pub fn run() -> sc_cli::Result<()> { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run::(&config)) }, + Some(Subcommand::PrecompileWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let PartialComponents { task_manager, backend, .. } = + service::new_partial(&config)?; + Ok((cmd.run(backend, config.chain_spec), task_manager)) + }) + }, None => { let runner = cli.create_runner(&cli.run)?; runner.run_node_until_exit(|config| async move {