diff --git a/.config/lingua.dic b/.config/lingua.dic index 59ca5caa72..56d04e82f4 100644 --- a/.config/lingua.dic +++ b/.config/lingua.dic @@ -37,7 +37,6 @@ InitiateChange Instance1 Instance2 Instance42 -InstantCurrencyPayments KSM/S KYC/M KeyPair @@ -66,6 +65,7 @@ Pre RLP RPC/MS Rialto/MS +RialtoParachain/MS Relayer/MS Runtime1 Runtime2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7d3bf6fd8a..33dd6b84a4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ variables: &default-vars GIT_DEPTH: 100 CARGO_INCREMENTAL: 0 ARCH: "x86_64" - CI_IMAGE: "paritytech/bridges-ci:staging" + CI_IMAGE: "paritytech/bridges-ci:production" RUST_BACKTRACE: full default: @@ -94,8 +94,11 @@ clippy-nightly: stage: lint <<: *docker-env <<: *test-refs + variables: + RUSTFLAGS: "-D warnings" script: - - SKIP_WASM_BUILD=1 cargo +nightly clippy --all-targets -- -A clippy::redundant_closure + # clippy currently is raising `derive-partial-eq-without-eq` warning even if `Eq` is actually derived + - SKIP_WASM_BUILD=1 cargo +nightly clippy --all-targets -- -A clippy::redundant_closure -A clippy::derive-partial-eq-without-eq fmt: stage: lint @@ -109,7 +112,7 @@ spellcheck: <<: *docker-env <<: *test-refs script: - - cargo spellcheck check -vvvv --cfg=.config/spellcheck.toml --checkers hunspell -m 1 + - cargo spellcheck check --cfg=.config/spellcheck.toml --checkers hunspell -m 1 #### stage: check @@ -144,7 +147,8 @@ test: - time cargo fetch - time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-test-runtime\").manifest_path"` - time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-runtime\").manifest_path"` - - CARGO_NET_OFFLINE=true time cargo test --verbose --workspace + - time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"kusama-runtime\").manifest_path"` + - CARGO_NET_OFFLINE=true SKIP_POLKADOT_RUNTIME_WASM_BUILD=1 SKIP_KUSAMA_RUNTIME_WASM_BUILD=1 SKIP_POLKADOT_TEST_RUNTIME_WASM_BUILD=1 time cargo test --verbose --workspace test-nightly: stage: test @@ -194,7 +198,8 @@ build: - time cargo fetch - time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-test-runtime\").manifest_path"` - time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-runtime\").manifest_path"` - - CARGO_NET_OFFLINE=true time cargo build --release --verbose --workspace + - time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"kusama-runtime\").manifest_path"` + - CARGO_NET_OFFLINE=true SKIP_POLKADOT_RUNTIME_WASM_BUILD=1 SKIP_KUSAMA_RUNTIME_WASM_BUILD=1 SKIP_POLKADOT_TEST_RUNTIME_WASM_BUILD=1 time cargo build --release --verbose --workspace after_script: # Prepare artifacts - mkdir -p ./artifacts @@ -228,9 +233,6 @@ build-nightly: GIT_STRATEGY: none DOCKERFILE: ci.Dockerfile IMAGE_NAME: docker.io/paritytech/$CI_JOB_NAME - VAULT_SERVER_URL: "https://vault.parity-mgmt-vault.parity.io" - VAULT_AUTH_PATH: "gitlab-parity-io-jwt" - VAULT_AUTH_ROLE: "cicd_gitlab_parity_${CI_PROJECT_NAME}" needs: - job: build artifacts: true @@ -248,15 +250,8 @@ build-nightly: FLOATING_TAG="latest"; fi - echo "Effective tags = ${VERSION} sha-${CI_COMMIT_SHORT_SHA} ${FLOATING_TAG}" - secrets: - DOCKER_HUB_USER: - vault: cicd/gitlab/parity/DOCKER_HUB_USER@kv - file: false - DOCKER_HUB_PASS: - vault: cicd/gitlab/parity/DOCKER_HUB_PASS@kv - file: false script: - - test "${DOCKER_HUB_USER}" -a "${DOCKER_HUB_PASS}" || + - test "${Docker_Hub_User_Parity}" -a "${Docker_Hub_Pass_Parity}" || ( echo "no docker credentials provided"; exit 1 ) - cd ./artifacts - buildah bud @@ -270,8 +265,8 @@ build-nightly: --tag "${IMAGE_NAME}:${FLOATING_TAG}" --file "${DOCKERFILE}" . # The job will success only on the protected branch - - echo "${DOCKER_HUB_PASS}" | - buildah login --username "${DOCKER_HUB_USER}" --password-stdin docker.io + - echo "${Docker_Hub_Pass_Parity}" | + buildah login --username "${Docker_Hub_User_Parity}" --password-stdin docker.io - buildah info - buildah push --format=v2s2 "${IMAGE_NAME}:${VERSION}" - buildah push --format=v2s2 "${IMAGE_NAME}:sha-${CI_COMMIT_SHORT_SHA}" diff --git a/.maintain/millau-weight-template.hbs b/.maintain/millau-weight-template.hbs index 7a2a67627b..afa75f57c9 100644 --- a/.maintain/millau-weight-template.hbs +++ b/.maintain/millau-weight-template.hbs @@ -30,6 +30,7 @@ #![allow(clippy::all)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; diff --git a/Cargo.lock b/Cargo.lock index 54e6f03c9d..a783d7fa69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.2.1", + "cpufeatures", "opaque-debug 0.3.0", ] @@ -94,7 +94,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -103,7 +103,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -237,9 +237,9 @@ dependencies = [ "parking", "polling", "slab", - "socket2 0.4.4", + "socket2", "waker-fn", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -274,20 +274,21 @@ dependencies = [ "libc", "once_cell", "signal-hook", - "winapi 0.3.9", + "winapi", ] [[package]] name = "async-std" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" +checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" dependencies = [ "async-attributes", "async-channel", "async-global-executor", "async-io", "async-lock", + "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -299,7 +300,7 @@ dependencies = [ "memchr", "num_cpus", "once_cell", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", "pin-utils", "slab", "wasm-bindgen-futures", @@ -307,15 +308,16 @@ dependencies = [ [[package]] name = "async-std-resolver" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed4e2c3da14d8ad45acb1e3191db7a918e9505b6f155b218e70a7c9a1a48c638" +checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" dependencies = [ "async-std", "async-trait", "futures-io", "futures-util", "pin-utils", + "socket2", "trust-dns-resolver", ] @@ -327,48 +329,26 @@ checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "asynchronous-codec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4401f0a3622dad2e0763fa79e0eb328bc70fb7dccfdd645341f00d671247d6" -dependencies = [ - "bytes 1.1.0", - "futures-sink", - "futures-util", - "memchr", - "pin-project-lite 0.2.7", -] - [[package]] name = "asynchronous-codec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.7", -] - -[[package]] -name = "atomic" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" -dependencies = [ - "autocfg", + "pin-project-lite 0.2.9", ] [[package]] @@ -385,14 +365,14 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backoff" @@ -406,16 +386,16 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" +checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" dependencies = [ "addr2line", "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object", + "object 0.27.1", "rustc-demangle", ] @@ -443,12 +423,6 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "base64ct" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71acf5509fc522cce1b100ac0121c635129bfd4d91cdf036bcc9b9935f97ccf5" - [[package]] name = "beef" version = "0.5.1" @@ -461,17 +435,21 @@ dependencies = [ [[package]] name = "beefy-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ + "async-trait", "beefy-primitives", "fnv", - "futures 0.3.21", + "futures", + "futures-timer", "hex", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-chain-spec", "sc-client-api", + "sc-consensus", + "sc-finality-grandpa", "sc-keystore", "sc-network", "sc-network-gossip", @@ -480,8 +458,10 @@ dependencies = [ "sp-application-crypto", "sp-arithmetic", "sp-blockchain", + "sp-consensus", "sp-core", "sp-keystore", + "sp-mmr-primitives", "sp-runtime", "substrate-prometheus-endpoint", "thiserror", @@ -491,18 +471,15 @@ dependencies = [ [[package]] name = "beefy-gadget-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "beefy-gadget", "beefy-primitives", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-pubsub", + "futures", + "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-rpc", "sc-utils", "serde", @@ -514,12 +491,16 @@ dependencies = [ [[package]] name = "beefy-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "beefy-primitives", + "sp-api", +] [[package]] name = "beefy-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "scale-info", @@ -582,17 +563,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "blake2" version = "0.10.4" @@ -614,39 +584,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "0.5.11" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec 0.7.2", "constant_time_eq", ] [[package]] name = "blake2s_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "constant_time_eq", -] - -[[package]] -name = "blake3" -version = "0.3.8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" +checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", - "arrayvec 0.5.2", - "cc", - "cfg-if 0.1.10", + "arrayvec 0.7.2", "constant_time_eq", - "crypto-mac 0.8.0", - "digest 0.9.0", ] [[package]] @@ -725,9 +680,9 @@ dependencies = [ [[package]] name = "bounded-vec" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47cca82fca99417fe405f09d93bb8fff90bdd03d13c631f18096ee123b4281c" +checksum = "3372be4090bf9d4da36bd8ba7ce6ca1669503d0cf6e667236c6df7f053153eb6" dependencies = [ "thiserror", ] @@ -736,7 +691,6 @@ dependencies = [ name = "bp-header-chain" version = "0.1.0" dependencies = [ - "assert_matches", "bp-runtime", "bp-test-utils", "finality-grandpa", @@ -767,17 +721,6 @@ dependencies = [ "sp-version", ] -[[package]] -name = "bp-message-dispatch" -version = "0.1.0" -dependencies = [ - "bp-runtime", - "frame-support", - "parity-scale-codec", - "scale-info", - "sp-std", -] - [[package]] name = "bp-messages" version = "0.1.0" @@ -819,6 +762,19 @@ dependencies = [ "sp-trie", ] +[[package]] +name = "bp-parachains" +version = "0.1.0" +dependencies = [ + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", +] + [[package]] name = "bp-polkadot" version = "0.1.0" @@ -844,7 +800,9 @@ dependencies = [ "frame-system", "hex", "parity-scale-codec", + "parity-util-mem", "scale-info", + "serde", "sp-api", "sp-core", "sp-runtime", @@ -852,6 +810,17 @@ dependencies = [ "sp-version", ] +[[package]] +name = "bp-relayers" +version = "0.1.0" +dependencies = [ + "frame-support", + "hex", + "hex-literal", + "sp-runtime", + "sp-std", +] + [[package]] name = "bp-rialto" version = "0.1.0" @@ -901,17 +870,20 @@ name = "bp-runtime" version = "0.1.0" dependencies = [ "frame-support", + "frame-system", "hash-db", "hex-literal", "num-traits", "parity-scale-codec", "scale-info", + "serde", "sp-core", "sp-io", "sp-runtime", "sp-state-machine", "sp-std", "sp-trie", + "trie-db", ] [[package]] @@ -928,21 +900,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "bp-token-swap" -version = "0.1.0" -dependencies = [ - "bp-runtime", - "frame-support", - "hex", - "hex-literal", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-std", -] - [[package]] name = "bp-westend" version = "0.1.0" @@ -978,28 +935,36 @@ dependencies = [ name = "bridge-runtime-common" version = "0.1.0" dependencies = [ - "bp-message-dispatch", "bp-messages", + "bp-parachains", + "bp-polkadot-core", "bp-runtime", - "ed25519-dalek", "frame-support", "frame-system", "hash-db", + "log", + "millau-runtime", + "num-traits", "pallet-balances", - "pallet-bridge-dispatch", "pallet-bridge-grandpa", "pallet-bridge-messages", + "pallet-bridge-parachains", "pallet-transaction-payment", + "pallet-xcm", "parity-scale-codec", "scale-info", "sp-api", "sp-core", + "sp-io", "sp-runtime", "sp-state-machine", "sp-std", "sp-trie", "sp-version", "static_assertions", + "xcm", + "xcm-builder", + "xcm-executor", ] [[package]] @@ -1052,19 +1017,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - -[[package]] -name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "bzip2-sys" @@ -1103,9 +1058,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", @@ -1158,21 +1113,21 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chacha20" -version = "0.7.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee7ad89dc1128635074c268ee661f90c3f7e83d9fd12910608c36b47d6c3412" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if 1.0.0", "cipher", - "cpufeatures 0.1.5", + "cpufeatures", "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580317203210c517b6d44794abfbe600698276db18127e37ad3e69bf5e848e5" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ "aead", "chacha20", @@ -1191,18 +1146,20 @@ dependencies = [ "num-integer", "num-traits", "time 0.1.44", - "winapi 0.3.9", + "winapi", ] [[package]] name = "cid" -version = "0.6.1" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff0e3bc0b6446b3f9663c1a6aba6ef06c5aeaa1bc92bd18077be337198ab9768" +checksum = "f6ed9c8b2d17acb8110c46f1da5bf4a696d745e1474a16db0cd2b49cd0249bf2" dependencies = [ + "core2", "multibase", - "multihash 0.13.2", - "unsigned-varint 0.5.1", + "multihash", + "serde", + "unsigned-varint", ] [[package]] @@ -1251,16 +1208,16 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.6" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +checksum = "b15f2ea93df33549dbe2e8eecd1ca55269d63ae0b3ba1f55db030817d1c2867f" dependencies = [ "atty", "bitflags", "clap_derive", + "clap_lex", "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", "strsim 0.10.0", "termcolor", "textwrap 0.15.0", @@ -1268,9 +1225,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.1.4" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -1279,6 +1236,47 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "coarsetime" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "454038500439e141804c655b4cd1bc6a70bcb95cd2bc9463af5661b6956f0e46" +dependencies = [ + "libc", + "once_cell", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "comfy-table" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85914173c2f558d61613bfbbf1911f14e630895087a7ed2fafc0f5319e1536e7" +dependencies = [ + "strum 0.24.1", + "strum_macros 0.24.0", + "unicode-width", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -1323,21 +1321,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] -name = "cpp_demangle" -version = "0.3.4" +name = "core2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931ab2a3e6330a07900b8e7ca4e106cdcbb93f2b9a52df55e54ee53d8305b55d" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" dependencies = [ - "cfg-if 1.0.0", + "memchr", ] [[package]] -name = "cpufeatures" -version = "0.1.5" +name = "cpp_demangle" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "931ab2a3e6330a07900b8e7ca4e106cdcbb93f2b9a52df55e54ee53d8305b55d" dependencies = [ - "libc", + "cfg-if 1.0.0", ] [[package]] @@ -1351,59 +1349,60 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9516ba6b2ba47b4cbf63b713f75b432fafa0a0e0464ec8381ec76e6efe931ab3" +checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489e5d0081f7edff6be12d71282a8bf387b5df64d5592454b75d662397f2d642" +checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", "cranelift-entity", + "cranelift-isle", "gimli", "log", - "regalloc", + "regalloc2", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36ee1140371bb0f69100e734b30400157a4adf7b86148dee8b0a438763ead48" +checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "981da52d8f746af1feb96290c83977ff8d41071a7499e991d8abae0d4869f564" +checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2" [[package]] name = "cranelift-entity" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2906740053dd3bcf95ce53df0fd9b5649c68ae4bd9adada92b406f059eae461" +checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cb156de1097f567d46bf57a0cd720a72c3e15e1a2bd8b1041ba2fc894471b7" +checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c" dependencies = [ "cranelift-codegen", "log", @@ -1411,11 +1410,17 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-isle" +version = "0.85.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b" + [[package]] name = "cranelift-native" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166028ca0343a6ee7bddac0e70084e142b23f99c701bd6f6ea9123afac1a7a46" +checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6" dependencies = [ "cranelift-codegen", "libc", @@ -1424,9 +1429,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.80.0" +version = "0.85.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5012a1cde0c8b3898770b711490d803018ae9bec2d60674ba0e5b2058a874f80" +checksum = "31a46513ae6f26f3f267d8d75b5373d555fbbd1e68681f348d99df43f747ec54" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1481,6 +1486,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.5" @@ -1539,15 +1554,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ct-logs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" -dependencies = [ - "sct 0.6.1", -] - [[package]] name = "ctor" version = "0.1.21" @@ -1581,26 +1587,30 @@ dependencies = [ [[package]] name = "cumulus-client-cli" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ - "clap 3.1.6", + "clap 3.2.18", + "parity-scale-codec", + "sc-chain-spec", "sc-cli", "sc-service", - "url 2.2.2", + "sp-core", + "sp-runtime", + "url", ] [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", "cumulus-primitives-core", "cumulus-relay-chain-interface", - "futures 0.3.21", + "futures", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", @@ -1616,12 +1626,12 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-aura" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "async-trait", "cumulus-client-consensus-common", "cumulus-primitives-core", - "futures 0.3.21", + "futures", "parity-scale-codec", "sc-client-api", "sc-consensus", @@ -1645,12 +1655,12 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "async-trait", "cumulus-relay-chain-interface", "dyn-clone", - "futures 0.3.21", + "futures", "parity-scale-codec", "polkadot-primitives", "sc-client-api", @@ -1666,15 +1676,15 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "async-trait", "cumulus-relay-chain-interface", "derive_more", - "futures 0.3.21", + "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-parachain", "polkadot-primitives", @@ -1691,11 +1701,11 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", - "futures 0.3.21", + "futures", "futures-timer", "parity-scale-codec", "polkadot-node-primitives", @@ -1715,7 +1725,7 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-client-cli", "cumulus-client-collator", @@ -1723,11 +1733,9 @@ dependencies = [ "cumulus-client-pov-recovery", "cumulus-primitives-core", "cumulus-relay-chain-interface", - "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-overseer", "polkadot-primitives", - "sc-chain-spec", "sc-client-api", "sc-consensus", "sc-consensus-babe", @@ -1745,7 +1753,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-aura-ext" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "frame-executive", "frame-support", @@ -1763,7 +1771,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1781,8 +1789,9 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ + "bytes", "cumulus-pallet-parachain-system-proc-macro", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", @@ -1811,9 +1820,9 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -1822,7 +1831,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1839,15 +1848,17 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", "log", "parity-scale-codec", + "polkadot-runtime-common", "rand_chacha 0.3.1", "scale-info", + "sp-io", "sp-runtime", "sp-std", "xcm", @@ -1857,7 +1868,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "frame-support", "parity-scale-codec", @@ -1873,7 +1884,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1896,10 +1907,10 @@ dependencies = [ [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", - "futures 0.3.21", + "futures", "parity-scale-codec", "sp-inherents", "sp-std", @@ -1909,37 +1920,43 @@ dependencies = [ [[package]] name = "cumulus-primitives-utility" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "frame-support", + "log", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-primitives", + "polkadot-runtime-common", + "sp-io", "sp-runtime", "sp-std", "sp-trie", "xcm", + "xcm-builder", + "xcm-executor", ] [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "async-trait", "cumulus-primitives-core", "cumulus-relay-chain-interface", - "futures 0.3.21", + "futures", "futures-timer", - "parking_lot 0.12.0", + "polkadot-cli", "polkadot-client", "polkadot-service", + "sc-cli", "sc-client-api", "sc-consensus-babe", "sc-network", - "sc-service", + "sc-sysinfo", "sc-telemetry", "sc-tracing", "sp-api", @@ -1954,19 +1971,18 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "async-trait", "cumulus-primitives-core", "derive_more", - "futures 0.3.21", - "jsonrpsee-core 0.9.0", + "futures", + "jsonrpsee-core", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-overseer", "polkadot-service", "sc-client-api", - "sc-service", "sp-api", "sp-blockchain", "sp-core", @@ -1978,7 +1994,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "parity-scale-codec", @@ -1999,8 +2015,8 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "socket2 0.4.4", - "winapi 0.3.9", + "socket2", + "winapi", ] [[package]] @@ -2016,7 +2032,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2045,6 +2061,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "data-encoding" version = "2.3.2" @@ -2160,7 +2189,7 @@ checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2171,7 +2200,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2198,9 +2227,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "0.4.8" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +checksum = "c6053ff46b5639ceb91756a85a4c8914668393a03170efd79c8884a529d80656" [[package]] name = "dyn-clonable" @@ -2225,9 +2254,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" [[package]] name = "ecdsa" @@ -2237,6 +2266,7 @@ checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" dependencies = [ "der", "elliptic-curve", + "rfc6979", "signature", ] @@ -2263,6 +2293,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek 3.2.0", + "hex", + "rand_core 0.6.3", + "sha2 0.9.8", + "thiserror", + "zeroize", +] + [[package]] name = "either" version = "1.6.1" @@ -2298,11 +2342,11 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" dependencies = [ - "heck 0.3.3", + "heck 0.4.0", "proc-macro2", "quote", "syn", @@ -2310,18 +2354,18 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.6.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.6.4" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ "proc-macro2", "quote", @@ -2330,9 +2374,9 @@ dependencies = [ [[package]] name = "enumn" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e58b112d5099aa0857c5d05f0eacab86406dd8c0f85fe5d320a13256d29ecf4" +checksum = "038b1afa59052df211f9efd58f8b1d84c242935ede1c3dbaed26b018a9e06ae2" dependencies = [ "proc-macro2", "quote", @@ -2392,7 +2436,7 @@ checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2406,7 +2450,34 @@ dependencies = [ ] [[package]] -name = "event-listener" +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "event-listener" version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" @@ -2417,7 +2488,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.21", + "futures", ] [[package]] @@ -2426,7 +2497,7 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" dependencies = [ - "blake3 1.3.1", + "blake3", "fs-err", "proc-macro2", "quote", @@ -2438,10 +2509,11 @@ version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6" dependencies = [ - "blake2 0.10.4", + "blake2", "fs-err", "proc-macro2", "quote", + "syn", ] [[package]] @@ -2458,9 +2530,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.5.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -2483,7 +2555,7 @@ checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" dependencies = [ "expander 0.0.4", "indexmap", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -2519,19 +2591,31 @@ dependencies = [ "log", ] +[[package]] +name = "filetime" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "windows-sys 0.36.1", +] + [[package]] name = "finality-grandpa" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9def033d8505edf199f6a5d07aa7e6d2d6185b164293b77f0efd108f4f3e11d" +checksum = "b22349c6a11563a202d95772a68e0fcf56119e74ea8a2a19cf2301460fcd0df5" dependencies = [ "either", - "futures 0.3.21", + "futures", "futures-timer", "log", "num-traits", "parity-scale-codec", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "scale-info", ] @@ -2543,7 +2627,7 @@ dependencies = [ "async-trait", "backoff", "bp-header-chain", - "futures 0.3.21", + "futures", "log", "num-traits", "parking_lot 0.11.2", @@ -2590,7 +2674,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", ] @@ -2602,13 +2686,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -2620,6 +2704,7 @@ dependencies = [ "serde", "sp-api", "sp-application-crypto", + "sp-core", "sp-io", "sp-runtime", "sp-runtime-interface", @@ -2630,28 +2715,35 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "Inflector", "chrono", - "clap 3.1.6", + "clap 3.2.18", + "comfy-table", "frame-benchmarking", "frame-support", + "frame-system", + "gethostname", "handlebars", "hash-db", "hex", "itertools", "kvdb", + "lazy_static", "linked-hash-map", "log", "memory-db", "parity-scale-codec", "rand 0.8.5", + "rand_pcg 0.3.1", + "sc-block-builder", "sc-cli", "sc-client-api", "sc-client-db", "sc-executor", "sc-service", + "sc-sysinfo", "serde", "serde_json", "serde_nanos", @@ -2660,19 +2752,34 @@ dependencies = [ "sp-core", "sp-database", "sp-externalities", + "sp-inherents", "sp-keystore", "sp-runtime", "sp-state-machine", - "sp-std", "sp-storage", "sp-trie", + "tempfile", + "thiserror", + "thousands", +] + +[[package]] +name = "frame-election-provider-solution-type" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ + "frame-election-provider-solution-type", "frame-support", "frame-system", "parity-scale-codec", @@ -2686,7 +2793,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -2714,12 +2821,13 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "bitflags", "frame-metadata", "frame-support-procedural", "impl-trait-for-tuples", + "k256", "log", "once_cell", "parity-scale-codec", @@ -2727,6 +2835,7 @@ dependencies = [ "scale-info", "serde", "smallvec", + "sp-api", "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", @@ -2743,7 +2852,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -2755,10 +2864,10 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -2767,7 +2876,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "proc-macro2", "quote", @@ -2777,7 +2886,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "log", @@ -2794,7 +2903,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -2809,7 +2918,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "sp-api", @@ -2818,7 +2927,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "sp-api", @@ -2841,7 +2950,7 @@ dependencies = [ "lazy_static", "libc", "libloading 0.5.2", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2851,7 +2960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2860,22 +2969,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "funty" version = "2.0.0" @@ -2884,15 +2977,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.1.31" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - -[[package]] -name = "futures" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" dependencies = [ "futures-channel", "futures-core", @@ -2905,9 +2992,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", "futures-sink", @@ -2915,15 +3002,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" dependencies = [ "futures-core", "futures-task", @@ -2933,9 +3020,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-lite" @@ -2948,15 +3035,15 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -2965,26 +3052,26 @@ dependencies = [ [[package]] name = "futures-rustls" -version = "0.21.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1387e07917c711fb4ee4f48ea0adb04a3c9739e53ef85bf43ae1edc2937a8b" +checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.19.1", - "webpki 0.21.4", + "rustls", + "webpki", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-timer" @@ -2994,11 +3081,10 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ - "futures 0.1.31", "futures-channel", "futures-core", "futures-io", @@ -3006,11 +3092,20 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", "pin-utils", "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -3030,6 +3125,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -3124,7 +3229,7 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -3133,15 +3238,15 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.6.9", "tracing", ] [[package]] name = "handlebars" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25546a65e5cf1f471f3438796fc634650b31d7fcde01d444c309aeb28b92e3a8" +checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" dependencies = [ "log", "pest", @@ -3177,9 +3282,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] @@ -3276,18 +3381,18 @@ checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" dependencies = [ "libc", "match_cfg", - "winapi 0.3.9", + "winapi", ] [[package]] name = "http" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", - "itoa 0.4.8", + "itoa 1.0.1", ] [[package]] @@ -3296,9 +3401,9 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" dependencies = [ - "bytes 1.1.0", + "bytes", "http", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", ] [[package]] @@ -3334,7 +3439,7 @@ version = "0.14.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -3344,8 +3449,8 @@ dependencies = [ "httparse", "httpdate", "itoa 0.4.8", - "pin-project-lite 0.2.7", - "socket2 0.4.4", + "pin-project-lite 0.2.9", + "socket2", "tokio", "tower-service", "tracing", @@ -3354,30 +3459,17 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ - "ct-logs", - "futures-util", + "http", "hyper", "log", - "rustls 0.19.1", - "rustls-native-certs 0.5.0", + "rustls", + "rustls-native-certs", "tokio", - "tokio-rustls 0.22.0", - "webpki 0.21.4", -] - -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "tokio-rustls", ] [[package]] @@ -3393,39 +3485,30 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2273e421f7c4f0fc99e1934fe4776f59d8df2972f4199d703fc0da9f2a9f73de" -dependencies = [ - "if-addrs-sys", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "if-addrs-sys" -version = "0.3.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de74b9dd780476e837e5eb5ab7c88b49ed304126e412030a0adba99c8efe79ea" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" dependencies = [ - "cc", "libc", + "winapi", ] [[package]] name = "if-watch" -version = "0.2.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8ab7f67bad3240049cb24fb9cb0b4c2c6af4c245840917fbbdededeee91179" +checksum = "015a7df1eb6dda30df37f34b63ada9b7b352984b0e84de2a20ed526345000791" dependencies = [ "async-io", - "futures 0.3.21", - "futures-lite", + "core-foundation", + "fnv", + "futures", "if-addrs", "ipnet", - "libc", "log", - "winapi 0.3.9", + "rtnetlink", + "system-configuration", + "windows", ] [[package]] @@ -3437,6 +3520,15 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + [[package]] name = "impl-serde" version = "0.3.2" @@ -3459,12 +3551,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown 0.12.3", "serde", ] @@ -3494,21 +3586,15 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.4.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ef6787e7f0faedc040f95716bdd0e62bcfcf4ba93da053b62dea2691c13864" -dependencies = [ - "winapi 0.3.9", -] +checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" [[package]] -name = "iovec" -version = "0.1.4" +name = "io-lifetimes" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] +checksum = "1ea37f355c05dde75b84bba2d767906ad522e97cd9e2eef2be7a4ab7fb442c06" [[package]] name = "ip_network" @@ -3518,13 +3604,13 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" dependencies = [ - "socket2 0.3.19", + "socket2", "widestring", - "winapi 0.3.9", + "winapi", "winreg", ] @@ -3557,7 +3643,7 @@ dependencies = [ "sluice", "tracing", "tracing-futures", - "url 2.2.2", + "url", "waker-fn", ] @@ -3613,29 +3699,13 @@ dependencies = [ "serde_json", ] -[[package]] -name = "jsonrpc-client-transports" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" -dependencies = [ - "derive_more", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-pubsub", - "log", - "serde", - "serde_json", - "url 1.7.2", -] - [[package]] name = "jsonrpc-core" version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.21", + "futures", "futures-executor", "futures-util", "log", @@ -3644,165 +3714,63 @@ dependencies = [ "serde_json", ] -[[package]] -name = "jsonrpc-core-client" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" -dependencies = [ - "futures 0.3.21", - "jsonrpc-client-transports", -] - -[[package]] -name = "jsonrpc-derive" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" -dependencies = [ - "proc-macro-crate 0.1.5", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jsonrpc-http-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" -dependencies = [ - "futures 0.3.21", - "hyper", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "net2", - "parking_lot 0.11.2", - "unicase", -] - -[[package]] -name = "jsonrpc-ipc-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "parity-tokio-ipc", - "parking_lot 0.11.2", - "tower-service", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "lazy_static", - "log", - "parking_lot 0.11.2", - "rand 0.7.3", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" -dependencies = [ - "bytes 1.1.0", - "futures 0.3.21", - "globset", - "jsonrpc-core", - "lazy_static", - "log", - "tokio", - "tokio-stream", - "tokio-util", - "unicase", -] - -[[package]] -name = "jsonrpc-ws-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f892c7d766369475ab7b0669f417906302d7c0fb521285c0a0c92e52e7c8e946" -dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "parity-ws", - "parking_lot 0.11.2", - "slab", -] - -[[package]] -name = "jsonrpsee" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" -dependencies = [ - "jsonrpsee-types 0.4.1", - "jsonrpsee-utils", - "jsonrpsee-ws-client 0.4.1", -] - [[package]] name = "jsonrpsee" -version = "0.8.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05fd8cd6c6b1bbd06881d2cf88f1fc83cc36c98f2219090f839115fb4a956cb9" +checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a" dependencies = [ - "jsonrpsee-core 0.8.0", + "jsonrpsee-core", + "jsonrpsee-http-server", "jsonrpsee-proc-macros", - "jsonrpsee-types 0.8.0", - "jsonrpsee-ws-client 0.8.0", + "jsonrpsee-types", + "jsonrpsee-ws-client", + "jsonrpsee-ws-server", + "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.8.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3303cdf246e6ab76e2866fb3d9acb6c76a068b1b28bd923a1b7a8122257ad7b5" +checksum = "8752740ecd374bcbf8b69f3e80b0327942df76f793f8d4e60d3355650c31fb74" dependencies = [ - "futures 0.3.21", + "futures-util", "http", - "jsonrpsee-core 0.8.0", - "jsonrpsee-types 0.8.0", - "pin-project 1.0.10", - "rustls-native-certs 0.6.1", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "rustls-native-certs", "soketto", "thiserror", "tokio", - "tokio-rustls 0.23.2", - "tokio-util", + "tokio-rustls", + "tokio-util 0.7.1", "tracing", - "webpki-roots 0.22.2", + "webpki-roots", ] [[package]] name = "jsonrpsee-core" -version = "0.8.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f220b5a238dc7992b90f1144fbf6eaa585872c9376afe6fe6863ffead6191bf3" +checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca" dependencies = [ "anyhow", "arrayvec 0.7.2", + "async-lock", "async-trait", "beef", "futures-channel", + "futures-timer", "futures-util", + "globset", + "http", "hyper", - "jsonrpsee-types 0.8.0", + "jsonrpsee-types", + "lazy_static", + "parking_lot 0.12.1", + "rand 0.8.5", "rustc-hash", "serde", "serde_json", @@ -3810,34 +3778,35 @@ dependencies = [ "thiserror", "tokio", "tracing", + "tracing-futures", + "unicase", ] [[package]] -name = "jsonrpsee-core" -version = "0.9.0" +name = "jsonrpsee-http-server" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22abc3274b265dcefe2e26c4beecf9fda4fffa48cf94930443a6c73678f020d5" +checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117" dependencies = [ - "anyhow", - "arrayvec 0.7.2", - "async-trait", - "beef", "futures-channel", + "futures-util", "hyper", - "jsonrpsee-types 0.9.0", + "jsonrpsee-core", + "jsonrpsee-types", "serde", "serde_json", - "soketto", - "thiserror", + "tokio", + "tracing", + "tracing-futures", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.8.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4299ebf790ea9de1cb72e73ff2ae44c723ef264299e5e2d5ef46a371eb3ac3d8" +checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -3845,42 +3814,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f778cf245158fbd8f5d50823a2e9e4c708a40be164766bd35e9fb1d86715b2" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-channel", - "futures-util", - "hyper", - "log", - "serde", - "serde_json", - "soketto", - "thiserror", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b3f601bbbe45cd63f5407b6f7d7950e08a7d4f82aa699ff41a4a5e9e54df58" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.9.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f4c45d2e2aa1db4c7d7d7dbaabc10a5b5258d99cd9d42fbfd5260b76f80c324" +checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d" dependencies = [ "anyhow", "beef", @@ -3891,56 +3827,42 @@ dependencies = [ ] [[package]] -name = "jsonrpsee-utils" -version = "0.4.1" +name = "jsonrpsee-ws-client" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" +checksum = "6ee5feddd5188e62ac08fcf0e56478138e581509d4730f3f7be9b57dd402a4ff" dependencies = [ - "arrayvec 0.7.2", - "beef", - "jsonrpsee-types 0.4.1", + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", ] [[package]] -name = "jsonrpsee-ws-client" -version = "0.4.1" +name = "jsonrpsee-ws-server" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559aa56fc402af206c00fc913dc2be1d9d788dcde045d14df141a535245d35ef" +checksum = "d488ba74fb369e5ab68926feb75a483458b88e768d44319f37e4ecad283c7325" dependencies = [ - "arrayvec 0.7.2", - "async-trait", - "fnv", - "futures 0.3.21", + "futures-channel", + "futures-util", "http", - "jsonrpsee-types 0.4.1", - "log", - "pin-project 1.0.10", - "rustls-native-certs 0.5.0", - "serde", + "jsonrpsee-core", + "jsonrpsee-types", "serde_json", "soketto", - "thiserror", "tokio", - "tokio-rustls 0.22.0", - "tokio-util", -] - -[[package]] -name = "jsonrpsee-ws-client" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff425cee7c779e33920913bc695447416078ee6d119f443f3060feffa4e86b5" -dependencies = [ - "jsonrpsee-client-transport", - "jsonrpsee-core 0.8.0", - "jsonrpsee-types 0.8.0", + "tokio-stream", + "tokio-util 0.7.1", + "tracing", + "tracing-futures", ] [[package]] name = "k256" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "587f53e46eb6dc82b53cda7ebf3ae3ad568ed987ced60962fc845f7fe22904e3" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" dependencies = [ "cfg-if 1.0.0", "ecdsa", @@ -3954,20 +3876,10 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "kusama-runtime" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "beefy-primitives", "bitvec", @@ -3985,6 +3897,7 @@ dependencies = [ "pallet-bags-list", "pallet-balances", "pallet-bounties", + "pallet-child-bounties", "pallet-collective", "pallet-democracy", "pallet-election-provider-multi-phase", @@ -3995,9 +3908,9 @@ dependencies = [ "pallet-im-online", "pallet-indices", "pallet-membership", - "pallet-mmr-primitives", "pallet-multisig", - "pallet-nicks", + "pallet-nomination-pools", + "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-preimage", "pallet-proxy", @@ -4032,6 +3945,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-io", + "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", @@ -4049,8 +3963,8 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-support", "polkadot-primitives", @@ -4086,14 +4000,14 @@ checksum = "ece7e668abd21387aeb6628130a6f4c802787f014fa46bc83221448322250357" dependencies = [ "kvdb", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", ] [[package]] name = "kvdb-rocksdb" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e72a631a32527fafe22d0751c002e67d28173c49dcaecf79d1aaa323c520e9" +checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" dependencies = [ "fs-swap", "kvdb", @@ -4101,7 +4015,7 @@ dependencies = [ "num_cpus", "owning_ref", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "regex", "rocksdb", "smallvec", @@ -4121,9 +4035,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.120" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libloading" @@ -4132,7 +4046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" dependencies = [ "cc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4142,7 +4056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" dependencies = [ "cfg-if 1.0.0", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4163,14 +4077,17 @@ dependencies = [ [[package]] name = "libp2p" -version = "0.40.0" +version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bec54343492ba5940a6c555e512c6721139835d28c59bc22febece72dfd0d9d" +checksum = "81327106887e42d004fbdab1fef93675be2e2e07c1b95fce45e2cc813485611d" dependencies = [ - "atomic", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", + "futures-timer", + "getrandom 0.2.3", + "instant", "lazy_static", + "libp2p-autonat", "libp2p-core", "libp2p-deflate", "libp2p-dns", @@ -4196,81 +4113,101 @@ dependencies = [ "libp2p-websocket", "libp2p-yamux", "multiaddr", - "parking_lot 0.11.2", - "pin-project 1.0.10", + "parking_lot 0.12.1", + "pin-project", + "rand 0.7.3", "smallvec", - "wasm-timer", +] + +[[package]] +name = "libp2p-autonat" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4decc51f3573653a9f4ecacb31b1b922dd20c25a6322bb15318ec04287ec46f9" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "instant", + "libp2p-core", + "libp2p-request-response", + "libp2p-swarm", + "log", + "prost", + "prost-build", + "rand 0.8.5", ] [[package]] name = "libp2p-core" -version = "0.30.2" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86aad7d54df283db817becded03e611137698a6509d4237a96881976a162340c" +checksum = "fbf9b94cefab7599b2d3dff2f93bee218c6621d68590b23ede4485813cbcece6" dependencies = [ "asn1_der", "bs58", "ed25519-dalek", "either", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "instant", "lazy_static", "libsecp256k1", "log", "multiaddr", - "multihash 0.14.0", + "multihash", "multistream-select", - "parking_lot 0.11.2", - "pin-project 1.0.10", + "parking_lot 0.12.1", + "pin-project", "prost", "prost-build", "rand 0.8.5", "ring", "rw-stream-sink", - "sha2 0.9.8", + "sha2 0.10.2", "smallvec", "thiserror", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", "zeroize", ] [[package]] name = "libp2p-deflate" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51a800adb195f33de63f4b17b63fe64cfc23bf2c6a0d3d0d5321328664e65197" +checksum = "d0183dc2a3da1fbbf85e5b6cf51217f55b14f5daea0c455a9536eef646bfec71" dependencies = [ "flate2", - "futures 0.3.21", + "futures", "libp2p-core", ] [[package]] name = "libp2p-dns" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8f89d15cb6e3c5bc22afff7513b11bab7856f2872d3cfba86f7f63a06bc498" +checksum = "6cbf54723250fa5d521383be789bf60efdabe6bacfb443f87da261019a49b4b5" dependencies = [ "async-std-resolver", - "futures 0.3.21", + "futures", "libp2p-core", "log", + "parking_lot 0.12.1", "smallvec", "trust-dns-resolver", ] [[package]] name = "libp2p-floodsub" -version = "0.31.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab3d7210901ea51b7bae2b581aa34521797af8c4ec738c980bda4a06434067f" +checksum = "98a4b6ffd53e355775d24b76f583fdda54b3284806f678499b57913adb94f231" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.21", + "futures", "libp2p-core", "libp2p-swarm", "log", @@ -4282,83 +4219,91 @@ dependencies = [ [[package]] name = "libp2p-gossipsub" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfeead619eb5dac46e65acc78c535a60aaec803d1428cca6407c3a4fc74d698d" +checksum = "74b4b888cfbeb1f5551acd3aa1366e01bf88ede26cc3c4645d0d2d004d5ca7b0" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "base64", "byteorder", - "bytes 1.1.0", + "bytes", "fnv", - "futures 0.3.21", + "futures", "hex_fmt", + "instant", "libp2p-core", "libp2p-swarm", "log", + "prometheus-client", "prost", "prost-build", "rand 0.7.3", "regex", - "sha2 0.9.8", + "sha2 0.10.2", "smallvec", - "unsigned-varint 0.7.1", + "unsigned-varint", "wasm-timer", ] [[package]] name = "libp2p-identify" -version = "0.31.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca1275574183f288ff8b72d535d5ffa5ea9292ef7829af8b47dcb197c7b0dcd" +checksum = "c50b585518f8efd06f93ac2f976bd672e17cdac794644b3117edd078e96bda06" dependencies = [ - "futures 0.3.21", + "asynchronous-codec", + "futures", + "futures-timer", "libp2p-core", "libp2p-swarm", "log", - "lru 0.6.6", + "lru 0.7.8", "prost", "prost-build", + "prost-codec", "smallvec", - "wasm-timer", + "thiserror", + "void", ] [[package]] name = "libp2p-kad" -version = "0.32.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2297dc0ca285f3a09d1368bde02449e539b46f94d32d53233f53f6625bcd3ba" +checksum = "740862893bb5f06ac24acc9d49bdeadc3a5e52e51818a30a25c1f3519da2c851" dependencies = [ - "arrayvec 0.5.2", - "asynchronous-codec 0.6.0", - "bytes 1.1.0", + "arrayvec 0.7.2", + "asynchronous-codec", + "bytes", "either", "fnv", - "futures 0.3.21", + "futures", + "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log", "prost", "prost-build", "rand 0.7.3", - "sha2 0.9.8", + "sha2 0.10.2", "smallvec", + "thiserror", "uint", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", - "wasm-timer", ] [[package]] name = "libp2p-mdns" -version = "0.32.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c864b64bdc8a84ff3910a0df88e6535f256191a450870f1e7e10cbf8e64d45" +checksum = "66e5e5919509603281033fd16306c61df7a4428ce274b67af5e14b07de5cdcb2" dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.21", + "futures", "if-watch", "lazy_static", "libp2p-core", @@ -4366,58 +4311,60 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.4.4", + "socket2", "void", ] [[package]] name = "libp2p-metrics" -version = "0.1.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4af432fcdd2f8ba4579b846489f8f0812cfd738ced2c0af39df9b1c48bbb6ab2" +checksum = "ef8aff4a1abef42328fbb30b17c853fff9be986dc39af17ee39f9c5f755c5e0c" dependencies = [ "libp2p-core", + "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-ping", + "libp2p-relay", "libp2p-swarm", - "open-metrics-client", + "prometheus-client", ] [[package]] name = "libp2p-mplex" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2cd64ef597f40e14bfce0497f50ecb63dd6d201c61796daeb4227078834fbf" +checksum = "61fd1b20638ec209c5075dfb2e8ce6a7ea4ec3cd3ad7b77f7a477c06d53322e2" dependencies = [ - "asynchronous-codec 0.6.0", - "bytes 1.1.0", - "futures 0.3.21", + "asynchronous-codec", + "bytes", + "futures", "libp2p-core", "log", "nohash-hasher", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "rand 0.7.3", "smallvec", - "unsigned-varint 0.7.1", + "unsigned-varint", ] [[package]] name = "libp2p-noise" -version = "0.33.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8772c7a99088221bb7ca9c5c0574bf55046a7ab4c319f3619b275f28c8fb87a" +checksum = "762408cb5d84b49a600422d7f9a42c18012d8da6ebcd570f9a4a4290ba41fb6f" dependencies = [ - "bytes 1.1.0", + "bytes", "curve25519-dalek 3.2.0", - "futures 0.3.21", + "futures", "lazy_static", "libp2p-core", "log", "prost", "prost-build", "rand 0.8.5", - "sha2 0.9.8", + "sha2 0.10.2", "snow", "static_assertions", "x25519-dalek", @@ -4426,33 +4373,34 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.31.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ef7b0ec5cf06530d9eb6cf59ae49d46a2c45663bde31c25a12f682664adbcf" +checksum = "100a6934ae1dbf8a693a4e7dd1d730fd60b774dafc45688ed63b554497c6c925" dependencies = [ - "futures 0.3.21", + "futures", + "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log", "rand 0.7.3", "void", - "wasm-timer", ] [[package]] name = "libp2p-plaintext" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fba1a6ff33e4a274c89a3b1d78b9f34f32af13265cc5c46c16938262d4e945a" +checksum = "be27bf0820a6238a4e06365b096d428271cce85a129cf16f2fe9eb1610c4df86" dependencies = [ - "asynchronous-codec 0.6.0", - "bytes 1.1.0", - "futures 0.3.21", + "asynchronous-codec", + "bytes", + "futures", "libp2p-core", "log", "prost", "prost-build", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", ] @@ -4462,9 +4410,9 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1a458bbda880107b5b36fcb9b5a1ef0c329685da0e203ed692a8ebe64cc92c" dependencies = [ - "futures 0.3.21", + "futures", "log", - "pin-project 1.0.10", + "pin-project", "rand 0.7.3", "salsa20", "sha3 0.9.1", @@ -4472,89 +4420,96 @@ dependencies = [ [[package]] name = "libp2p-relay" -version = "0.4.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2852b61c90fa8ce3c8fcc2aba76e6cefc20d648f9df29157d6b3a916278ef3e3" +checksum = "4931547ee0cce03971ccc1733ff05bb0c4349fd89120a39e9861e2bbe18843c3" dependencies = [ - "asynchronous-codec 0.6.0", - "bytes 1.1.0", - "futures 0.3.21", + "asynchronous-codec", + "bytes", + "either", + "futures", "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log", - "pin-project 1.0.10", + "pin-project", "prost", "prost-build", - "rand 0.7.3", + "prost-codec", + "rand 0.8.5", "smallvec", - "unsigned-varint 0.7.1", + "static_assertions", + "thiserror", "void", - "wasm-timer", ] [[package]] name = "libp2p-rendezvous" -version = "0.1.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14a6d2b9e7677eff61dc3d2854876aaf3976d84a01ef6664b610c77a0c9407c5" +checksum = "9511c9672ba33284838e349623319c8cad2d18cfad243ae46c6b7e8a2982ea4e" dependencies = [ - "asynchronous-codec 0.6.0", + "asynchronous-codec", "bimap", - "futures 0.3.21", + "futures", + "futures-timer", + "instant", "libp2p-core", "libp2p-swarm", "log", "prost", "prost-build", "rand 0.8.5", - "sha2 0.9.8", + "sha2 0.10.2", "thiserror", - "unsigned-varint 0.7.1", + "unsigned-varint", "void", - "wasm-timer", ] [[package]] name = "libp2p-request-response" -version = "0.13.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a877a4ced6d46bf84677e1974e8cf61fb434af73b2e96fb48d6cb6223a4634d8" +checksum = "508a189e2795d892c8f5c1fa1e9e0b1845d32d7b0b249dbf7b05b18811361843" dependencies = [ "async-trait", - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", + "instant", "libp2p-core", "libp2p-swarm", "log", - "lru 0.7.3", "rand 0.7.3", "smallvec", - "unsigned-varint 0.7.1", - "wasm-timer", + "unsigned-varint", ] [[package]] name = "libp2p-swarm" -version = "0.31.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5184a508f223bc100a12665517773fb8730e9f36fc09eefb670bf01b107ae9" +checksum = "95ac5be6c2de2d1ff3f7693fda6faf8a827b1f3e808202277783fea9f527d114" dependencies = [ "either", - "futures 0.3.21", + "fnv", + "futures", + "futures-timer", + "instant", "libp2p-core", "log", + "pin-project", "rand 0.7.3", "smallvec", + "thiserror", "void", - "wasm-timer", ] [[package]] name = "libp2p-swarm-derive" -version = "0.25.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "072c290f727d39bdc4e9d6d1c847978693d25a673bd757813681e33e5f6c00c2" +checksum = "9f54a64b6957249e0ce782f8abf41d97f69330d02bf229f0672d864f0650cc76" dependencies = [ "quote", "syn", @@ -4562,40 +4517,40 @@ dependencies = [ [[package]] name = "libp2p-tcp" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7399c5b6361ef525d41c11fcf51635724f832baf5819b30d3d873eabb4fbae4b" +checksum = "8a6771dc19aa3c65d6af9a8c65222bfc8fcd446630ddca487acd161fa6096f3b" dependencies = [ "async-io", - "futures 0.3.21", + "futures", "futures-timer", "if-watch", "ipnet", "libc", "libp2p-core", "log", - "socket2 0.4.4", + "socket2", ] [[package]] name = "libp2p-uds" -version = "0.30.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7563e46218165dfd60f64b96f7ce84590d75f53ecbdc74a7dd01450dc5973" +checksum = "d125e3e5f0d58f3c6ac21815b20cf4b6a88b8db9dc26368ea821838f4161fd4d" dependencies = [ "async-std", - "futures 0.3.21", + "futures", "libp2p-core", "log", ] [[package]] name = "libp2p-wasm-ext" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1008a302b73c5020251f9708c653f5ed08368e530e247cc9cd2f109ff30042cf" +checksum = "ec894790eec3c1608f8d1a8a0bdf0dbeb79ed4de2dce964222011c2896dfa05a" dependencies = [ - "futures 0.3.21", + "futures", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -4605,31 +4560,32 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.31.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e12df82d1ed64969371a9e65ea92b91064658604cc2576c2757f18ead9a1cf" +checksum = "9808e57e81be76ff841c106b4c5974fb4d41a233a7bdd2afbf1687ac6def3818" dependencies = [ "either", - "futures 0.3.21", + "futures", "futures-rustls", "libp2p-core", "log", + "parking_lot 0.12.1", "quicksink", "rw-stream-sink", "soketto", - "url 2.2.2", - "webpki-roots 0.21.1", + "url", + "webpki-roots", ] [[package]] name = "libp2p-yamux" -version = "0.34.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7362abb8867d7187e7e93df17f460d554c997fc5c8ac57dc1259057f6889af" +checksum = "c6dea686217a06072033dc025631932810e2f6ad784e4fafa42e27d311c7a81c" dependencies = [ - "futures 0.3.21", + "futures", "libp2p-core", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "thiserror", "yamux", ] @@ -4736,9 +4692,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.0.36" +version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a261afc61b7a5e323933b402ca6a1765183687c614789b1e4db7762ed4230bca" +checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" + +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" [[package]] name = "lock_api" @@ -4751,9 +4713,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", "value-bag", @@ -4770,11 +4732,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.3" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" dependencies = [ - "hashbrown 0.11.2", + "hashbrown 0.12.3", ] [[package]] @@ -4857,6 +4819,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memfd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a" +dependencies = [ + "libc", +] + [[package]] name = "memmap" version = "0.7.0" @@ -4864,7 +4835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4901,7 +4872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" dependencies = [ "hash-db", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "parity-util-mem", ] @@ -4941,7 +4912,7 @@ dependencies = [ "bp-messages", "bp-runtime", "finality-relay", - "futures 0.3.21", + "futures", "hex", "log", "num-traits", @@ -4950,25 +4921,13 @@ dependencies = [ "sp-arithmetic", ] -[[package]] -name = "metered-channel" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" -dependencies = [ - "derive_more", - "futures 0.3.21", - "futures-timer", - "thiserror", - "tracing", -] - [[package]] name = "mick-jaeger" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" dependencies = [ - "futures 0.3.21", + "futures", "rand 0.8.5", "thrift", ] @@ -4982,10 +4941,10 @@ dependencies = [ "beefy-primitives", "bp-millau", "bp-runtime", - "clap 3.1.6", + "clap 3.2.18", "frame-benchmarking", "frame-benchmarking-cli", - "jsonrpc-core", + "jsonrpsee", "millau-runtime", "node-inspect", "pallet-bridge-messages", @@ -5021,13 +4980,16 @@ version = "0.1.0" dependencies = [ "beefy-primitives", "bp-header-chain", - "bp-message-dispatch", "bp-messages", "bp-millau", + "bp-polkadot-core", + "bp-relayers", "bp-rialto", + "bp-rialto-parachain", "bp-runtime", "bp-westend", "bridge-runtime-common", + "env_logger 0.8.4", "frame-benchmarking", "frame-executive", "frame-support", @@ -5035,17 +4997,17 @@ dependencies = [ "frame-system-rpc-runtime-api", "hex-literal", "libsecp256k1", + "log", "pallet-aura", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", - "pallet-bridge-dispatch", "pallet-bridge-grandpa", "pallet-bridge-messages", - "pallet-bridge-token-swap", + "pallet-bridge-parachains", + "pallet-bridge-relayers", "pallet-grandpa", "pallet-mmr", - "pallet-mmr-primitives", "pallet-randomness-collective-flip", "pallet-session", "pallet-shift-session-manager", @@ -5053,6 +5015,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-xcm", "parity-scale-codec", "scale-info", "serde", @@ -5062,6 +5025,8 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-inherents", + "sp-io", + "sp-mmr-primitives", "sp-offchain", "sp-runtime", "sp-session", @@ -5071,6 +5036,9 @@ dependencies = [ "sp-version", "static_assertions", "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", ] [[package]] @@ -5095,25 +5063,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - [[package]] name = "mio" version = "0.8.1" @@ -5122,34 +5071,10 @@ checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" dependencies = [ "libc", "log", - "miow 0.3.7", + "miow", "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", - "winapi 0.3.9", -] - -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio 0.6.23", - "slab", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "winapi", ] [[package]] @@ -5158,7 +5083,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -5169,27 +5094,27 @@ checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" [[package]] name = "multiaddr" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ee4ea82141951ac6379f964f71b20876d43712bea8faf6dd1a375e08a46499" +checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" dependencies = [ "arrayref", "bs58", "byteorder", "data-encoding", - "multihash 0.14.0", - "percent-encoding 2.1.0", + "multihash", + "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.1", - "url 2.2.2", + "unsigned-varint", + "url", ] [[package]] name = "multibase" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b78c60039650ff12e140ae867ef5299a58e19dded4d334c849dc7177083667e2" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" dependencies = [ "base-x", "data-encoding", @@ -5198,41 +5123,28 @@ dependencies = [ [[package]] name = "multihash" -version = "0.13.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" +checksum = "1c346cf9999c631f002d8f977c4eaeaa0e6386f16007202308d0b3757522c2cc" dependencies = [ "blake2b_simd", "blake2s_simd", - "blake3 0.3.8", - "digest 0.9.0", - "generic-array 0.14.4", - "multihash-derive", - "sha2 0.9.8", - "sha3 0.9.1", - "unsigned-varint 0.5.1", -] - -[[package]] -name = "multihash" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "752a61cd890ff691b4411423d23816d5866dd5621e4d1c5687a53b94b5a979d8" -dependencies = [ - "digest 0.9.0", - "generic-array 0.14.4", + "blake3", + "core2", + "digest 0.10.3", "multihash-derive", - "sha2 0.9.8", - "unsigned-varint 0.7.1", + "sha2 0.10.2", + "sha3 0.10.1", + "unsigned-varint", ] [[package]] name = "multihash-derive" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", @@ -5248,16 +5160,16 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56a336acba8bc87c8876f6425407dbbe6c417bf478b22015f8fb0994ef3bc0ab" +checksum = "363a84be6453a70e63513660f4894ef815daf88e3356bffcda9ca27d810ce83b" dependencies = [ - "bytes 1.1.0", - "futures 0.3.21", + "bytes", + "futures", "log", - "pin-project 1.0.10", + "pin-project", "smallvec", - "unsigned-varint 0.7.1", + "unsigned-varint", ] [[package]] @@ -5291,30 +5203,102 @@ dependencies = [ [[package]] name = "names" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a8690bf09abf659851e58cd666c3d37ac6af07c2bd7a9e332cfba471715775" +checksum = "e7d66043b25d4a6cccb23619d10c19c25304b355a7dccd4a8e11423dd2382146" dependencies = [ "rand 0.8.5", ] [[package]] -name = "net2" -version = "0.2.37" +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" + +[[package]] +name = "netlink-packet-core" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" dependencies = [ - "cfg-if 0.1.10", + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +dependencies = [ + "anyhow", + "bitflags", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +dependencies = [ + "async-io", + "bytes", + "futures", + "libc", + "log", +] + +[[package]] +name = "nix" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", "libc", - "winapi 0.3.9", ] [[package]] name = "node-inspect" version = "0.9.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "clap 3.1.6", + "clap 3.2.18", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -5355,7 +5339,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -5455,17 +5439,27 @@ name = "object" version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "crc32fast", + "hashbrown 0.11.2", "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.8.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "opaque-debug" @@ -5479,29 +5473,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "open-metrics-client" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7337d80c23c2d8b1349563981bc4fb531220733743ba8115454a67b181173f0d" -dependencies = [ - "dtoa", - "itoa 0.4.8", - "open-metrics-client-derive-text-encode", - "owning_ref", -] - -[[package]] -name = "open-metrics-client-derive-text-encode" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c83b586f00268c619c1cb3340ec1a6f59dd9ba1d9833a273a68e6d5cd8ffc" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "openssl-probe" version = "0.1.4" @@ -5521,6 +5492,36 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "orchestra" +version = "0.0.1" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" +dependencies = [ + "async-trait", + "dyn-clonable", + "futures", + "futures-timer", + "orchestra-proc-macro", + "pin-project", + "prioritized-metered-channel", + "thiserror", + "tracing", +] + +[[package]] +name = "orchestra-proc-macro" +version = "0.0.1" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" +dependencies = [ + "expander 0.0.6", + "itertools", + "petgraph", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ordered-float" version = "1.1.1" @@ -5535,9 +5536,6 @@ name = "os_str_bytes" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] [[package]] name = "owning_ref" @@ -5551,7 +5549,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5567,7 +5565,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5583,7 +5581,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5598,7 +5596,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5622,7 +5620,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-election-provider-support", "frame-support", @@ -5637,7 +5635,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5652,7 +5650,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "beefy-primitives", "frame-support", @@ -5668,18 +5666,16 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "beefy-merkle-tree", "beefy-primitives", "frame-support", "frame-system", "hex", - "k256", "log", "pallet-beefy", "pallet-mmr", - "pallet-mmr-primitives", "pallet-session", "parity-scale-codec", "scale-info", @@ -5693,7 +5689,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5708,60 +5704,66 @@ dependencies = [ ] [[package]] -name = "pallet-bridge-dispatch" +name = "pallet-bridge-grandpa" version = "0.1.0" dependencies = [ - "bp-message-dispatch", + "bp-header-chain", "bp-runtime", + "bp-test-utils", + "finality-grandpa", + "frame-benchmarking", "frame-support", "frame-system", "log", + "num-traits", "parity-scale-codec", "scale-info", + "serde", "sp-core", + "sp-finality-grandpa", "sp-io", "sp-runtime", "sp-std", + "sp-trie", ] [[package]] -name = "pallet-bridge-grandpa" +name = "pallet-bridge-messages" version = "0.1.0" dependencies = [ - "bp-header-chain", + "bitvec", + "bp-messages", "bp-runtime", "bp-test-utils", - "finality-grandpa", "frame-benchmarking", "frame-support", "frame-system", "log", "num-traits", + "pallet-balances", "parity-scale-codec", "scale-info", "serde", "sp-core", - "sp-finality-grandpa", "sp-io", "sp-runtime", "sp-std", - "sp-trie", ] [[package]] -name = "pallet-bridge-messages" +name = "pallet-bridge-parachains" version = "0.1.0" dependencies = [ - "bitvec", - "bp-message-dispatch", - "bp-messages", + "bp-header-chain", + "bp-parachains", + "bp-polkadot-core", "bp-runtime", + "bp-test-utils", "frame-benchmarking", "frame-support", "frame-system", "log", - "num-traits", - "pallet-balances", + "pallet-bridge-grandpa", "parity-scale-codec", "scale-info", "serde", @@ -5769,26 +5771,45 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "sp-trie", ] [[package]] -name = "pallet-bridge-token-swap" +name = "pallet-bridge-relayers" version = "0.1.0" dependencies = [ - "bp-message-dispatch", "bp-messages", + "bp-relayers", "bp-runtime", - "bp-token-swap", "frame-benchmarking", "frame-support", "frame-system", "log", + "num-traits", "pallet-balances", - "pallet-bridge-dispatch", "pallet-bridge-messages", "parity-scale-codec", "scale-info", "serde", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-child-bounties" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "frame-support", + "frame-system", + "log", + "pallet-bounties", + "pallet-treasury", + "parity-scale-codec", + "scale-info", "sp-core", "sp-io", "sp-runtime", @@ -5798,7 +5819,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5815,7 +5836,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5831,7 +5852,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5848,13 +5869,13 @@ dependencies = [ "sp-runtime", "sp-std", "static_assertions", - "strum 0.23.0", + "strum 0.24.1", ] [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5871,7 +5892,7 @@ dependencies = [ [[package]] name = "pallet-gilt" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5886,7 +5907,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5909,7 +5930,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "enumflags2", "frame-benchmarking", @@ -5925,7 +5946,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5944,7 +5965,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -5960,7 +5981,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -5977,33 +5998,17 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "ckb-merkle-mountain-range", "frame-benchmarking", "frame-support", "frame-system", - "pallet-mmr-primitives", "parity-scale-codec", "scale-info", "sp-core", "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-mmr-primitives" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" -dependencies = [ - "frame-support", - "frame-system", - "log", - "parity-scale-codec", - "serde", - "sp-api", - "sp-core", + "sp-mmr-primitives", "sp-runtime", "sp-std", ] @@ -6011,24 +6016,22 @@ dependencies = [ [[package]] name = "pallet-mmr-rpc" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "pallet-mmr-primitives", + "jsonrpsee", "parity-scale-codec", "serde", "sp-api", "sp-blockchain", "sp-core", + "sp-mmr-primitives", "sp-runtime", ] [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6040,23 +6043,36 @@ dependencies = [ ] [[package]] -name = "pallet-nicks" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +name = "pallet-nomination-pools" +version = "1.0.0" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", + "log", "parity-scale-codec", "scale-info", + "sp-core", "sp-io", "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-nomination-pools-runtime-api" +version = "1.0.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "parity-scale-codec", + "sp-api", "sp-std", ] [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6073,7 +6089,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -6089,7 +6105,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6103,7 +6119,7 @@ dependencies = [ [[package]] name = "pallet-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6117,8 +6133,9 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "parity-scale-codec", @@ -6131,7 +6148,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -6147,7 +6164,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6183,7 +6200,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6197,7 +6214,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-election-provider-support", "frame-support", @@ -6218,9 +6235,9 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -6229,7 +6246,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "log", "sp-arithmetic", @@ -6238,7 +6255,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6252,7 +6269,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-benchmarking", "frame-support", @@ -6270,7 +6287,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6288,14 +6305,13 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", "parity-scale-codec", "scale-info", "serde", - "smallvec", "sp-core", "sp-io", "sp-runtime", @@ -6305,11 +6321,9 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "sp-api", @@ -6322,7 +6336,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6333,7 +6347,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6349,7 +6363,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6364,7 +6378,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-support", "frame-system", @@ -6377,8 +6391,8 @@ dependencies = [ [[package]] name = "pallet-xcm" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-support", "frame-system", @@ -6387,6 +6401,7 @@ dependencies = [ "scale-info", "serde", "sp-core", + "sp-io", "sp-runtime", "sp-std", "xcm", @@ -6396,7 +6411,7 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#4e952282914719fafd2df450993ccc2ce9395415" +source = "git+https://github.com/paritytech/cumulus?branch=gav-xcm-v3#516669814078a308e8de659979aa0f97e8d67eff" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -6406,11 +6421,31 @@ dependencies = [ "serde", ] +[[package]] +name = "parachains-relay" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "backoff", + "bp-parachains", + "bp-polkadot-core", + "futures", + "linked-hash-map", + "log", + "num-traits", + "parity-scale-codec", + "parking_lot 0.11.2", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + [[package]] name = "parity-db" -version = "0.3.8" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865edee5b792f537356d9e55cbc138e7f4718dc881a7ea45a18b37bf61c21e3d" +checksum = "2bb474d0ed0836e185cb998a6b140ed1073d1fbf27d690ecf9ede8030289382c" dependencies = [ "blake2-rfc", "crc32fast", @@ -6427,13 +6462,14 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.1.2" +version = "3.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b44461635bbb1a0300f100a841e571e7d919c81c73075ef5d152ffdb521066" +checksum = "9182e4a71cae089267ab03e67c99368db7cd877baf50f931e5d6d4b71e195ac0" dependencies = [ "arrayvec 0.7.2", "bitvec", "byte-slice-cast", + "bytes", "impl-trait-for-tuples", "parity-scale-codec-derive", "serde", @@ -6441,11 +6477,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c45ed1f39709f5a89338fab50e59816b2e8815f5bb58276e7ddf9afd495f73f8" +checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -6453,23 +6489,9 @@ dependencies = [ [[package]] name = "parity-send-wrapper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" - -[[package]] -name = "parity-tokio-ipc" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" -dependencies = [ - "futures 0.3.21", - "libc", - "log", - "rand 0.7.3", - "tokio", - "winapi 0.3.9", -] +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" [[package]] name = "parity-util-mem" @@ -6478,13 +6500,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" dependencies = [ "cfg-if 1.0.0", - "hashbrown 0.12.0", + "ethereum-types", + "hashbrown 0.12.3", "impl-trait-for-tuples", + "lru 0.7.8", "parity-util-mem-derive", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "primitive-types", "smallvec", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -6513,24 +6537,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" -[[package]] -name = "parity-ws" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5983d3929ad50f12c3eb9a6743f19d691866ecd44da74c0a3308c3f8a56df0c6" -dependencies = [ - "byteorder", - "bytes 0.4.12", - "httparse", - "log", - "mio 0.6.23", - "mio-extras", - "rand 0.7.3", - "sha-1 0.8.2", - "slab", - "url 2.2.2", -] - [[package]] name = "parking" version = "2.0.0" @@ -6550,9 +6556,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core 0.9.1", @@ -6569,7 +6575,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -6582,7 +6588,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.32.0", ] [[package]] @@ -6615,12 +6621,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -6680,33 +6680,13 @@ dependencies = [ "indexmap", ] -[[package]] -name = "pin-project" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9615c18d31137579e9ff063499264ddc1278e7b1982757ebc111028c4d1dc909" -dependencies = [ - "pin-project-internal 0.4.29", -] - [[package]] name = "pin-project" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ - "pin-project-internal 1.0.10", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "044964427019eed9d49d9d5bbce6047ef18f37100ea400912a9fa4a3523ab12a" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] @@ -6728,9 +6708,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -6738,17 +6718,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" -dependencies = [ - "der", - "spki", - "zeroize", -] - [[package]] name = "pkg-config" version = "0.3.22" @@ -6763,40 +6732,42 @@ checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" [[package]] name = "polkadot-approval-distribution" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", - "tracing", + "rand 0.8.5", + "tracing-gum", ] [[package]] name = "polkadot-availability-bitfield-distribution" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", - "tracing", + "rand 0.8.5", + "tracing-gum", ] [[package]] name = "polkadot-availability-distribution" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "derive_more", "fatality", - "futures 0.3.21", - "lru 0.7.3", + "futures", + "lru 0.7.8", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -6808,17 +6779,17 @@ dependencies = [ "sp-core", "sp-keystore", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-availability-recovery" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "fatality", - "futures 0.3.21", - "lru 0.7.3", + "futures", + "lru 0.7.8", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -6829,26 +6800,29 @@ dependencies = [ "rand 0.8.5", "sc-network", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-cli" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "clap 3.1.6", + "clap 3.2.18", "frame-benchmarking-cli", - "futures 0.3.21", + "futures", "log", + "polkadot-client", "polkadot-node-core-pvf", "polkadot-node-metrics", "polkadot-performance-test", "polkadot-service", "sc-cli", "sc-service", + "sc-sysinfo", "sc-tracing", "sp-core", + "sp-keyring", "sp-trie", "substrate-build-script-utils", "thiserror", @@ -6857,16 +6831,21 @@ dependencies = [ [[package]] name = "polkadot-client" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "beefy-primitives", "frame-benchmarking", + "frame-benchmarking-cli", + "frame-system", "frame-system-rpc-runtime-api", - "pallet-mmr-primitives", + "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "polkadot-core-primitives", + "polkadot-node-core-parachains-inherent", "polkadot-primitives", "polkadot-runtime", + "polkadot-runtime-common", "sc-client-api", "sc-consensus", "sc-executor", @@ -6877,22 +6856,27 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-core", "sp-finality-grandpa", + "sp-inherents", + "sp-keyring", + "sp-mmr-primitives", "sp-offchain", "sp-runtime", "sp-session", "sp-storage", + "sp-timestamp", "sp-transaction-pool", ] [[package]] name = "polkadot-collator-protocol" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "always-assert", "fatality", - "futures 0.3.21", + "futures", "futures-timer", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -6903,13 +6887,13 @@ dependencies = [ "sp-keystore", "sp-runtime", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-core-primitives" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "parity-scale-codec", "parity-util-mem", @@ -6921,13 +6905,13 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "derive_more", "fatality", - "futures 0.3.21", - "lru 0.7.3", + "futures", + "lru 0.7.8", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -6939,13 +6923,13 @@ dependencies = [ "sp-application-crypto", "sp-keystore", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-erasure-coding" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -6958,10 +6942,10 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -6973,34 +6957,39 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-keystore", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-network-bridge" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ + "always-assert", "async-trait", - "futures 0.3.21", + "bytes", + "fatality", + "futures", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", "sc-network", + "sc-network-common", "sp-consensus", - "tracing", + "thiserror", + "tracing-gum", ] [[package]] name = "polkadot-node-collation-generation" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-primitives", @@ -7010,20 +6999,20 @@ dependencies = [ "sp-core", "sp-maybe-compressed-blob", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-approval-voting" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bitvec", "derive_more", - "futures 0.3.21", + "futures", "futures-timer", "kvdb", - "lru 0.7.3", + "lru 0.7.8", "merlin", "parity-scale-codec", "polkadot-node-jaeger", @@ -7038,16 +7027,17 @@ dependencies = [ "sp-consensus", "sp-consensus-slots", "sp-runtime", - "tracing", + "thiserror", + "tracing-gum", ] [[package]] name = "polkadot-node-core-av-store" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bitvec", - "futures 0.3.21", + "futures", "futures-timer", "kvdb", "parity-scale-codec", @@ -7058,16 +7048,17 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-backing" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bitvec", - "futures 0.3.21", + "fatality", + "futures", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7076,31 +7067,31 @@ dependencies = [ "polkadot-statement-table", "sp-keystore", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-bitfield-signing" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", "sp-keystore", "thiserror", - "tracing", + "tracing-gum", "wasm-timer", ] [[package]] name = "polkadot-node-core-candidate-validation" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "parity-scale-codec", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -7109,30 +7100,30 @@ dependencies = [ "polkadot-parachain", "polkadot-primitives", "sp-maybe-compressed-blob", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-chain-api" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "polkadot-node-subsystem", "polkadot-node-subsystem-util", "polkadot-primitives", "sc-client-api", "sc-consensus-babe", "sp-blockchain", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-chain-selection" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "kvdb", "parity-scale-codec", @@ -7141,18 +7132,18 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-dispute-coordinator" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "fatality", - "futures 0.3.21", + "futures", "kvdb", - "lru 0.7.3", + "lru 0.7.8", "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7160,16 +7151,16 @@ dependencies = [ "polkadot-primitives", "sc-keystore", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-parachains-inherent" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "polkadot-node-subsystem", "polkadot-primitives", @@ -7177,16 +7168,17 @@ dependencies = [ "sp-inherents", "sp-runtime", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-provisioner" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bitvec", - "futures 0.3.21", + "fatality", + "futures", "futures-timer", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7194,26 +7186,27 @@ dependencies = [ "polkadot-primitives", "rand 0.8.5", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-pvf" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "always-assert", "assert_matches", "async-process", "async-std", - "futures 0.3.21", + "futures", "futures-timer", "parity-scale-codec", - "pin-project 1.0.10", + "pin-project", "polkadot-core-primitives", "polkadot-node-subsystem-util", "polkadot-parachain", "rand 0.8.5", + "rayon", "sc-executor", "sc-executor-common", "sc-executor-wasmtime", @@ -7224,15 +7217,16 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-tracing", "sp-wasm-interface", - "tracing", + "tempfile", + "tracing-gum", ] [[package]] name = "polkadot-node-core-pvf-checker" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-util", @@ -7240,38 +7234,36 @@ dependencies = [ "polkadot-primitives", "sp-keystore", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-core-runtime-api" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "futures", "memory-lru", "parity-util-mem", "polkadot-node-subsystem", + "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-primitives", - "sp-api", - "sp-authority-discovery", "sp-consensus-babe", - "sp-core", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-jaeger" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "async-std", "lazy_static", "log", "mick-jaeger", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-node-primitives", "polkadot-primitives", "sc-network", @@ -7281,48 +7273,52 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bs58", - "futures 0.3.21", + "futures", "futures-timer", "log", - "metered-channel", "parity-scale-codec", "polkadot-primitives", + "prioritized-metered-channel", "sc-cli", "sc-service", "sc-tracing", "substrate-prometheus-endpoint", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-node-network-protocol" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "async-trait", + "derive_more", "fatality", - "futures 0.3.21", + "futures", + "hex", "parity-scale-codec", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", + "rand 0.8.5", "sc-authority-discovery", "sc-network", - "strum 0.24.0", + "strum 0.24.1", "thiserror", + "tracing-gum", ] [[package]] name = "polkadot-node-primitives" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bounded-vec", - "futures 0.3.21", + "futures", "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", @@ -7340,8 +7336,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -7350,41 +7346,44 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ + "async-trait", "derive_more", - "futures 0.3.21", + "futures", + "orchestra", "polkadot-node-jaeger", "polkadot-node-network-protocol", "polkadot-node-primitives", - "polkadot-overseer-gen", "polkadot-primitives", "polkadot-statement-table", "sc-network", "smallvec", + "sp-api", + "sp-authority-discovery", + "sp-consensus-babe", "substrate-prometheus-endpoint", "thiserror", ] [[package]] name = "polkadot-node-subsystem-util" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "async-trait", "derive_more", "fatality", - "futures 0.3.21", + "futures", "itertools", "kvdb", - "lru 0.7.3", - "metered-channel", + "lru 0.7.8", "parity-db", "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.2", - "pin-project 1.0.10", + "pin-project", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", @@ -7392,68 +7391,42 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-overseer", "polkadot-primitives", + "prioritized-metered-channel", "rand 0.8.5", "sp-application-crypto", "sp-core", "sp-keystore", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-overseer" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "futures 0.3.21", + "async-trait", + "futures", "futures-timer", - "lru 0.7.3", + "lru 0.7.8", + "orchestra", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem-types", - "polkadot-overseer-gen", "polkadot-primitives", "sc-client-api", "sp-api", - "tracing", -] - -[[package]] -name = "polkadot-overseer-gen" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" -dependencies = [ - "async-trait", - "futures 0.3.21", - "futures-timer", - "metered-channel", - "pin-project 1.0.10", - "polkadot-node-network-protocol", - "polkadot-node-primitives", - "polkadot-overseer-gen-proc-macro", - "thiserror", - "tracing", -] - -[[package]] -name = "polkadot-overseer-gen-proc-macro" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" -dependencies = [ - "expander 0.0.6", - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn", + "sp-core", + "tracing-gum", ] [[package]] name = "polkadot-parachain" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "derive_more", "frame-support", @@ -7469,8 +7442,8 @@ dependencies = [ [[package]] name = "polkadot-performance-test" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -7484,8 +7457,8 @@ dependencies = [ [[package]] name = "polkadot-primitives" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bitvec", "frame-system", @@ -7514,12 +7487,12 @@ dependencies = [ [[package]] name = "polkadot-rpc" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "beefy-gadget", "beefy-gadget-rpc", - "jsonrpc-core", + "jsonrpsee", "pallet-mmr-rpc", "pallet-transaction-payment-rpc", "polkadot-primitives", @@ -7541,12 +7514,13 @@ dependencies = [ "sp-keystore", "sp-runtime", "substrate-frame-rpc-system", + "substrate-state-trie-migration-rpc", ] [[package]] name = "polkadot-runtime" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "beefy-primitives", "bitvec", @@ -7563,6 +7537,7 @@ dependencies = [ "pallet-bags-list", "pallet-balances", "pallet-bounties", + "pallet-child-bounties", "pallet-collective", "pallet-democracy", "pallet-election-provider-multi-phase", @@ -7572,9 +7547,8 @@ dependencies = [ "pallet-im-online", "pallet-indices", "pallet-membership", - "pallet-mmr-primitives", "pallet-multisig", - "pallet-nicks", + "pallet-nomination-pools", "pallet-offences", "pallet-preimage", "pallet-proxy", @@ -7607,6 +7581,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-io", + "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", @@ -7624,8 +7599,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "beefy-primitives", "bitvec", @@ -7669,8 +7644,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-support", "polkadot-primitives", @@ -7681,8 +7656,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bs58", "parity-scale-codec", @@ -7693,8 +7668,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "bitflags", "bitvec", @@ -7733,21 +7708,20 @@ dependencies = [ [[package]] name = "polkadot-service" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "async-trait", "beefy-gadget", "beefy-primitives", "frame-system-rpc-runtime-api", - "futures 0.3.21", + "futures", "hex-literal", "kvdb", "kvdb-rocksdb", - "lru 0.7.3", + "lru 0.7.8", "pallet-babe", "pallet-im-online", - "pallet-mmr-primitives", "pallet-staking", "pallet-transaction-payment-rpc-runtime-api", "parity-db", @@ -7776,6 +7750,7 @@ dependencies = [ "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", + "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-parachain", @@ -7794,17 +7769,19 @@ dependencies = [ "sc-consensus", "sc-consensus-babe", "sc-consensus-slots", - "sc-consensus-uncles", "sc-executor", "sc-finality-grandpa", "sc-keystore", "sc-network", + "sc-network-common", "sc-offchain", "sc-service", "sc-sync-state-rpc", + "sc-sysinfo", "sc-telemetry", "sc-transaction-pool", "serde", + "serde_json", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -7826,17 +7803,17 @@ dependencies = [ "sp-trie", "substrate-prometheus-endpoint", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-statement-distribution" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "arrayvec 0.5.2", "fatality", - "futures 0.3.21", + "futures", "indexmap", "parity-scale-codec", "polkadot-node-network-protocol", @@ -7847,13 +7824,13 @@ dependencies = [ "sp-keystore", "sp-staking", "thiserror", - "tracing", + "tracing-gum", ] [[package]] name = "polkadot-statement-table" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -7862,8 +7839,8 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "beefy-primitives", "bitvec", @@ -7879,8 +7856,6 @@ dependencies = [ "pallet-balances", "pallet-grandpa", "pallet-indices", - "pallet-mmr-primitives", - "pallet-nicks", "pallet-offences", "pallet-session", "pallet-staking", @@ -7908,6 +7883,7 @@ dependencies = [ "sp-core", "sp-inherents", "sp-io", + "sp-mmr-primitives", "sp-offchain", "sp-runtime", "sp-session", @@ -7924,13 +7900,12 @@ dependencies = [ [[package]] name = "polkadot-test-service" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-benchmarking", "frame-system", - "futures 0.1.31", - "futures 0.3.21", + "futures", "hex", "pallet-balances", "pallet-staking", @@ -7955,6 +7930,7 @@ dependencies = [ "sc-executor", "sc-finality-grandpa", "sc-network", + "sc-network-common", "sc-service", "sc-tracing", "sc-transaction-pool", @@ -7973,7 +7949,7 @@ dependencies = [ "tempfile", "test-runtime-constants", "tokio", - "tracing", + "tracing-gum", ] [[package]] @@ -7986,7 +7962,7 @@ dependencies = [ "libc", "log", "wepoll-ffi", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -7995,7 +7971,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ - "cpufeatures 0.2.1", + "cpufeatures", "opaque-debug 0.3.0", "universal-hash", ] @@ -8007,7 +7983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ "cfg-if 1.0.0", - "cpufeatures 0.2.1", + "cpufeatures", "opaque-debug 0.3.0", "universal-hash", ] @@ -8026,26 +8002,34 @@ checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ "fixed-hash", "impl-codec", + "impl-rlp", "impl-serde", "scale-info", "uint", ] [[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +name = "prioritized-metered-channel" +version = "0.2.0" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ - "toml", + "coarsetime", + "crossbeam-queue", + "derive_more", + "futures", + "futures-timer", + "nanorand", + "thiserror", + "tracing", ] [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] @@ -8076,11 +8060,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -8097,24 +8081,49 @@ dependencies = [ "thiserror", ] +[[package]] +name = "prometheus-client" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1abe0255c04d15f571427a2d1e00099016506cf3297b53853acd2b7eb87825" +dependencies = [ + "dtoa", + "itoa 1.0.1", + "owning_ref", + "prometheus-client-derive-text-encode", +] + +[[package]] +name = "prometheus-client-derive-text-encode" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e12d01b9d66ad9eb4529c57666b6263fc1993cb30261d83ead658fdd932652" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "prost" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" dependencies = [ - "bytes 1.1.0", + "bytes", "prost-derive", ] [[package]] name = "prost-build" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" dependencies = [ - "bytes 1.1.0", - "heck 0.3.3", + "bytes", + "cfg-if 1.0.0", + "cmake", + "heck 0.4.0", "itertools", "lazy_static", "log", @@ -8127,11 +8136,24 @@ dependencies = [ "which", ] +[[package]] +name = "prost-codec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" +dependencies = [ + "asynchronous-codec", + "bytes", + "prost", + "thiserror", + "unsigned-varint", +] + [[package]] name = "prost-derive" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" dependencies = [ "anyhow", "itertools", @@ -8142,11 +8164,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ - "bytes 1.1.0", + "bytes", "prost", ] @@ -8184,9 +8206,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -8208,7 +8230,7 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", + "rand_pcg 0.2.1", ] [[package]] @@ -8288,6 +8310,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core 0.6.3", +] + [[package]] name = "rawpointer" version = "0.2.1" @@ -8372,13 +8403,14 @@ dependencies = [ ] [[package]] -name = "regalloc" -version = "0.0.33" +name = "regalloc2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d808cff91dfca7b239d40b972ba628add94892b1d9e19a842aedc5cfae8ab1a" +checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c" dependencies = [ + "fxhash", "log", - "rustc-hash", + "slice-group-by", "smallvec", ] @@ -8417,29 +8449,18 @@ dependencies = [ "bitflags", "libc", "mach", - "winapi 0.3.9", + "winapi", ] [[package]] name = "relay-kusama-client" version = "0.1.0" dependencies = [ - "bp-header-chain", "bp-kusama", - "bp-message-dispatch", - "bp-messages", - "bp-polkadot", - "bp-polkadot-core", - "bp-runtime", - "bridge-runtime-common", "frame-support", - "pallet-bridge-dispatch", - "parity-scale-codec", "relay-substrate-client", "relay-utils", - "scale-info", "sp-core", - "sp-runtime", ] [[package]] @@ -8463,22 +8484,11 @@ dependencies = [ name = "relay-polkadot-client" version = "0.1.0" dependencies = [ - "bp-header-chain", - "bp-kusama", - "bp-message-dispatch", - "bp-messages", "bp-polkadot", - "bp-polkadot-core", - "bp-runtime", - "bridge-runtime-common", "frame-support", - "pallet-bridge-dispatch", - "parity-scale-codec", "relay-substrate-client", "relay-utils", - "scale-info", "sp-core", - "sp-runtime", ] [[package]] @@ -8502,36 +8512,28 @@ dependencies = [ name = "relay-rialto-parachain-client" version = "0.1.0" dependencies = [ - "bp-rialto", + "bp-messages", + "bp-rialto-parachain", "frame-support", "frame-system", "pallet-transaction-payment", + "parity-scale-codec", "relay-substrate-client", "relay-utils", "rialto-parachain-runtime", + "sp-core", + "sp-runtime", ] [[package]] name = "relay-rococo-client" version = "0.1.0" dependencies = [ - "bp-header-chain", - "bp-message-dispatch", - "bp-messages", - "bp-polkadot-core", "bp-rococo", - "bp-runtime", - "bp-wococo", - "bridge-runtime-common", "frame-support", - "pallet-bridge-dispatch", - "pallet-bridge-messages", - "parity-scale-codec", "relay-substrate-client", "relay-utils", - "scale-info", "sp-core", - "sp-runtime", ] [[package]] @@ -8546,8 +8548,8 @@ dependencies = [ "finality-relay", "frame-support", "frame-system", - "futures 0.3.21", - "jsonrpsee 0.8.0", + "futures", + "jsonrpsee", "log", "num-traits", "pallet-balances", @@ -8583,7 +8585,7 @@ dependencies = [ "backoff", "bp-runtime", "env_logger 0.8.4", - "futures 0.3.21", + "futures", "isahc", "jsonpath_lib", "log", @@ -8602,7 +8604,6 @@ version = "0.1.0" dependencies = [ "bp-westend", "frame-support", - "parity-scale-codec", "relay-substrate-client", "relay-utils", "sp-core", @@ -8613,32 +8614,20 @@ dependencies = [ name = "relay-wococo-client" version = "0.1.0" dependencies = [ - "bp-header-chain", - "bp-message-dispatch", - "bp-messages", - "bp-polkadot-core", - "bp-rococo", - "bp-runtime", "bp-wococo", - "bridge-runtime-common", "frame-support", - "pallet-bridge-dispatch", - "pallet-bridge-messages", - "parity-scale-codec", "relay-substrate-client", "relay-utils", - "scale-info", "sp-core", - "sp-runtime", ] [[package]] name = "remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "env_logger 0.9.0", - "jsonrpsee 0.8.0", + "jsonrpsee", "log", "parity-scale-codec", "serde", @@ -8655,7 +8644,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -8669,10 +8658,15 @@ dependencies = [ ] [[package]] -name = "retain_mut" -version = "0.1.4" +name = "rfc6979" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] [[package]] name = "rialto-bridge-node" @@ -8683,18 +8677,17 @@ dependencies = [ "beefy-primitives", "bp-rialto", "bp-runtime", - "clap 3.1.6", + "clap 3.2.18", "frame-benchmarking", "frame-benchmarking-cli", "frame-system-rpc-runtime-api", - "futures 0.3.21", + "futures", "jsonrpc-core", "kvdb", "kvdb-rocksdb", - "lru 0.7.3", + "lru 0.7.8", "node-inspect", "pallet-bridge-messages", - "pallet-mmr-primitives", "pallet-mmr-rpc", "pallet-transaction-payment-rpc", "pallet-transaction-payment-rpc-runtime-api", @@ -8731,6 +8724,7 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-inherents", + "sp-mmr-primitives", "sp-offchain", "sp-runtime", "sp-session", @@ -8746,7 +8740,8 @@ dependencies = [ name = "rialto-parachain-collator" version = "0.1.0" dependencies = [ - "clap 3.1.6", + "bp-rialto-parachain", + "clap 3.2.18", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", @@ -8761,8 +8756,9 @@ dependencies = [ "frame-benchmarking", "frame-benchmarking-cli", "hex-literal", - "jsonrpc-core", + "jsonrpsee", "log", + "pallet-bridge-messages", "pallet-transaction-payment-rpc", "parity-scale-codec", "polkadot-cli", @@ -8808,7 +8804,12 @@ dependencies = [ name = "rialto-parachain-runtime" version = "0.1.0" dependencies = [ + "bp-messages", + "bp-millau", + "bp-relayers", "bp-rialto-parachain", + "bp-runtime", + "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -8826,6 +8827,9 @@ dependencies = [ "log", "pallet-aura", "pallet-balances", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-relayers", "pallet-randomness-collective-flip", "pallet-sudo", "pallet-timestamp", @@ -8861,12 +8865,13 @@ version = "0.1.0" dependencies = [ "beefy-primitives", "bp-header-chain", - "bp-message-dispatch", "bp-messages", "bp-millau", + "bp-relayers", "bp-rialto", "bp-runtime", "bridge-runtime-common", + "env_logger 0.8.4", "frame-benchmarking", "frame-executive", "frame-support", @@ -8880,18 +8885,18 @@ dependencies = [ "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", - "pallet-bridge-dispatch", "pallet-bridge-grandpa", "pallet-bridge-messages", + "pallet-bridge-relayers", "pallet-grandpa", "pallet-mmr", - "pallet-mmr-primitives", "pallet-session", "pallet-shift-session-manager", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-xcm", "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", @@ -8906,6 +8911,7 @@ dependencies = [ "sp-finality-grandpa", "sp-inherents", "sp-io", + "sp-mmr-primitives", "sp-offchain", "sp-runtime", "sp-session", @@ -8915,6 +8921,9 @@ dependencies = [ "sp-version", "static_assertions", "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", ] [[package]] @@ -8929,7 +8938,17 @@ dependencies = [ "spin", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "rlp" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" +dependencies = [ + "bytes", + "rustc-hex", ] [[package]] @@ -8944,12 +8963,27 @@ dependencies = [ [[package]] name = "rpassword" -version = "5.0.1" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "rtnetlink" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +dependencies = [ + "async-global-executor", + "futures", + "log", + "netlink-packet-route", + "netlink-proto", + "nix", + "thiserror", ] [[package]] @@ -8979,15 +9013,6 @@ dependencies = [ "semver 0.9.0", ] -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" @@ -8999,29 +9024,30 @@ dependencies = [ [[package]] name = "rustix" -version = "0.31.3" +version = "0.33.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2dcfc2778a90e38f56a708bfc90572422e11d6c7ee233d053d1f782cf9df6d2" +checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" dependencies = [ "bitflags", "errno", - "io-lifetimes", + "io-lifetimes 0.5.3", "libc", - "linux-raw-sys", - "winapi 0.3.9", + "linux-raw-sys 0.0.42", + "winapi", ] [[package]] -name = "rustls" -version = "0.19.1" +name = "rustix" +version = "0.35.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "72c825b8aa8010eb9ee99b75f05e10180b9278d161583034d7574c9d617aeada" dependencies = [ - "base64", - "log", - "ring", - "sct 0.6.1", - "webpki 0.21.4", + "bitflags", + "errno", + "io-lifetimes 0.7.3", + "libc", + "linux-raw-sys 0.0.46", + "windows-sys 0.36.1", ] [[package]] @@ -9032,20 +9058,8 @@ checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" dependencies = [ "log", "ring", - "sct 0.7.0", - "webpki 0.22.0", -] - -[[package]] -name = "rustls-native-certs" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" -dependencies = [ - "openssl-probe", - "rustls 0.19.1", - "schannel", - "security-framework", + "sct", + "webpki", ] [[package]] @@ -9077,12 +9091,12 @@ checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] name = "rw-stream-sink" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" +checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" dependencies = [ - "futures 0.3.21", - "pin-project 0.4.29", + "futures", + "pin-project", "static_assertions", ] @@ -9122,7 +9136,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "log", "sp-core", @@ -9133,10 +9147,9 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "ip_network", "libp2p", @@ -9146,7 +9159,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sc-client-api", - "sc-network", + "sc-network-common", "sp-api", "sp-authority-discovery", "sp-blockchain", @@ -9160,9 +9173,9 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "log", "parity-scale-codec", @@ -9183,7 +9196,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9199,13 +9212,13 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "impl-trait-for-tuples", "memmap2 0.5.0", "parity-scale-codec", "sc-chain-spec-derive", - "sc-network", + "sc-network-common", "sc-telemetry", "serde", "serde_json", @@ -9216,9 +9229,9 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -9227,12 +9240,12 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "chrono", - "clap 3.1.6", + "clap 3.2.18", "fdlimit", - "futures 0.3.21", + "futures", "hex", "libp2p", "log", @@ -9242,6 +9255,7 @@ dependencies = [ "regex", "rpassword", "sc-client-api", + "sc-client-db", "sc-keystore", "sc-network", "sc-service", @@ -9265,14 +9279,14 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "fnv", - "futures 0.3.21", + "futures", "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -9293,7 +9307,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "hash-db", "kvdb", @@ -9303,7 +9317,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-client-api", "sc-state-db", "sp-arithmetic", @@ -9318,14 +9332,14 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "libp2p", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-client-api", "sc-utils", "serde", @@ -9342,10 +9356,10 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "log", "parity-scale-codec", "sc-block-builder", @@ -9371,20 +9385,19 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "fork-tree", - "futures 0.3.21", + "futures", "log", "merlin", "num-bigint", "num-rational 0.2.4", "num-traits", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", - "retain_mut", "sc-client-api", "sc-consensus", "sc-consensus-epochs", @@ -9414,12 +9427,10 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "futures", + "jsonrpsee", "sc-consensus-babe", "sc-consensus-epochs", "sc-rpc-api", @@ -9438,7 +9449,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "fork-tree", "parity-scale-codec", @@ -9451,10 +9462,10 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "log", "parity-scale-codec", @@ -9476,7 +9487,7 @@ dependencies = [ [[package]] name = "sc-consensus-uncles" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "sc-client-api", "sp-authorship", @@ -9487,12 +9498,12 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "lazy_static", - "lru 0.6.6", + "lru 0.7.8", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-executor-common", "sc-executor-wasmi", "sc-executor-wasmtime", @@ -9514,14 +9525,13 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "environmental", "parity-scale-codec", "sc-allocator", - "sp-core", "sp-maybe-compressed-blob", - "sp-serializer", + "sp-sandbox", "sp-wasm-interface", "thiserror", "wasm-instrument", @@ -9531,15 +9541,14 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "log", "parity-scale-codec", "sc-allocator", "sc-executor-common", - "scoped-tls", - "sp-core", "sp-runtime-interface", + "sp-sandbox", "sp-wasm-interface", "wasmi", ] @@ -9547,17 +9556,19 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "cfg-if 1.0.0", "libc", "log", + "once_cell", "parity-scale-codec", "parity-wasm 0.42.2", + "rustix 0.35.9", "sc-allocator", "sc-executor-common", - "sp-core", "sp-runtime-interface", + "sp-sandbox", "sp-wasm-interface", "wasmtime", ] @@ -9565,19 +9576,19 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "ahash", "async-trait", "dyn-clone", "finality-grandpa", "fork-tree", - "futures 0.3.21", + "futures", "futures-timer", "hex", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.8.5", "sc-block-builder", "sc-chain-spec", @@ -9585,6 +9596,7 @@ dependencies = [ "sc-consensus", "sc-keystore", "sc-network", + "sc-network-common", "sc-network-gossip", "sc-telemetry", "sc-utils", @@ -9605,14 +9617,11 @@ dependencies = [ [[package]] name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "finality-grandpa", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-pubsub", + "futures", + "jsonrpsee", "log", "parity-scale-codec", "sc-client-api", @@ -9629,15 +9638,15 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "ansi_term 0.12.1", - "futures 0.3.21", + "futures", "futures-timer", "log", "parity-util-mem", "sc-client-api", - "sc-network", + "sc-network-common", "sc-transaction-pool-api", "sp-blockchain", "sp-runtime", @@ -9646,11 +9655,11 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "hex", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "serde_json", "sp-application-crypto", "sp-core", @@ -9661,17 +9670,17 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "asynchronous-codec 0.5.0", + "asynchronous-codec", "bitflags", - "bytes 1.1.0", + "bytes", "cid", "either", "fnv", "fork-tree", - "futures 0.3.21", + "futures", "futures-timer", "hex", "ip_network", @@ -9679,16 +9688,17 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log", - "lru 0.7.3", + "lru 0.7.8", "parity-scale-codec", - "parking_lot 0.12.0", - "pin-project 1.0.10", + "parking_lot 0.12.1", + "pin-project", "prost", "prost-build", "rand 0.7.3", "sc-block-builder", "sc-client-api", "sc-consensus", + "sc-network-common", "sc-peerset", "sc-utils", "serde", @@ -9698,51 +9708,124 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-core", - "sp-finality-grandpa", "sp-runtime", "substrate-prometheus-endpoint", "thiserror", - "unsigned-varint 0.6.0", + "unsigned-varint", "void", "zeroize", ] +[[package]] +name = "sc-network-common" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "async-trait", + "bitflags", + "bytes", + "futures", + "libp2p", + "parity-scale-codec", + "prost-build", + "sc-consensus", + "sc-peerset", + "serde", + "smallvec", + "sp-consensus", + "sp-finality-grandpa", + "sp-runtime", + "thiserror", +] + [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "ahash", - "futures 0.3.21", + "futures", "futures-timer", "libp2p", "log", - "lru 0.7.3", - "sc-network", + "lru 0.7.8", + "sc-network-common", + "sc-peerset", "sp-runtime", "substrate-prometheus-endpoint", "tracing", ] +[[package]] +name = "sc-network-light" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "futures", + "hex", + "libp2p", + "log", + "parity-scale-codec", + "prost", + "prost-build", + "sc-client-api", + "sc-network-common", + "sc-peerset", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-network-sync" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "fork-tree", + "futures", + "hex", + "libp2p", + "log", + "lru 0.7.8", + "parity-scale-codec", + "prost", + "prost-build", + "sc-client-api", + "sc-consensus", + "sc-network-common", + "sc-peerset", + "smallvec", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-finality-grandpa", + "sp-runtime", + "thiserror", +] + [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", - "futures 0.3.21", + "futures", "futures-timer", "hex", "hyper", "hyper-rustls", + "libp2p", "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "sc-client-api", - "sc-network", + "sc-network-common", + "sc-peerset", "sc-utils", "sp-api", "sp-core", @@ -9755,9 +9838,9 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "libp2p", "log", "sc-utils", @@ -9768,7 +9851,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -9777,15 +9860,14 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "hash-db", - "jsonrpc-core", - "jsonrpc-pubsub", + "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -9808,18 +9890,16 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-pubsub", + "futures", + "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-chain-spec", "sc-transaction-pool-api", + "scale-info", "serde", "serde_json", "sp-core", @@ -9833,14 +9913,10 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-http-server", - "jsonrpc-ipc-server", - "jsonrpc-pubsub", - "jsonrpc-ws-server", + "futures", + "jsonrpsee", "log", "serde_json", "substrate-prometheus-endpoint", @@ -9850,21 +9926,20 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "directories", "exit-future", - "futures 0.3.21", + "futures", "futures-timer", "hash-db", - "jsonrpc-core", - "jsonrpc-pubsub", + "jsonrpsee", "log", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.12.0", - "pin-project 1.0.10", + "parking_lot 0.12.1", + "pin-project", "rand 0.7.3", "sc-block-builder", "sc-chain-spec", @@ -9875,9 +9950,13 @@ dependencies = [ "sc-informant", "sc-keystore", "sc-network", + "sc-network-common", + "sc-network-light", + "sc-network-sync", "sc-offchain", "sc-rpc", "sc-rpc-server", + "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", @@ -9914,13 +9993,13 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "log", "parity-scale-codec", "parity-util-mem", "parity-util-mem-derive", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sc-client-api", "sp-core", ] @@ -9928,11 +10007,9 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "jsonrpsee", "parity-scale-codec", "sc-chain-spec", "sc-client-api", @@ -9946,17 +10023,36 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sc-sysinfo" +version = "6.0.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "futures", + "libc", + "log", + "rand 0.7.3", + "rand_pcg 0.2.1", + "regex", + "sc-telemetry", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-std", +] + [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "chrono", - "futures 0.3.21", + "futures", "libp2p", "log", - "parking_lot 0.12.0", - "pin-project 1.0.10", + "parking_lot 0.12.1", + "pin-project", "rand 0.7.3", "serde", "serde_json", @@ -9967,7 +10063,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "ansi_term 0.12.1", "atty", @@ -9976,7 +10072,7 @@ dependencies = [ "libc", "log", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "regex", "rustc-hash", "sc-client-api", @@ -9998,9 +10094,9 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -10009,16 +10105,15 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "linked-hash-map", "log", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.12.0", - "retain_mut", + "parking_lot 0.12.1", "sc-client-api", "sc-transaction-pool-api", "sc-utils", @@ -10036,9 +10131,9 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "log", "serde", "sp-blockchain", @@ -10049,21 +10144,21 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "futures-timer", "lazy_static", "log", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "prometheus", ] [[package]] name = "scale-info" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0563970d79bcbf3c537ce3ad36d859b30d36fc5b190efd227f1f7a84d7cf0d42" +checksum = "c46be926081c9f4dd5dd9b6f1d3e3229f2360bc6502dd8836f84a93b7c75e99a" dependencies = [ "bitvec", "cfg-if 1.0.0", @@ -10075,11 +10170,11 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.0.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7805950c36512db9e3251c970bb7ac425f326716941862205d612ab3b5e46e2" +checksum = "50e334bb10a245e28e5fd755cabcafd96cfcd167c99ae63a46924ca8d8703a3c" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -10092,7 +10187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -10113,28 +10208,12 @@ dependencies = [ "zeroize", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sct" version = "0.7.0" @@ -10153,25 +10232,24 @@ checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" dependencies = [ "der", "generic-array 0.14.4", - "pkcs8", "subtle", "zeroize", ] [[package]] name = "secp256k1" -version = "0.21.3" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260" +checksum = "b7649a0b3ffb32636e60c7ce0d70511eda9c52c658cd0634e194d5a19943aeff" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +checksum = "7058dc8eaf3f2810d7828680320acda0b25a288f6d288e19278e249bbf74226b" dependencies = [ "cc", ] @@ -10214,7 +10292,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" dependencies = [ - "semver-parser 0.7.0", + "semver-parser", ] [[package]] @@ -10223,16 +10301,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] [[package]] @@ -10250,29 +10319,20 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "serde" -version = "1.0.136" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -10281,9 +10341,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.78" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "indexmap", "itoa 1.0.1", @@ -10320,7 +10380,7 @@ checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures 0.2.1", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -10345,19 +10405,19 @@ checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpufeatures 0.2.1", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] [[package]] name = "sha2" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if 1.0.0", - "cpufeatures 0.2.1", + "cpufeatures", "digest 0.10.3", ] @@ -10423,6 +10483,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" dependencies = [ + "digest 0.9.0", "rand_core 0.6.3", ] @@ -10444,10 +10505,16 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" + [[package]] name = "slot-range-helper" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "enumn", "parity-scale-codec", @@ -10490,31 +10557,19 @@ checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" [[package]] name = "snow" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6142f7c25e94f6fd25a32c3348ec230df9109b463f59c8c7acc4bd34936babb7" +checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" dependencies = [ "aes-gcm", - "blake2 0.9.2", + "blake2", "chacha20poly1305", - "rand 0.8.5", + "curve25519-dalek 4.0.0-pre.1", "rand_core 0.6.3", "ring", - "rustc_version 0.3.3", - "sha2 0.9.8", + "rustc_version 0.4.0", + "sha2 0.10.2", "subtle", - "x25519-dalek", -] - -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi 0.3.9", ] [[package]] @@ -10524,7 +10579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -10534,9 +10589,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ "base64", - "bytes 1.1.0", + "bytes", "flate2", - "futures 0.3.21", + "futures", "httparse", "log", "rand 0.8.5", @@ -10546,7 +10601,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "hash-db", "log", @@ -10556,6 +10611,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-std", + "sp-trie", "sp-version", "thiserror", ] @@ -10563,10 +10619,10 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "blake2 0.10.4", - "proc-macro-crate 1.1.3", + "blake2", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -10575,7 +10631,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "scale-info", @@ -10588,7 +10644,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "integer-sqrt", "num-traits", @@ -10603,7 +10659,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "scale-info", @@ -10616,7 +10672,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "parity-scale-codec", @@ -10628,7 +10684,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "sp-api", @@ -10640,13 +10696,13 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "futures", "log", - "lru 0.7.3", + "lru 0.7.8", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "sp-api", "sp-consensus", "sp-database", @@ -10658,10 +10714,10 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "futures-timer", "log", "parity-scale-codec", @@ -10677,7 +10733,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "parity-scale-codec", @@ -10695,7 +10751,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "merlin", @@ -10718,7 +10774,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "scale-info", @@ -10732,9 +10788,10 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", + "scale-info", "schnorrkel", "sp-core", "sp-runtime", @@ -10744,15 +10801,15 @@ dependencies = [ [[package]] name = "sp-core" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "base58", "bitflags", "blake2-rfc", "byteorder", "dyn-clonable", - "ed25519-dalek", - "futures 0.3.21", + "ed25519-zebra", + "futures", "hash-db", "hash256-std-hasher", "hex", @@ -10764,7 +10821,7 @@ dependencies = [ "num-traits", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "primitive-types", "rand 0.7.3", "regex", @@ -10790,12 +10847,12 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "blake2 0.10.4", + "blake2", "byteorder", "digest 0.10.3", - "sha2 0.10.1", + "sha2 0.10.2", "sha3 0.10.1", "sp-std", "twox-hash", @@ -10804,7 +10861,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "proc-macro2", "quote", @@ -10815,16 +10872,16 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "kvdb", - "parking_lot 0.12.0", + "parking_lot 0.12.1", ] [[package]] name = "sp-debug-derive" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "proc-macro2", "quote", @@ -10834,7 +10891,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.12.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "environmental", "parity-scale-codec", @@ -10845,7 +10902,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "finality-grandpa", "log", @@ -10863,7 +10920,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -10877,14 +10934,15 @@ dependencies = [ [[package]] name = "sp-io" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "futures 0.3.21", + "bytes", + "futures", "hash-db", "libsecp256k1", "log", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "secp256k1", "sp-core", "sp-externalities", @@ -10902,24 +10960,24 @@ dependencies = [ [[package]] name = "sp-keyring" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum 0.23.0", + "strum 0.24.1", ] [[package]] name = "sp-keystore" version = "0.12.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "merlin", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "schnorrkel", "serde", "sp-core", @@ -10930,42 +10988,45 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "thiserror", "zstd", ] [[package]] -name = "sp-npos-elections" +name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ + "log", "parity-scale-codec", - "scale-info", "serde", - "sp-arithmetic", + "sp-api", "sp-core", - "sp-npos-elections-solution-type", + "sp-debug-derive", "sp-runtime", "sp-std", ] [[package]] -name = "sp-npos-elections-solution-type" +name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std", ] [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "sp-api", "sp-core", @@ -10975,7 +11036,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "backtrace", "lazy_static", @@ -10985,7 +11046,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "rustc-hash", "serde", @@ -10995,7 +11056,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "either", "hash256-std-hasher", @@ -11017,8 +11078,9 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ + "bytes", "impl-trait-for-tuples", "parity-scale-codec", "primitive-types", @@ -11034,28 +11096,33 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "Inflector", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] -name = "sp-serializer" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +name = "sp-sandbox" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "serde", - "serde_json", + "log", + "parity-scale-codec", + "sp-core", + "sp-io", + "sp-std", + "sp-wasm-interface", + "wasmi", ] [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "scale-info", @@ -11069,7 +11136,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "scale-info", @@ -11080,13 +11147,13 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.12.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "hash-db", "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "rand 0.7.3", "smallvec", "sp-core", @@ -11096,19 +11163,18 @@ dependencies = [ "sp-trie", "thiserror", "tracing", - "trie-db", "trie-root", ] [[package]] name = "sp-std" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" [[package]] name = "sp-storage" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11121,7 +11187,7 @@ dependencies = [ [[package]] name = "sp-tasks" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "log", "sp-core", @@ -11134,7 +11200,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "futures-timer", @@ -11150,7 +11216,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "sp-std", @@ -11162,7 +11228,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "sp-api", "sp-runtime", @@ -11171,7 +11237,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", "log", @@ -11187,15 +11253,22 @@ dependencies = [ [[package]] name = "sp-trie" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ + "ahash", "hash-db", + "hashbrown 0.12.3", + "lazy_static", + "lru 0.7.8", "memory-db", + "nohash-hasher", "parity-scale-codec", + "parking_lot 0.12.1", "scale-info", "sp-core", "sp-std", "thiserror", + "tracing", "trie-db", "trie-root", ] @@ -11203,7 +11276,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11220,7 +11293,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -11231,7 +11304,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "impl-trait-for-tuples", "log", @@ -11247,23 +11320,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spki" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "ss58-registry" -version = "1.12.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8319f44e20b42e5c11b88b1ad4130c35fe2974665a007b08b02322070177136a" +checksum = "1c8a1e645fa0bd3e81a90e592a677f7ada3182ac338c4a71cd9ec0ba911f6abb" dependencies = [ "Inflector", + "num-format", "proc-macro2", "quote", "serde", @@ -11383,44 +11447,22 @@ dependencies = [ [[package]] name = "strum" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" -dependencies = [ - "strum_macros 0.23.1", -] - -[[package]] -name = "strum" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96acfc1b70604b8b2f1ffa4c57e59176c7dbb05d556c71ecd2f5498a1dee7f8" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ "strum_macros 0.24.0", ] [[package]] name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "strum_macros" -version = "0.23.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" dependencies = [ "heck 0.3.3", "proc-macro2", "quote", - "rustversion", "syn", ] @@ -11453,7 +11495,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "platforms", ] @@ -11461,18 +11503,17 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.21", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", + "futures", + "jsonrpsee", "log", "parity-scale-codec", "sc-client-api", "sc-rpc-api", "sc-transaction-pool-api", + "serde_json", "sp-api", "sp-block-builder", "sp-blockchain", @@ -11483,7 +11524,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "futures-util", "hyper", @@ -11501,24 +11542,20 @@ dependencies = [ "async-std", "async-trait", "bp-header-chain", - "bp-kusama", - "bp-message-dispatch", "bp-messages", "bp-millau", - "bp-polkadot", + "bp-parachains", + "bp-polkadot-core", "bp-rialto", "bp-rialto-parachain", - "bp-rococo", "bp-runtime", "bp-test-utils", - "bp-token-swap", "bp-westend", - "bp-wococo", "bridge-runtime-common", "finality-grandpa", "finality-relay", "frame-support", - "futures 0.3.21", + "futures", "hex", "hex-literal", "log", @@ -11527,27 +11564,21 @@ dependencies = [ "num-format", "num-traits", "pallet-balances", - "pallet-bridge-dispatch", - "pallet-bridge-grandpa", "pallet-bridge-messages", - "pallet-bridge-token-swap", + "pallet-bridge-parachains", + "parachains-relay", "parity-scale-codec", - "paste", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", "rand 0.8.5", - "relay-kusama-client", "relay-millau-client", - "relay-polkadot-client", "relay-rialto-client", "relay-rialto-parachain-client", - "relay-rococo-client", "relay-substrate-client", "relay-utils", "relay-westend-client", - "relay-wococo-client", "rialto-parachain-runtime", "rialto-runtime", "sp-core", @@ -11559,6 +11590,7 @@ dependencies = [ "strum 0.21.0", "substrate-relay-helper", "tempfile", + "xcm", ] [[package]] @@ -11571,6 +11603,8 @@ dependencies = [ "bp-header-chain", "bp-messages", "bp-millau", + "bp-parachains", + "bp-polkadot-core", "bp-rialto", "bp-rococo", "bp-runtime", @@ -11580,15 +11614,18 @@ dependencies = [ "finality-relay", "frame-support", "frame-system", - "futures 0.3.21", + "futures", "log", "messages-relay", "num-traits", "pallet-balances", "pallet-bridge-grandpa", "pallet-bridge-messages", + "pallet-bridge-parachains", "pallet-transaction-payment", + "parachains-relay", "parity-scale-codec", + "relay-rialto-client", "relay-rococo-client", "relay-substrate-client", "relay-utils", @@ -11600,13 +11637,34 @@ dependencies = [ "thiserror", ] +[[package]] +name = "substrate-state-trie-migration-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" +dependencies = [ + "jsonrpsee", + "log", + "parity-scale-codec", + "sc-client-api", + "sc-rpc-api", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "trie-db", +] + [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "async-trait", - "futures 0.3.21", + "futures", "hex", "parity-scale-codec", "sc-client-api", @@ -11629,13 +11687,14 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ "ansi_term 0.12.1", "build-helper", "cargo_metadata", + "filetime", "sp-maybe-compressed-blob", - "strum 0.23.0", + "strum 0.24.1", "tempfile", "toml", "walkdir", @@ -11650,13 +11709,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.88" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -11685,7 +11744,28 @@ dependencies = [ "ntapi", "once_cell", "rayon", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "system-configuration" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -11702,16 +11782,16 @@ checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff" [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", + "fastrand", "libc", - "rand 0.8.5", "redox_syscall", "remove_dir_all", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -11725,8 +11805,8 @@ dependencies = [ [[package]] name = "test-runtime-constants" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-support", "polkadot-primitives", @@ -11752,24 +11832,30 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "thousands" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" + [[package]] name = "thread_local" version = "1.1.4" @@ -11820,7 +11906,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -11853,6 +11939,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.5.1" @@ -11870,22 +11965,23 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" dependencies = [ - "bytes 1.1.0", + "autocfg", + "bytes", "libc", "memchr", - "mio 0.8.1", + "mio", "num_cpus", "once_cell", - "parking_lot 0.12.0", - "pin-project-lite 0.2.7", + "parking_lot 0.12.1", + "pin-project-lite 0.2.9", "signal-hook-registry", - "socket2 0.4.4", + "socket2", "tokio-macros", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -11899,26 +11995,15 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls 0.19.1", - "tokio", - "webpki 0.21.4", -] - [[package]] name = "tokio-rustls" version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" dependencies = [ - "rustls 0.20.4", + "rustls", "tokio", - "webpki 0.22.0", + "webpki", ] [[package]] @@ -11928,7 +12013,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", "tokio", ] @@ -11938,12 +12023,25 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", - "futures-io", "futures-sink", "log", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite 0.2.9", "tokio", ] @@ -11964,22 +12062,22 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.7", + "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.20" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -11988,11 +12086,11 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.23" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ - "lazy_static", + "once_cell", "valuable", ] @@ -12002,15 +12100,38 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 1.0.10", + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-gum" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" +dependencies = [ + "polkadot-node-jaeger", + "polkadot-primitives", "tracing", + "tracing-gum-proc-macro", +] + +[[package]] +name = "tracing-gum-proc-macro" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" +dependencies = [ + "expander 0.0.6", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "tracing-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -12052,12 +12173,12 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" +checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" dependencies = [ "hash-db", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "log", "rustc-hex", "smallvec", @@ -12074,9 +12195,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -12085,7 +12206,7 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.2.3", + "idna", "ipnet", "lazy_static", "log", @@ -12093,14 +12214,14 @@ dependencies = [ "smallvec", "thiserror", "tinyvec", - "url 2.2.2", + "url", ] [[package]] name = "trust-dns-resolver" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" dependencies = [ "cfg-if 1.0.0", "futures-util", @@ -12108,7 +12229,7 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "resolv-conf", "smallvec", "thiserror", @@ -12124,10 +12245,10 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#89fcb3e4f62d221d4e161a437768e77d6265889e" +source = "git+https://github.com/paritytech//substrate?branch=sv-locked-for-gav-xcm-v3-and-bridges#57e3486d9c7bb4deaef33cf9ba2da083b4e40314" dependencies = [ - "clap 3.1.6", - "jsonrpsee 0.4.1", + "clap 3.2.18", + "jsonrpsee", "log", "parity-scale-codec", "remote-externalities", @@ -12154,11 +12275,11 @@ checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" [[package]] name = "twox-hash" -version = "1.6.2" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.3", "rand 0.8.5", "static_assertions", @@ -12203,6 +12324,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -12240,32 +12367,14 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsigned-varint" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" - -[[package]] -name = "unsigned-varint" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35581ff83d4101e58b582e607120c7f5ffb17e632a980b1f38334d76b36908b2" -dependencies = [ - "asynchronous-codec 0.5.0", - "bytes 1.1.0", - "futures-io", - "futures-util", -] - [[package]] name = "unsigned-varint" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ - "asynchronous-codec 0.6.0", - "bytes 1.1.0", + "asynchronous-codec", + "bytes", "futures-io", "futures-util", ] @@ -12276,17 +12385,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.2.2" @@ -12294,9 +12392,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna 0.2.3", + "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", ] [[package]] @@ -12307,9 +12405,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.0.0-alpha.8" +version = "1.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" dependencies = [ "ctor", "version_check", @@ -12352,7 +12450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi 0.3.9", + "winapi", "winapi-util", ] @@ -12476,7 +12574,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.21", + "futures", "js-sys", "parking_lot 0.11.2", "pin-utils", @@ -12493,6 +12591,7 @@ checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" dependencies = [ "downcast-rs", "libc", + "libm", "memory_units", "num-rational 0.2.4", "num-traits", @@ -12511,31 +12610,33 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.81.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" +checksum = "570460c58b21e9150d2df0eaaedbb7816c34bcec009ae0dcc976e40ba81463e7" +dependencies = [ + "indexmap", +] [[package]] name = "wasmtime" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414be1bc5ca12e755ffd3ff7acc3a6d1979922f8237fc34068b2156cebcc3270" +checksum = "1f50eadf868ab6a04b7b511460233377d0bfbb92e417b2f6a98b98fef2e098f5" dependencies = [ "anyhow", "backtrace", "bincode", "cfg-if 1.0.0", - "cpp_demangle", "indexmap", "lazy_static", "libc", "log", - "object", + "object 0.28.4", + "once_cell", "paste", "psm", "rayon", "region", - "rustc-demangle", "serde", "target-lexicon", "wasmparser", @@ -12544,14 +12645,14 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "winapi 0.3.9", + "winapi", ] [[package]] name = "wasmtime-cache" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9b4cd1949206fda9241faf8c460a7d797aa1692594d3dd6bc1cbfa57ee20d0" +checksum = "d1df23c642e1376892f3b72f311596976979cbf8b85469680cdd3a8a063d12a2" dependencies = [ "anyhow", "base64", @@ -12559,19 +12660,19 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix", + "rustix 0.33.7", "serde", "sha2 0.9.8", "toml", - "winapi 0.3.9", + "winapi", "zstd", ] [[package]] name = "wasmtime-cranelift" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4693d33725773615a4c9957e4aa731af57b27dca579702d1d8ed5750760f1a9" +checksum = "f264ff6b4df247d15584f2f53d009fbc90032cfdc2605b52b961bffc71b6eccd" dependencies = [ "anyhow", "cranelift-codegen", @@ -12582,7 +12683,7 @@ dependencies = [ "gimli", "log", "more-asserts", - "object", + "object 0.28.4", "target-lexicon", "thiserror", "wasmparser", @@ -12591,9 +12692,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b17e47116a078b9770e6fb86cff8b9a660826623cebcfff251b047c8d8993ef" +checksum = "839d2820e4b830f4b9e7aa08d4c0acabf4a5036105d639f6dfa1c6891c73bdc6" dependencies = [ "anyhow", "cranelift-entity", @@ -12601,7 +12702,7 @@ dependencies = [ "indexmap", "log", "more-asserts", - "object", + "object 0.28.4", "serde", "target-lexicon", "thiserror", @@ -12611,56 +12712,72 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60ea5b380bdf92e32911400375aeefb900ac9d3f8e350bb6ba555a39315f2ee7" +checksum = "ef0a0bcbfa18b946d890078ba0e1bc76bcc53eccfb40806c0020ec29dcd1bd49" dependencies = [ "addr2line", "anyhow", "bincode", "cfg-if 1.0.0", + "cpp_demangle", "gimli", - "object", + "log", + "object 0.28.4", "region", - "rustix", + "rustc-demangle", + "rustix 0.33.7", "serde", "target-lexicon", "thiserror", "wasmtime-environ", + "wasmtime-jit-debug", "wasmtime-runtime", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4779d976206c458edd643d1ac622b6c37e4a0800a8b1d25dfbf245ac2f2cac" +dependencies = [ + "lazy_static", + "object 0.28.4", + "rustix 0.33.7", ] [[package]] name = "wasmtime-runtime" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abc7cd79937edd6e238b337608ebbcaf9c086a8457f01dfd598324f7fa56d81a" +checksum = "b7eb6ffa169eb5dcd18ac9473c817358cd57bc62c244622210566d473397954a" dependencies = [ "anyhow", "backtrace", "cc", "cfg-if 1.0.0", "indexmap", - "lazy_static", "libc", "log", "mach", + "memfd", "memoffset", "more-asserts", "rand 0.8.5", "region", - "rustix", + "rustix 0.33.7", "thiserror", "wasmtime-environ", - "winapi 0.3.9", + "wasmtime-jit-debug", + "winapi", ] [[package]] name = "wasmtime-types" -version = "0.33.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e5e51a461a2cf2b69e1fc48f325b17d78a8582816e18479e8ead58844b23f8" +checksum = "8d932b0ac5336f7308d869703dd225610a6a3aeaa8e968c52b43eed96cefb1c2" dependencies = [ "cranelift-entity", "serde", @@ -12678,16 +12795,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki" version = "0.22.0" @@ -12698,22 +12805,13 @@ dependencies = [ "untrusted", ] -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki 0.21.4", -] - [[package]] name = "webpki-roots" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" dependencies = [ - "webpki 0.22.0", + "webpki", ] [[package]] @@ -12738,15 +12836,9 @@ dependencies = [ [[package]] name = "widestring" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" - -[[package]] -name = "winapi" -version = "0.2.8" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" [[package]] name = "winapi" @@ -12758,12 +12850,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -12776,7 +12862,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -12785,17 +12871,43 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +dependencies = [ + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", +] + [[package]] name = "windows-sys" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.32.0", + "windows_i686_gnu 0.32.0", + "windows_i686_msvc 0.32.0", + "windows_x86_64_gnu 0.32.0", + "windows_x86_64_msvc 0.32.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] [[package]] @@ -12804,24 +12916,72 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_i686_gnu" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + [[package]] name = "windows_i686_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_x86_64_gnu" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -12829,22 +12989,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] -name = "winreg" -version = "0.6.2" +name = "windows_x86_64_msvc" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -dependencies = [ - "winapi 0.3.9", -] +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "windows_x86_64_msvc" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "winapi", ] [[package]] @@ -12869,24 +13031,28 @@ dependencies = [ [[package]] name = "xcm" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "derivative", "impl-trait-for-tuples", "log", "parity-scale-codec", "scale-info", + "serde", + "sp-io", + "sp-runtime", "xcm-procedural", ] [[package]] name = "xcm-builder" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-support", "frame-system", + "impl-trait-for-tuples", "log", "pallet-transaction-payment", "parity-scale-codec", @@ -12902,8 +13068,8 @@ dependencies = [ [[package]] name = "xcm-executor" -version = "0.9.18" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -12919,8 +13085,8 @@ dependencies = [ [[package]] name = "xcm-procedural" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot?branch=master#975e780ae0d988dc033f400ba822d14b326ee5b9" +version = "0.9.27" +source = "git+https://github.com/paritytech//polkadot?branch=locked-for-gav-xcm-v3-and-bridges#dd02a13f43b4fabb5293027d6977b59fb0050eed" dependencies = [ "Inflector", "proc-macro2", @@ -12930,32 +13096,32 @@ dependencies = [ [[package]] name = "yamux" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107" +checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5" dependencies = [ - "futures 0.3.21", + "futures", "log", "nohash-hasher", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "rand 0.8.5", "static_assertions", ] [[package]] name = "zeroize" -version = "1.4.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +checksum = "7eb5728b8afd3f280a869ce1d4c554ffaed35f45c231fc41bfbd0381bef50317" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.2.2" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", "quote", @@ -12965,18 +13131,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.9.2+zstd.1.5.1" +version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.3+zstd.1.5.1" +version = "5.0.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" dependencies = [ "libc", "zstd-sys", @@ -12984,9 +13150,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.2+zstd.1.5.1" +version = "2.0.1+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 1090a0fe5b..0af32c9ca9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,239 @@ members = [ "primitives/*", "relays/*", ] + +# we need to be able to work with XCMv3, but it is not yet in Polkadot master +# => manual patch is required. Because of https://github.com/rust-lang/cargo/issues/5478 +# we need to use double slash in the repo name. +# +# Once XCMv3 PR is merged, we may remove both Substrate and Polkadot patch section. + +[patch."https://github.com/paritytech/substrate"] +beefy-gadget = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +beefy-gadget-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +beefy-merkle-tree = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +beefy-primitives = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +fork-tree = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-benchmarking = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-benchmarking-cli = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-election-provider-solution-type = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-election-provider-support = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-executive = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-support = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-support-procedural = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-support-procedural-tools = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-support-procedural-tools-derive = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-system = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-system-benchmarking = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +frame-try-runtime = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +node-inspect = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-aura = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-authority-discovery = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-authorship = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-babe = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-bags-list = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-balances = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-beefy = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-beefy-mmr = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-bounties = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-child-bounties = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-collective = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-democracy = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-election-provider-multi-phase = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-elections-phragmen = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-gilt = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-grandpa = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-identity = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-im-online = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-indices = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-membership = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-mmr = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-mmr-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-multisig = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +#pallet-nicks = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-nomination-pools = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-nomination-pools-runtime-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-offences = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-preimage = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-proxy = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-randomness-collective-flip = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-recovery = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-scheduler = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-session = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-society = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-staking = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-staking-reward-curve = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-staking-reward-fn = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-sudo = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-timestamp = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-tips = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-transaction-payment = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-treasury = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-utility = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +pallet-vesting = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +remote-externalities = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-allocator = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-authority-discovery = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-basic-authorship = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-block-builder = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-chain-spec = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-chain-spec-derive = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-cli = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-client-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-client-db = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus-aura = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus-babe = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus-babe-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus-epochs = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus-slots = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-consensus-uncles = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-executor = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-executor-common = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-executor-wasmi = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-executor-wasmtime = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-finality-grandpa = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-finality-grandpa-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-informant = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-keystore = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-network = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-network-common = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-network-gossip = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-offchain = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-peerset = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-proposer-metrics = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-rpc-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-rpc-server = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-service = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-state-db = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-sync-state-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-sysinfo = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-telemetry = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-tracing = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-tracing-proc-macro = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-transaction-pool = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-transaction-pool-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sc-utils = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-api = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-api-proc-macro = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-application-crypto = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-arithmetic = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-authority-discovery = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-authorship = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-block-builder = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-blockchain = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-consensus = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-consensus-aura = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-consensus-babe = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-consensus-slots = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-consensus-vrf = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-core = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-core-hashing = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-core-hashing-proc-macro = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-database = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-debug-derive = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-externalities = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-finality-grandpa = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-inherents = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-io = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-keyring = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-keystore = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-maybe-compressed-blob = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-mmr-primitives = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-npos-elections = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-offchain = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-panic-handler = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-runtime = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-runtime-interface = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-runtime-interface-proc-macro = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +#sp-serializer = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-session = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-staking = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-state-machine = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-std = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-storage = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-tasks = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-timestamp = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-tracing = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-transaction-pool = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-transaction-storage-proof = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-trie = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-version = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-version-proc-macro = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +sp-wasm-interface = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +substrate-build-script-utils = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +substrate-frame-rpc-system = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +substrate-prometheus-endpoint = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +substrate-state-trie-migration-rpc = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +substrate-test-client = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +substrate-wasm-builder = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } +try-runtime-cli = { git = "https://github.com/paritytech//substrate", branch = "sv-locked-for-gav-xcm-v3-and-bridges" } + +[patch."https://github.com/paritytech/polkadot"] +kusama-runtime = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +kusama-runtime-constants = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +#metered-channel = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +pallet-xcm = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-approval-distribution = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-availability-bitfield-distribution = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-availability-distribution = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-availability-recovery = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-cli = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-client = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-collator-protocol = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-core-primitives = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-dispute-distribution = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-erasure-coding = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-gossip-support = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-network-bridge = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-collation-generation = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-approval-voting = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-av-store = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-backing = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-bitfield-signing = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-candidate-validation = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-chain-api = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-chain-selection = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-dispute-coordinator = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-parachains-inherent = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-provisioner = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-pvf = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-pvf-checker = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-core-runtime-api = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-jaeger = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-metrics = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-network-protocol = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-primitives = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-subsystem = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-subsystem-types = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-node-subsystem-util = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-overseer = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +#polkadot-overseer-gen = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +#polkadot-overseer-gen-proc-macro = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-parachain = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-performance-test = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-primitives = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-rpc = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-runtime = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-runtime-common = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-runtime-constants = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-runtime-metrics = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-service = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-statement-distribution = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-statement-table = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-test-runtime = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +polkadot-test-service = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +slot-range-helper = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +test-runtime-constants = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +tracing-gum = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +tracing-gum-proc-macro = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +xcm = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +xcm-builder = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +xcm-executor = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } +xcm-procedural = { git = "https://github.com/paritytech//polkadot", branch = "locked-for-gav-xcm-v3-and-bridges" } diff --git a/Dockerfile b/Dockerfile index bc51f76ba9..a64b59e708 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,8 @@ # # See the `deployments/README.md` for all the available `PROJECT` values. -FROM docker.io/paritytech/bridges-ci:latest as builder +FROM docker.io/paritytech/bridges-ci:production as builder +USER root WORKDIR /parity-bridges-common COPY . . diff --git a/README.md b/README.md index ac3e49b94c..d45b328b2b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,11 @@ Substrate chains. 🚧 The bridges are currently under construction - a hardhat is recommended beyond this point 🚧 +**IMPORTANT**: this documentation is outdated and it is mostly related to the previous version of our +bridge. Right there's an ongoing work to make our bridge work with XCM messages. Old bridge is still +available at [encoded-calls-messaging](https://github.com/paritytech/parity-bridges-common/releases/tag/encoded-calls-messaging) +tag. + ## Contents - [Installation](#installation) @@ -57,8 +62,8 @@ docker run --rm -it -w /shellhere/parity-bridges-common \ If you want to reproduce other steps of CI process you can use the following [guide](https://github.com/paritytech/scripts#reproduce-ci-locally). -If you need more information about setting up your development environment Substrate's -[Getting Started](https://substrate.dev/docs/en/knowledgebase/getting-started/) page is a good +If you need more information about setting up your development environment [Substrate's +Installation page](https://docs.substrate.io/main-docs/install/) is a good resource. ## High-Level Architecture diff --git a/bin/millau/node/Cargo.toml b/bin/millau/node/Cargo.toml index 3825b92b70..e83f3c4f56 100644 --- a/bin/millau/node/Cargo.toml +++ b/bin/millau/node/Cargo.toml @@ -5,14 +5,13 @@ version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" build = "build.rs" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] clap = { version = "3.1", features = ["derive"] } -jsonrpc-core = "18.0" -serde_json = "1.0.59" +jsonrpsee = { version = "0.15.1", features = ["server"] } +serde_json = "1.0.79" # Bridge dependencies diff --git a/bin/millau/node/src/chain_spec.rs b/bin/millau/node/src/chain_spec.rs index a7e3c7c877..66ab997aa7 100644 --- a/bin/millau/node/src/chain_spec.rs +++ b/bin/millau/node/src/chain_spec.rs @@ -15,17 +15,31 @@ // along with Parity Bridges Common. If not, see . use beefy_primitives::crypto::AuthorityId as BeefyId; -use bp_millau::derive_account_from_rialto_id; use millau_runtime::{ AccountId, AuraConfig, BalancesConfig, BeefyConfig, BridgeRialtoMessagesConfig, - BridgeWestendGrandpaConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, - Signature, SudoConfig, SystemConfig, WASM_BINARY, + BridgeRialtoParachainMessagesConfig, BridgeWestendGrandpaConfig, GenesisConfig, GrandpaConfig, + SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY, }; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{sr25519, Pair, Public}; use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; +/// "Names" of the authorities accounts at local testnet. +const LOCAL_AUTHORITIES_ACCOUNTS: [&str; 5] = ["Alice", "Bob", "Charlie", "Dave", "Eve"]; +/// "Names" of the authorities accounts at development testnet. +const DEV_AUTHORITIES_ACCOUNTS: [&str; 1] = [LOCAL_AUTHORITIES_ACCOUNTS[0]]; +/// "Names" of all possible authorities accounts. +const ALL_AUTHORITIES_ACCOUNTS: [&str; 5] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Name" of the `sudo` account. +const SUDO_ACCOUNT: &str = "Sudo"; +/// "Name" of the account, which owns the with-Westend GRANDPA pallet. +const WESTEND_GRANDPA_PALLET_OWNER: &str = "Westend.GrandpaOwner"; +/// "Name" of the account, which owns the with-Rialto messages pallet. +const RIALTO_MESSAGES_PALLET_OWNER: &str = "Rialto.MessagesOwner"; +/// "Name" of the account, which owns the with-RialtoParachain messages pallet. +const RIALTO_PARACHAIN_MESSAGES_PALLET_OWNER: &str = "RialtoParachain.MessagesOwner"; + /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. pub type ChainSpec = sc_service::GenericChainSpec; @@ -86,8 +100,11 @@ impl Alternative { sc_service::ChainType::Development, || { testnet_genesis( - vec![get_authority_keys_from_seed("Alice")], - get_account_id_from_seed::("Alice"), + DEV_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), endowed_accounts(), true, ) @@ -105,14 +122,11 @@ impl Alternative { sc_service::ChainType::Local, || { testnet_genesis( - vec![ - get_authority_keys_from_seed("Alice"), - get_authority_keys_from_seed("Bob"), - get_authority_keys_from_seed("Charlie"), - get_authority_keys_from_seed("Dave"), - get_authority_keys_from_seed("Eve"), - ], - get_account_id_from_seed::("Alice"), + LOCAL_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), endowed_accounts(), true, ) @@ -133,48 +147,41 @@ impl Alternative { /// accounts used by relayers in our test deployments, accounts used for demonstration /// purposes), are all available on these chains. fn endowed_accounts() -> Vec { + let all_authorities = ALL_AUTHORITIES_ACCOUNTS.iter().flat_map(|x| { + [ + get_account_id_from_seed::(x), + get_account_id_from_seed::(&format!("{}//stash", x)), + ] + }); vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), + // Sudo account + get_account_id_from_seed::(SUDO_ACCOUNT), + // Regular (unused) accounts get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("George"), - get_account_id_from_seed::("Harry"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), - get_account_id_from_seed::("George//stash"), - get_account_id_from_seed::("Harry//stash"), - get_account_id_from_seed::("RialtoMessagesOwner"), - get_account_id_from_seed::("WithRialtoTokenSwap"), - pallet_bridge_messages::relayer_fund_account_id::< - bp_millau::AccountId, - bp_millau::AccountIdConverter, - >(), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Alice"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Bob"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Charlie"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Dave"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Eve"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Ferdie"), - )), + // Accounts, used by Westend<>Millau bridge + get_account_id_from_seed::(WESTEND_GRANDPA_PALLET_OWNER), + get_account_id_from_seed::("Westend.HeadersRelay1"), + get_account_id_from_seed::("Westend.HeadersRelay2"), + get_account_id_from_seed::("Westend.WestmintHeaders1"), + get_account_id_from_seed::("Westend.WestmintHeaders2"), + // Accounts, used by Rialto<>Millau bridge + get_account_id_from_seed::(RIALTO_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("Rialto.HeadersAndMessagesRelay"), + get_account_id_from_seed::("Rialto.OutboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Rialto.InboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Rialto.MessagesSender"), + // Accounts, used by RialtoParachain<>Millau bridge + get_account_id_from_seed::(RIALTO_PARACHAIN_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("RialtoParachain.HeadersAndMessagesRelay1"), + get_account_id_from_seed::("RialtoParachain.HeadersAndMessagesRelay2"), + get_account_id_from_seed::("RialtoParachain.RialtoHeadersRelay1"), + get_account_id_from_seed::("RialtoParachain.RialtoHeadersRelay2"), + get_account_id_from_seed::("RialtoParachain.MessagesSender"), ] + .into_iter() + .chain(all_authorities) + .collect() } fn session_keys(aura: AuraId, beefy: BeefyId, grandpa: GrandpaId) -> SessionKeys { @@ -209,21 +216,20 @@ fn testnet_genesis( bridge_westend_grandpa: BridgeWestendGrandpaConfig { // for our deployments to avoid multiple same-nonces transactions: // //Alice is already used to initialize Rialto<->Millau bridge - // => let's use //George to initialize Westend->Millau bridge - owner: Some(get_account_id_from_seed::("George")), + // => let's use //Westend.GrandpaOwner to initialize Westend->Millau bridge + owner: Some(get_account_id_from_seed::(WESTEND_GRANDPA_PALLET_OWNER)), ..Default::default() }, bridge_rialto_messages: BridgeRialtoMessagesConfig { - owner: Some(get_account_id_from_seed::("RialtoMessagesOwner")), + owner: Some(get_account_id_from_seed::(RIALTO_MESSAGES_PALLET_OWNER)), + ..Default::default() + }, + bridge_rialto_parachain_messages: BridgeRialtoParachainMessagesConfig { + owner: Some(get_account_id_from_seed::( + RIALTO_PARACHAIN_MESSAGES_PALLET_OWNER, + )), ..Default::default() }, + xcm_pallet: Default::default(), } } - -#[test] -fn derived_dave_account_is_as_expected() { - let dave = get_account_id_from_seed::("Dave"); - let derived: AccountId = - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(dave)); - assert_eq!(derived.to_string(), "5DNW6UVnb7TN6wX5KwXtDYR3Eccecbdzuw89HqjyNfkzce6J".to_string()); -} diff --git a/bin/millau/node/src/cli.rs b/bin/millau/node/src/cli.rs index c3c3d134e3..0280254bca 100644 --- a/bin/millau/node/src/cli.rs +++ b/bin/millau/node/src/cli.rs @@ -67,5 +67,6 @@ pub enum Subcommand { Inspect(node_inspect::cli::InspectCmd), /// Benchmark runtime pallets. + #[clap(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), } diff --git a/bin/millau/node/src/command.rs b/bin/millau/node/src/command.rs index 4dbf9575df..e9f94b03a2 100644 --- a/bin/millau/node/src/command.rs +++ b/bin/millau/node/src/command.rs @@ -19,6 +19,7 @@ use crate::{ service, service::new_partial, }; +use frame_benchmarking_cli::BenchmarkCmd; use millau_runtime::{Block, RuntimeApi}; use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; @@ -77,18 +78,23 @@ pub fn run() -> sc_cli::Result<()> { )); match &cli.subcommand { - Some(Subcommand::Benchmark(cmd)) => - if cfg!(feature = "runtime-benchmarks") { - let runner = cli.create_runner(cmd)?; - - runner.sync_run(|config| cmd.run::(config)) - } else { - println!( - "Benchmarking wasn't enabled when building the node. \ - You can enable it with `--features runtime-benchmarks`." - ); - Ok(()) - }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner + .sync_run(|config| cmd.run::(config)) + } else { + println!( + "Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + ); + Ok(()) + }, + _ => Err("Unsupported benchmarking subcommand".into()), + } + }, Some(Subcommand::Key(cmd)) => cmd.run(&cli), Some(Subcommand::Sign(cmd)) => cmd.run(), Some(Subcommand::Verify(cmd)) => cmd.run(), @@ -135,7 +141,7 @@ pub fn run() -> sc_cli::Result<()> { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { let PartialComponents { client, task_manager, backend, .. } = new_partial(&config)?; - Ok((cmd.run(client, backend), task_manager)) + Ok((cmd.run(client, backend, None), task_manager)) }) }, Some(Subcommand::Inspect(cmd)) => { diff --git a/bin/millau/node/src/service.rs b/bin/millau/node/src/service.rs index 15f88269aa..5b4461f3ca 100644 --- a/bin/millau/node/src/service.rs +++ b/bin/millau/node/src/service.rs @@ -16,19 +16,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// UPDATE GUIDE: -// 1) replace everything with node-template/src/service.rs contents (found in main Substrate repo); -// 2) from old code keep `rpc_extensions_builder` - we use our own custom RPCs; -// 3) from old code keep the Beefy gadget; -// 4) fix compilation errors; -// 5) test :) -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== - +use jsonrpsee::RpcModule; use millau_runtime::{self, opaque::Block, RuntimeApi}; use sc_client_api::{BlockBackend, ExecutorProvider}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; @@ -83,6 +71,8 @@ pub fn new_partial( FullSelectChain, >, sc_finality_grandpa::LinkHalf, + beefy_gadget::BeefyVoterLinks, + beefy_gadget::BeefyRPCLinks, Option, ), >, @@ -140,11 +130,18 @@ pub fn new_partial( telemetry.as_ref().map(|x| x.handle()), )?; + let (beefy_block_import, beefy_voter_links, beefy_rpc_links) = + beefy_gadget::beefy_block_import_and_links( + grandpa_block_import.clone(), + backend.clone(), + client.clone(), + ); + let slot_duration = sc_consensus_aura::slot_duration(&*client)?; let import_queue = sc_consensus_aura::import_queue::(ImportQueueParams { - block_import: grandpa_block_import.clone(), + block_import: beefy_block_import, justification_import: Some(Box::new(grandpa_block_import.clone())), client: client.clone(), create_inherent_data_providers: move |_, ()| async move { @@ -175,7 +172,7 @@ pub fn new_partial( keystore_container, select_chain, transaction_pool, - other: (grandpa_block_import, grandpa_link, telemetry), + other: (grandpa_block_import, grandpa_link, beefy_voter_links, beefy_rpc_links, telemetry), }) } @@ -196,7 +193,7 @@ pub fn new_full(mut config: Configuration) -> Result mut keystore_container, select_chain, transaction_pool, - other: (block_import, grandpa_link, mut telemetry), + other: (block_import, grandpa_link, beefy_voter_links, beefy_rpc_links, mut telemetry), } = new_partial(&config)?; if let Some(url) = &config.keystore_remote { @@ -264,18 +261,16 @@ pub fn new_full(mut config: Configuration) -> Result let enable_grandpa = !config.disable_grandpa; let prometheus_registry = config.prometheus_registry().cloned(); let shared_voter_state = SharedVoterState::empty(); - let (beefy_commitment_link, beefy_commitment_stream) = - beefy_gadget::notification::BeefySignedCommitmentStream::::channel(); - let (beefy_best_block_link, beefy_best_block_stream) = - beefy_gadget::notification::BeefyBestBlockStream::::channel(); let rpc_extensions_builder = { use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider; - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; - use sc_finality_grandpa_rpc::{GrandpaApi, GrandpaRpcHandler}; + use beefy_gadget_rpc::{Beefy, BeefyApiServer}; + use pallet_mmr_rpc::{Mmr, MmrApiServer}; + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use sc_finality_grandpa_rpc::{Grandpa, GrandpaApiServer}; use sc_rpc::DenyUnsafe; - use substrate_frame_rpc_system::{FullSystem, SystemApi}; + use substrate_frame_rpc_system::{System, SystemApiServer}; let backend = backend.clone(); let client = client.clone(); @@ -291,33 +286,33 @@ pub fn new_full(mut config: Configuration) -> Result ); Box::new(move |_, subscription_executor: sc_rpc::SubscriptionTaskExecutor| { - let mut io = jsonrpc_core::IoHandler::default(); - io.extend_with(SystemApi::to_delegate(FullSystem::new( - client.clone(), - pool.clone(), - DenyUnsafe::No, - ))); - io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new( - client.clone(), - ))); - io.extend_with(GrandpaApi::to_delegate(GrandpaRpcHandler::new( - shared_authority_set.clone(), - shared_voter_state.clone(), - justification_stream.clone(), - subscription_executor.clone(), - finality_proof_provider.clone(), - ))); - io.extend_with(beefy_gadget_rpc::BeefyApi::to_delegate( - beefy_gadget_rpc::BeefyRpcHandler::::new( - beefy_commitment_stream.clone(), - beefy_best_block_stream.clone(), + let mut io = RpcModule::new(()); + let map_err = |e| sc_service::Error::Other(format!("{}", e)); + io.merge(System::new(client.clone(), pool.clone(), DenyUnsafe::No).into_rpc()) + .map_err(map_err)?; + io.merge(TransactionPayment::new(client.clone()).into_rpc()).map_err(map_err)?; + io.merge( + Grandpa::new( + subscription_executor.clone(), + shared_authority_set.clone(), + shared_voter_state.clone(), + justification_stream.clone(), + finality_proof_provider.clone(), + ) + .into_rpc(), + ) + .map_err(map_err)?; + io.merge( + Beefy::::new( + beefy_rpc_links.from_voter_justif_stream.clone(), + beefy_rpc_links.from_voter_best_beefy_stream.clone(), subscription_executor, ) - .map_err(|e| sc_service::Error::Other(format!("{}", e)))?, - )); - io.extend_with(pallet_mmr_rpc::MmrApi::to_delegate(pallet_mmr_rpc::Mmr::new( - client.clone(), - ))); + .map_err(|e| sc_service::Error::Other(format!("{}", e)))? + .into_rpc(), + ) + .map_err(map_err)?; + io.merge(Mmr::new(client.clone()).into_rpc()).map_err(map_err)?; Ok(io) }) }; @@ -328,7 +323,7 @@ pub fn new_full(mut config: Configuration) -> Result keystore: keystore_container.sync_keystore(), task_manager: &mut task_manager, transaction_pool: transaction_pool.clone(), - rpc_extensions_builder, + rpc_builder: rpc_extensions_builder.clone(), backend: backend.clone(), system_rpc_tx, config, @@ -392,22 +387,22 @@ pub fn new_full(mut config: Configuration) -> Result if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None }; let beefy_params = beefy_gadget::BeefyParams { - client, + client: client.clone(), backend, + runtime: client, key_store: keystore.clone(), network: network.clone(), - signed_commitment_sender: beefy_commitment_link, - beefy_best_block_sender: beefy_best_block_link, - min_block_delta: 4, + min_block_delta: 2, prometheus_registry: prometheus_registry.clone(), protocol_name: beefy_protocol_name, + links: beefy_voter_links, }; // Start the BEEFY bridge gadget. task_manager.spawn_essential_handle().spawn_blocking( "beefy-gadget", None, - beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params), + beefy_gadget::start_beefy_gadget::<_, _, _, _, _>(beefy_params), ); let grandpa_config = sc_finality_grandpa::Config { diff --git a/bin/millau/runtime/Cargo.toml b/bin/millau/runtime/Cargo.toml index 162404b77e..05e79074b6 100644 --- a/bin/millau/runtime/Cargo.toml +++ b/bin/millau/runtime/Cargo.toml @@ -3,31 +3,33 @@ name = "millau-runtime" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] hex-literal = "0.3" -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge dependencies bp-header-chain = { path = "../../../primitives/header-chain", default-features = false } -bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false } bp-messages = { path = "../../../primitives/messages", default-features = false } bp-millau = { path = "../../../primitives/chain-millau", default-features = false } +bp-polkadot-core = { path = "../../../primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../../primitives/relayers", default-features = false } bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false } +bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain", default-features = false } bp-runtime = { path = "../../../primitives/runtime", default-features = false } bp-westend = { path = "../../../primitives/chain-westend", default-features = false } bridge-runtime-common = { path = "../../runtime-common", default-features = false } -pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false } pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../../modules/messages", default-features = false } -pallet-bridge-token-swap = { path = "../../../modules/token-swap", default-features = false } +pallet-bridge-parachains = { path = "../../../modules/parachains", default-features = false } +pallet-bridge-relayers = { path = "../../../modules/relayers", default-features = false } pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false } # Substrate Dependencies @@ -44,7 +46,6 @@ pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "mast pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -57,6 +58,8 @@ sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -65,8 +68,16 @@ sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +# Polkadot Dependencies + +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } + [dev-dependencies] bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test"] } +env_logger = "0.8" static_assertions = "1.1" [build-dependencies] @@ -77,10 +88,12 @@ default = ["std"] std = [ "beefy-primitives/std", "bp-header-chain/std", - "bp-message-dispatch/std", "bp-messages/std", "bp-millau/std", + "bp-polkadot-core/std", + "bp-relayers/std", "bp-rialto/std", + "bp-rialto-parachain/std", "bp-runtime/std", "bp-westend/std", "bridge-runtime-common/std", @@ -89,14 +102,15 @@ std = [ "frame-support/std", "frame-system-rpc-runtime-api/std", "frame-system/std", + "log/std", "pallet-aura/std", "pallet-balances/std", "pallet-beefy/std", "pallet-beefy-mmr/std", - "pallet-bridge-dispatch/std", "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", - "pallet-bridge-token-swap/std", + "pallet-bridge-parachains/std", + "pallet-bridge-relayers/std", "pallet-grandpa/std", "pallet-mmr/std", "pallet-randomness-collective-flip/std", @@ -106,6 +120,7 @@ std = [ "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", + "pallet-xcm/std", "scale-info/std", "serde", "sp-api/std", @@ -114,6 +129,7 @@ std = [ "sp-core/std", "sp-finality-grandpa/std", "sp-inherents/std", + "sp-io/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -121,6 +137,9 @@ std = [ "sp-transaction-pool/std", "sp-trie/std", "sp-version/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", ] runtime-benchmarks = [ "bridge-runtime-common/runtime-benchmarks", @@ -129,6 +148,9 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "libsecp256k1", "pallet-bridge-messages/runtime-benchmarks", - "pallet-bridge-token-swap/runtime-benchmarks", + "pallet-bridge-parachains/runtime-benchmarks", + "pallet-bridge-relayers/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", ] diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index d2da5affb2..2fea97cea8 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -29,49 +29,65 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod rialto_messages; - -use crate::rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge}; +pub mod rialto_parachain_messages; +pub mod xcm_config; + +use crate::{ + rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge}, + rialto_parachain_messages::{ + ToRialtoParachainMessagePayload, WithRialtoParachainMessageBridge, + }, +}; use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet}; +use bp_runtime::{HeaderId, HeaderIdProvider}; use bridge_runtime_common::messages::{ source::estimate_message_dispatch_and_delivery_fee, MessageBridge, }; +use codec::Decode; use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; -use pallet_mmr_primitives::{ - DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof, -}; use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo}; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_mmr_primitives::{DataOrHash, EncodableOpaqueLeaf, Error as MmrError, Proof as MmrProof}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perquintill, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perquintill, }; use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; +// to be able to use Millau runtime in `bridge-runtime-common` tests +pub use bridge_runtime_common; + // A few exports that help ease life for downstream crates. pub use frame_support::{ construct_runtime, parameter_types, traits::{Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem}, - weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, RuntimeDbWeight, Weight}, - StorageValue, + weights::{ + constants::WEIGHT_PER_SECOND, ConstantMultiplier, DispatchClass, IdentityFee, + RuntimeDbWeight, Weight, + }, + RuntimeDebug, StorageValue, }; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall; pub use pallet_bridge_messages::Call as MessagesCall; +pub use pallet_bridge_parachains::Call as BridgeParachainsCall; pub use pallet_sudo::Call as SudoCall; pub use pallet_timestamp::Call as TimestampCall; +pub use pallet_xcm::Call as XcmCall; +use bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; @@ -220,18 +236,8 @@ impl pallet_aura::Config for Runtime { impl pallet_beefy::Config for Runtime { type BeefyId = BeefyId; -} - -impl pallet_bridge_dispatch::Config for Runtime { - type Event = Event; - type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce); - type Call = Call; - type CallFilter = frame_support::traits::Everything; - type EncodedCall = crate::rialto_messages::FromRialtoEncodedCall; - type SourceChainAccountId = bp_rialto::AccountId; - type TargetChainAccountPublic = MultiSigner; - type TargetChainSignature = MultiSignature; - type AccountIdConverter = bp_millau::AccountIdConverter; + type MaxAuthorities = MaxAuthorities; + type OnNewValidatorSet = MmrLeaf; } impl pallet_grandpa::Config for Runtime { @@ -250,12 +256,21 @@ impl pallet_grandpa::Config for Runtime { type MaxAuthorities = MaxAuthorities; } -type MmrHash = ::Output; +/// MMR helper types. +mod mmr { + use super::Runtime; + pub use pallet_mmr::primitives::*; + use sp_runtime::traits::Keccak256; + + pub type Leaf = <::LeafData as LeafDataProvider>::LeafData; + pub type Hash = ::Output; + pub type Hashing = ::Hashing; +} impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = b"mmr"; type Hashing = Keccak256; - type Hash = MmrHash; + type Hash = mmr::Hash; type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; type WeightInfo = (); type LeafData = pallet_beefy_mmr::Pallet; @@ -278,10 +293,17 @@ parameter_types! { pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0); } +pub struct BeefyDummyDataProvider; + +impl beefy_primitives::mmr::BeefyDataProvider<()> for BeefyDummyDataProvider { + fn extra_data() {} +} + impl pallet_beefy_mmr::Config for Runtime { type LeafVersion = LeafVersion; type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; - type ParachainHeads = (); + type LeafExtra = (); + type BeefyDataProvider = BeefyDummyDataProvider; } parameter_types! { @@ -333,15 +355,16 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = bp_millau::WeightToFee; + type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< Runtime, TargetBlockFullness, AdjustmentVariable, MinimumMultiplier, >; + type Event = Event; } impl pallet_sudo::Config for Runtime { @@ -376,6 +399,13 @@ parameter_types! { pub const MaxRequests: u32 = 50; } +impl pallet_bridge_relayers::Config for Runtime { + type Event = Event; + type Reward = Balance; + type PaymentProcedure = bp_relayers::MintReward, AccountId>; + type WeightInfo = (); +} + #[cfg(feature = "runtime-benchmarks")] parameter_types! { /// Number of headers to keep in benchmarks. @@ -427,6 +457,7 @@ parameter_types! { bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _; pub const RootAccountForPayments: Option = None; pub const RialtoChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID; + pub const RialtoParachainChainId: bp_runtime::ChainId = bp_runtime::RIALTO_PARACHAIN_CHAIN_ID; } /// Instance of the messages pallet used to relay messages to/from Rialto chain. @@ -440,6 +471,7 @@ impl pallet_bridge_messages::Config for Runtime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = crate::rialto_messages::ToRialtoMaximalOutboundPayloadSize; type OutboundPayload = crate::rialto_messages::ToRialtoMessagePayload; type OutboundMessageFee = Balance; @@ -447,48 +479,85 @@ impl pallet_bridge_messages::Config for Runtime { type InboundMessageFee = bp_rialto::Balance; type InboundRelayer = bp_rialto::AccountId; - type AccountIdConverter = bp_millau::AccountIdConverter; - type TargetHeaderChain = crate::rialto_messages::Rialto; type LaneMessageVerifier = crate::rialto_messages::ToRialtoMessageVerifier; type MessageDeliveryAndDispatchPayment = - pallet_bridge_messages::instant_payments::InstantCurrencyPayments< + pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter< Runtime, WithRialtoMessagesInstance, - pallet_balances::Pallet, GetDeliveryConfirmationTransactionFee, >; type OnMessageAccepted = (); - type OnDeliveryConfirmed = - pallet_bridge_token_swap::Pallet; + type OnDeliveryConfirmed = (); type SourceHeaderChain = crate::rialto_messages::Rialto; type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch; type BridgedChainId = RialtoChainId; } +/// Instance of the messages pallet used to relay messages to/from RialtoParachain chain. +pub type WithRialtoParachainMessagesInstance = pallet_bridge_messages::Instance1; + +impl pallet_bridge_messages::Config for Runtime { + type Event = Event; + type WeightInfo = pallet_bridge_messages::weights::MillauWeight; + type Parameter = rialto_parachain_messages::MillauToRialtoParachainMessagesParameter; + type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = + crate::rialto_parachain_messages::ToRialtoParachainMaximalOutboundPayloadSize; + type OutboundPayload = crate::rialto_parachain_messages::ToRialtoParachainMessagePayload; + type OutboundMessageFee = Balance; + + type InboundPayload = crate::rialto_parachain_messages::FromRialtoParachainMessagePayload; + type InboundMessageFee = bp_rialto_parachain::Balance; + type InboundRelayer = bp_rialto_parachain::AccountId; + + type TargetHeaderChain = crate::rialto_parachain_messages::RialtoParachain; + type LaneMessageVerifier = crate::rialto_parachain_messages::ToRialtoParachainMessageVerifier; + type MessageDeliveryAndDispatchPayment = + pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter< + Runtime, + WithRialtoParachainMessagesInstance, + GetDeliveryConfirmationTransactionFee, + >; + type OnMessageAccepted = (); + type OnDeliveryConfirmed = (); + + type SourceHeaderChain = crate::rialto_parachain_messages::RialtoParachain; + type MessageDispatch = crate::rialto_parachain_messages::FromRialtoParachainMessageDispatch; + type BridgedChainId = RialtoParachainChainId; +} + parameter_types! { - pub const TokenSwapMessagesLane: bp_messages::LaneId = *b"swap"; + pub const RialtoParasPalletName: &'static str = bp_rialto::PARAS_PALLET_NAME; + pub const WestendParasPalletName: &'static str = bp_westend::PARAS_PALLET_NAME; } -/// Instance of the with-Rialto token swap pallet. -pub type WithRialtoTokenSwapInstance = (); +/// Instance of the with-Rialto parachains pallet. +pub type WithRialtoParachainsInstance = (); -impl pallet_bridge_token_swap::Config for Runtime { +impl pallet_bridge_parachains::Config for Runtime { type Event = Event; - type WeightInfo = (); + type WeightInfo = pallet_bridge_parachains::weights::MillauWeight; + type BridgesGrandpaPalletInstance = RialtoGrandpaInstance; + type ParasPalletName = RialtoParasPalletName; + type TrackedParachains = frame_support::traits::Everything; + type HeadsToKeep = HeadersToKeep; +} - type BridgedChainId = RialtoChainId; - type OutboundMessageLaneId = TokenSwapMessagesLane; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessagesBridge = pallet_bridge_messages::Pallet; - #[cfg(feature = "runtime-benchmarks")] - type MessagesBridge = bp_messages::source_chain::NoopMessagesBridge; - type ThisCurrency = pallet_balances::Pallet; - type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter; +/// Instance of the with-Westend parachains pallet. +pub type WithWestendParachainsInstance = pallet_bridge_parachains::Instance1; - type BridgedChain = bp_rialto::Rialto; - type FromBridgedToThisAccountIdConverter = bp_millau::AccountIdConverter; +impl pallet_bridge_parachains::Config for Runtime { + type Event = Event; + type WeightInfo = pallet_bridge_parachains::weights::MillauWeight; + type BridgesGrandpaPalletInstance = WestendGrandpaInstance; + type ParasPalletName = WestendParasPalletName; + type TrackedParachains = frame_support::traits::Everything; + type HeadsToKeep = HeadersToKeep; } construct_runtime!( @@ -505,7 +574,7 @@ construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, // Consensus support. Session: pallet_session::{Pallet, Call, Storage, Event, Config}, @@ -519,16 +588,33 @@ construct_runtime!( MmrLeaf: pallet_beefy_mmr::{Pallet, Storage}, // Rialto bridge modules. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage}, - BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event}, BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, - BridgeRialtoTokenSwap: pallet_bridge_token_swap::{Pallet, Call, Storage, Event, Origin}, // Westend bridge modules. BridgeWestendGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Config, Storage}, + BridgeWestendParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event}, + + // RialtoParachain bridge modules. + BridgeRialtoParachains: pallet_bridge_parachains::{Pallet, Call, Storage, Event}, + BridgeRialtoParachainMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config}, + + // Pallet for sending XCM. + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, } ); +generate_bridge_reject_obsolete_headers_and_messages! { + Call, AccountId, + // Grandpa + BridgeRialtoGrandpa, BridgeWestendGrandpa, + // Parachains + BridgeRialtoParachains, + //Messages + BridgeRialtoMessages, BridgeRialtoParachainMessages +} + /// The address format for describing accounts. pub type Address = AccountId; /// Block header type as expected by this runtime. @@ -549,6 +635,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + BridgeRejectObsoleteHeadersAndMessages, ); /// The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; @@ -669,36 +756,68 @@ impl_runtime_apis! { } } - impl pallet_mmr_primitives::MmrApi for Runtime { + impl sp_mmr_primitives::MmrApi for Runtime { fn generate_proof(leaf_index: u64) - -> Result<(EncodableOpaqueLeaf, MmrProof), MmrError> + -> Result<(EncodableOpaqueLeaf, MmrProof), MmrError> { - Mmr::generate_proof(leaf_index) - .map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof)) + Mmr::generate_batch_proof(vec![leaf_index]) + .and_then(|(leaves, proof)| Ok(( + mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), + mmr::BatchProof::into_single_leaf_proof(proof)? + ))) } - fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof) + fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof) -> Result<(), MmrError> { - pub type Leaf = < - ::LeafData as LeafDataProvider - >::LeafData; - - let leaf: Leaf = leaf + let leaf: mmr::Leaf = leaf .into_opaque_leaf() .try_decode() .ok_or(MmrError::Verify)?; - Mmr::verify_leaf(leaf, proof) + Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof)) } fn verify_proof_stateless( - root: MmrHash, + root: mmr::Hash, leaf: EncodableOpaqueLeaf, - proof: MmrProof + proof: MmrProof ) -> Result<(), MmrError> { - type MmrHashing = ::Hashing; let node = DataOrHash::Data(leaf.into_opaque_leaf()); - pallet_mmr::verify_leaf_proof::(root, node, proof) + pallet_mmr::verify_leaves_proof::( + root, + vec![node], + pallet_mmr::primitives::Proof::into_batch_proof(proof), + ) + } + + fn mmr_root() -> Result { + Ok(Mmr::mmr_root()) + } + + fn generate_batch_proof(leaf_indices: Vec) + -> Result<(Vec, mmr::BatchProof), mmr::Error> + { + Mmr::generate_batch_proof(leaf_indices) + .map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof)) + } + + fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) + -> Result<(), mmr::Error> + { + let leaves = leaves.into_iter().map(|leaf| + leaf.into_opaque_leaf() + .try_decode() + .ok_or(mmr::Error::Verify)).collect::, mmr::Error>>()?; + Mmr::verify_leaves(leaves, proof) + } + + fn verify_batch_proof_stateless( + root: mmr::Hash, + leaves: Vec, + proof: mmr::BatchProof + ) -> Result<(), mmr::Error> { + let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); + pallet_mmr::verify_leaves_proof::(root, nodes, proof) } } @@ -738,16 +857,41 @@ impl_runtime_apis! { } impl bp_rialto::RialtoFinalityApi for Runtime { - fn best_finalized() -> (bp_rialto::BlockNumber, bp_rialto::Hash) { - let header = BridgeRialtoGrandpa::best_finalized(); - (header.number, header.hash()) + fn best_finalized() -> Option> { + BridgeRialtoGrandpa::best_finalized().map(|header| header.id()) } } impl bp_westend::WestendFinalityApi for Runtime { - fn best_finalized() -> (bp_westend::BlockNumber, bp_westend::Hash) { - let header = BridgeWestendGrandpa::best_finalized(); - (header.number, header.hash()) + fn best_finalized() -> Option> { + BridgeWestendGrandpa::best_finalized().map(|header| header.id()) + } + } + + impl bp_westend::WestmintFinalityApi for Runtime { + fn best_finalized() -> Option> { + // the parachains finality pallet is never decoding parachain heads, so it is + // only done in the integration code + use bp_westend::WESTMINT_PARACHAIN_ID; + let encoded_head = pallet_bridge_parachains::Pallet::< + Runtime, + WithWestendParachainsInstance, + >::best_parachain_head(WESTMINT_PARACHAIN_ID.into())?; + let head = bp_westend::Header::decode(&mut &encoded_head.0[..]).ok()?; + Some(head.id()) + } + } + + impl bp_rialto_parachain::RialtoParachainFinalityApi for Runtime { + fn best_finalized() -> Option> { + // the parachains finality pallet is never decoding parachain heads, so it is + // only done in the integration code + let encoded_head = pallet_bridge_parachains::Pallet::< + Runtime, + WithRialtoParachainsInstance, + >::best_parachain_head(bp_rialto_parachain::RIALTO_PARACHAIN_ID.into())?; + let head = bp_rialto_parachain::Header::decode(&mut &encoded_head.0[..]).ok()?; + Some(head.id()) } } @@ -768,15 +912,63 @@ impl_runtime_apis! { lane: bp_messages::LaneId, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, - ) -> Vec> { + ) -> Vec> { bridge_runtime_common::messages_api::outbound_message_details::< Runtime, WithRialtoMessagesInstance, - WithRialtoMessageBridge, >(lane, begin, end) } } + impl bp_rialto::FromRialtoInboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> Vec { + bridge_runtime_common::messages_api::inbound_message_details::< + Runtime, + WithRialtoMessagesInstance, + >(lane, messages) + } + } + + impl bp_rialto_parachain::ToRialtoParachainOutboundLaneApi for Runtime { + fn estimate_message_delivery_and_dispatch_fee( + _lane_id: bp_messages::LaneId, + payload: ToRialtoParachainMessagePayload, + rialto_parachain_to_this_conversion_rate: Option, + ) -> Option { + estimate_message_dispatch_and_delivery_fee::( + &payload, + WithRialtoParachainMessageBridge::RELAYER_FEE_PERCENT, + rialto_parachain_to_this_conversion_rate, + ).ok() + } + + fn message_details( + lane: bp_messages::LaneId, + begin: bp_messages::MessageNonce, + end: bp_messages::MessageNonce, + ) -> Vec> { + bridge_runtime_common::messages_api::outbound_message_details::< + Runtime, + WithRialtoParachainMessagesInstance, + >(lane, begin, end) + } + } + + impl bp_rialto_parachain::FromRialtoParachainInboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> Vec { + bridge_runtime_common::messages_api::inbound_message_details::< + Runtime, + WithRialtoParachainMessagesInstance, + >(lane, messages) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( @@ -787,12 +979,14 @@ impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use pallet_bridge_messages::benchmarking::Pallet as MessagesBench; + use pallet_bridge_parachains::benchmarking::Pallet as ParachainsBench; let mut list = Vec::::new(); - list_benchmark!(list, extra, pallet_bridge_token_swap, BridgeRialtoTokenSwap); list_benchmark!(list, extra, pallet_bridge_messages, MessagesBench::); list_benchmark!(list, extra, pallet_bridge_grandpa, BridgeRialtoGrandpa); + list_benchmark!(list, extra, pallet_bridge_parachains, ParachainsBench::); + list_benchmark!(list, extra, pallet_bridge_relayers, BridgeRelayers); let storage_info = AllPalletsWithSystem::storage_info(); @@ -829,6 +1023,10 @@ impl_runtime_apis! { MessageParams, MessageProofParams, }; + use pallet_bridge_parachains::benchmarking::{ + Pallet as ParachainsBench, + Config as ParachainsConfig, + }; use rialto_messages::WithRialtoMessageBridge; impl MessagesConfig for Runtime { @@ -862,8 +1060,6 @@ impl_runtime_apis! { ) -> (rialto_messages::FromRialtoMessagesProof, Weight) { prepare_message_proof::( params, - &VERSION, - Balance::MAX / 100, ) } @@ -875,31 +1071,27 @@ impl_runtime_apis! { ) } - fn is_message_dispatched(nonce: bp_messages::MessageNonce) -> bool { - frame_system::Pallet::::events() - .into_iter() - .map(|event_record| event_record.event) - .any(|event| matches!( - event, - Event::BridgeDispatch(pallet_bridge_dispatch::Event::::MessageDispatched( - _, ([0, 0, 0, 0], nonce_from_event), _, - )) if nonce_from_event == nonce - )) + fn is_message_dispatched(_nonce: bp_messages::MessageNonce) -> bool { + true } } - use pallet_bridge_token_swap::benchmarking::Config as TokenSwapConfig; - - impl TokenSwapConfig for Runtime { - fn initialize_environment() { - let relayers_fund_account = pallet_bridge_messages::relayer_fund_account_id::< - bp_millau::AccountId, - bp_millau::AccountIdConverter, - >(); - pallet_balances::Pallet::::make_free_balance_be( - &relayers_fund_account, - Balance::MAX / 100, - ); + impl ParachainsConfig for Runtime { + fn prepare_parachain_heads_proof( + parachains: &[bp_polkadot_core::parachains::ParaId], + parachain_head_size: u32, + proof_size: bp_runtime::StorageProofSize, + ) -> ( + pallet_bridge_parachains::RelayBlockNumber, + pallet_bridge_parachains::RelayBlockHash, + bp_polkadot_core::parachains::ParaHeadsProof, + Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, + ) { + bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof::( + parachains, + parachain_head_size, + proof_size, + ) } } @@ -910,37 +1102,19 @@ impl_runtime_apis! { MessagesBench:: ); add_benchmark!(params, batches, pallet_bridge_grandpa, BridgeRialtoGrandpa); - add_benchmark!(params, batches, pallet_bridge_token_swap, BridgeRialtoTokenSwap); + add_benchmark!( + params, + batches, + pallet_bridge_parachains, + ParachainsBench:: + ); + add_benchmark!(params, batches, pallet_bridge_relayers, BridgeRelayers); Ok(batches) } } } -/// Rialto account ownership digest from Millau. -/// -/// The byte vector returned by this function should be signed with a Rialto account private key. -/// This way, the owner of `millau_account_id` on Millau proves that the Rialto account private key -/// is also under his control. -pub fn millau_to_rialto_account_ownership_digest( - rialto_call: &Call, - millau_account_id: AccountId, - rialto_spec_version: SpecVersion, -) -> sp_std::vec::Vec -where - Call: codec::Encode, - AccountId: codec::Encode, - SpecVersion: codec::Encode, -{ - pallet_bridge_dispatch::account_ownership_digest( - rialto_call, - millau_account_id, - rialto_spec_version, - bp_runtime::MILLAU_CHAIN_ID, - bp_runtime::RIALTO_CHAIN_ID, - ) -} - #[cfg(test)] mod tests { use super::*; diff --git a/bin/millau/runtime/src/rialto_messages.rs b/bin/millau/runtime/src/rialto_messages.rs index d925d805dd..ccca4222f6 100644 --- a/bin/millau/runtime/src/rialto_messages.rs +++ b/bin/millau/runtime/src/rialto_messages.rs @@ -16,7 +16,7 @@ //! Everything required to serve Millau <-> Rialto messages. -use crate::Runtime; +use crate::{Call, OriginCaller, Runtime}; use bp_messages::{ source_chain::{SenderOrigin, TargetHeaderChain}, @@ -24,7 +24,9 @@ use bp_messages::{ InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, }; use bp_runtime::{Chain, ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID}; -use bridge_runtime_common::messages::{self, MessageBridge, MessageTransaction}; +use bridge_runtime_common::messages::{ + self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction, +}; use codec::{Decode, Encode}; use frame_support::{ parameter_types, @@ -33,13 +35,19 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; -use sp_std::{convert::TryFrom, ops::RangeInclusive}; +use sp_std::convert::TryFrom; +/// Default lane that is used to send messages to Rialto. +pub const DEFAULT_XCM_LANE_TO_RIALTO: LaneId = [0, 0, 0, 0]; /// Initial value of `RialtoToMillauConversionRate` parameter. pub const INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE: FixedU128 = FixedU128::from_inner(FixedU128::DIV); /// Initial value of `RialtoFeeMultiplier` parameter. pub const INITIAL_RIALTO_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = 2 * crate::xcm_config::BASE_XCM_WEIGHT; parameter_types! { /// Rialto to Millau conversion rate. Initially we treat both tokens as equal. @@ -49,19 +57,14 @@ parameter_types! { } /// Message payload for Millau -> Rialto messages. -pub type ToRialtoMessagePayload = - messages::source::FromThisChainMessagePayload; +pub type ToRialtoMessagePayload = messages::source::FromThisChainMessagePayload; /// Message verifier for Millau -> Rialto messages. pub type ToRialtoMessageVerifier = messages::source::FromThisChainMessageVerifier; /// Message payload for Rialto -> Millau messages. -pub type FromRialtoMessagePayload = - messages::target::FromBridgedChainMessagePayload; - -/// Encoded Millau Call as it comes from Rialto. -pub type FromRialtoEncodedCall = messages::target::FromBridgedChainEncodedMessageCall; +pub type FromRialtoMessagePayload = messages::target::FromBridgedChainMessagePayload; /// Messages proof for Rialto -> Millau messages. pub type FromRialtoMessagesProof = messages::target::FromBridgedChainMessagesProof; @@ -73,11 +76,17 @@ pub type ToRialtoMessagesDeliveryProof = /// Call-dispatch based message dispatch for Rialto -> Millau messages. pub type FromRialtoMessageDispatch = messages::target::FromBridgedChainMessageDispatch< WithRialtoMessageBridge, - crate::Runtime, - pallet_balances::Pallet, - (), + xcm_executor::XcmExecutor, + crate::xcm_config::XcmWeigher, + // 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + // (it is prepended with `UniversalOrigin` instruction) + frame_support::traits::ConstU64, >; +/// Maximal outbound payload size of Millau -> Rialto messages. +pub type ToRialtoMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + /// Millau <-> Rialto message bridge. #[derive(RuntimeDebug, Clone, Copy)] pub struct WithRialtoMessageBridge; @@ -96,7 +105,7 @@ impl MessageBridge for WithRialtoMessageBridge { bridged_to_this_conversion_rate_override: Option, ) -> bp_millau::Balance { let conversion_rate = bridged_to_this_conversion_rate_override - .unwrap_or_else(|| RialtoToMillauConversionRate::get()); + .unwrap_or_else(RialtoToMillauConversionRate::get); bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance)) .unwrap_or(bp_millau::Balance::MAX) } @@ -118,43 +127,37 @@ impl messages::ChainWithMessages for Millau { impl messages::ThisChainWithMessages for Millau { type Origin = crate::Origin; type Call = crate::Call; + type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation< + Self::AccountId, + { bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT }, + { bp_rialto::EXTRA_STORAGE_PROOF_SIZE }, + { bp_millau::TX_EXTRA_BYTES }, + >; fn is_message_accepted(send_origin: &Self::Origin, lane: &LaneId) -> bool { - // lanes 0x00000000 && 0x00000001 are accepting any paid messages, while - // `TokenSwapMessageLane` only accepts messages from token swap pallet - let token_swap_dedicated_lane = crate::TokenSwapMessagesLane::get(); - match *lane { - [0, 0, 0, 0] | [0, 0, 0, 1] => send_origin.linked_account().is_some(), - _ if *lane == token_swap_dedicated_lane => matches!( - send_origin.caller, - crate::OriginCaller::BridgeRialtoTokenSwap( - pallet_bridge_token_swap::RawOrigin::TokenSwap { .. } - ) - ), - _ => false, + let here_location = + xcm::v3::MultiLocation::from(crate::xcm_config::UniversalLocation::get()); + match send_origin.caller { + OriginCaller::XcmPallet(pallet_xcm::Origin::Xcm(ref location)) + if *location == here_location => + { + log::trace!(target: "runtime::bridge", "Verifying message sent using XCM pallet to Rialto"); + }, + _ => { + // keep in mind that in this case all messages are free (in term of fees) + // => it's just to keep testing bridge on our test deployments until we'll have a + // better option + log::trace!(target: "runtime::bridge", "Verifying message sent using messages pallet to Rialto"); + }, } + + *lane == DEFAULT_XCM_LANE_TO_RIALTO || *lane == [0, 0, 0, 1] } fn maximal_pending_messages_at_outbound_lane() -> MessageNonce { MessageNonce::MAX } - fn estimate_delivery_confirmation_transaction() -> MessageTransaction { - let inbound_data_size = InboundLaneData::::encoded_size_hint( - bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); - - MessageTransaction { - dispatch_weight: bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT, - size: inbound_data_size - .saturating_add(bp_rialto::EXTRA_STORAGE_PROOF_SIZE) - .saturating_add(bp_millau::TX_EXTRA_BYTES), - } - } - fn transaction_payment(transaction: MessageTransaction) -> bp_millau::Balance { // `transaction` may represent transaction from the future, when multiplier value will // be larger, so let's use slightly increased value @@ -189,19 +192,8 @@ impl messages::BridgedChainWithMessages for Rialto { bp_rialto::Rialto::max_extrinsic_size() } - fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive { - // we don't want to relay too large messages + keep reserve for future upgrades - let upper_limit = messages::target::maximal_incoming_message_dispatch_weight( - bp_rialto::Rialto::max_extrinsic_weight(), - ); - - // we're charging for payload bytes in `WithRialtoMessageBridge::transaction_payment` - // function - // - // this bridge may be used to deliver all kind of messages, so we're not making any - // assumptions about minimal dispatch weight here - - 0..=upper_limit + fn verify_dispatch_weight(_message_payload: &[u8]) -> bool { + true } fn estimate_delivery_transaction( @@ -290,20 +282,8 @@ impl SourceHeaderChain for Rialto { impl SenderOrigin for crate::Origin { fn linked_account(&self) -> Option { - match self.caller { - crate::OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) => - Some(submitter.clone()), - crate::OriginCaller::system(frame_system::RawOrigin::Root) | - crate::OriginCaller::system(frame_system::RawOrigin::None) => - crate::RootAccountForPayments::get(), - crate::OriginCaller::BridgeRialtoTokenSwap( - pallet_bridge_token_swap::RawOrigin::TokenSwap { - ref swap_account_at_this_chain, - .. - }, - ) => Some(swap_account_at_this_chain.clone()), - _ => None, - } + // XCM deals wit fees in our deployments + None } } @@ -363,12 +343,10 @@ mod tests { ); let max_incoming_inbound_lane_data_proof_size = - bp_messages::InboundLaneData::<()>::encoded_size_hint( - bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, + bp_messages::InboundLaneData::<()>::encoded_size_hint_u32( bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as _, bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as _, - ) - .unwrap_or(u32::MAX); + ); pallet_bridge_messages::ensure_able_to_receive_confirmation::( bp_millau::Millau::max_extrinsic_size(), bp_millau::Millau::max_extrinsic_weight(), @@ -388,7 +366,6 @@ mod tests { bridge: WithRialtoMessageBridge, this_chain: bp_millau::Millau, bridged_chain: bp_rialto::Rialto, - this_chain_account_id_converter: bp_millau::AccountIdConverter ); assert_complete_bridge_constants::< diff --git a/bin/millau/runtime/src/rialto_parachain_messages.rs b/bin/millau/runtime/src/rialto_parachain_messages.rs new file mode 100644 index 0000000000..6840b703f4 --- /dev/null +++ b/bin/millau/runtime/src/rialto_parachain_messages.rs @@ -0,0 +1,295 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Everything required to serve Millau <-> RialtoParachain messages. + +use crate::Runtime; + +use bp_messages::{ + source_chain::TargetHeaderChain, + target_chain::{ProvedMessages, SourceHeaderChain}, + InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, +}; +use bp_polkadot_core::parachains::ParaId; +use bp_runtime::{Chain, ChainId, MILLAU_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID}; +use bridge_runtime_common::messages::{ + self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction, +}; +use codec::{Decode, Encode}; +use frame_support::{ + parameter_types, + weights::{DispatchClass, Weight}, + RuntimeDebug, +}; +use scale_info::TypeInfo; +use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; +use sp_std::convert::TryFrom; + +/// Default lane that is used to send messages to Rialto parachain. +pub const DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN: LaneId = [0, 0, 0, 0]; +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = 2 * crate::xcm_config::BASE_XCM_WEIGHT; + +/// Initial value of `RialtoParachainToMillauConversionRate` parameter. +pub const INITIAL_RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE: FixedU128 = + FixedU128::from_inner(FixedU128::DIV); +/// Initial value of `RialtoParachainFeeMultiplier` parameter. +pub const INITIAL_RIALTO_PARACHAIN_FEE_MULTIPLIER: FixedU128 = + FixedU128::from_inner(FixedU128::DIV); + +parameter_types! { + /// RialtoParachain to Millau conversion rate. Initially we treat both tokens as equal. + pub storage RialtoParachainToMillauConversionRate: FixedU128 = INITIAL_RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE; + /// Fee multiplier value at RialtoParachain chain. + pub storage RialtoParachainFeeMultiplier: FixedU128 = INITIAL_RIALTO_PARACHAIN_FEE_MULTIPLIER; +} + +/// Message payload for Millau -> RialtoParachain messages. +pub type ToRialtoParachainMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for Millau -> RialtoParachain messages. +pub type ToRialtoParachainMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Message payload for RialtoParachain -> Millau messages. +pub type FromRialtoParachainMessagePayload = + messages::target::FromBridgedChainMessagePayload; + +/// Messages proof for RialtoParachain -> Millau messages. +type FromRialtoParachainMessagesProof = + messages::target::FromBridgedChainMessagesProof; + +/// Messages delivery proof for Millau -> RialtoParachain messages. +type ToRialtoParachainMessagesDeliveryProof = + messages::source::FromBridgedChainMessagesDeliveryProof; + +/// Call-dispatch based message dispatch for RialtoParachain -> Millau messages. +pub type FromRialtoParachainMessageDispatch = messages::target::FromBridgedChainMessageDispatch< + WithRialtoParachainMessageBridge, + xcm_executor::XcmExecutor, + crate::xcm_config::XcmWeigher, + // 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + // (it is prepended with `UniversalOrigin` instruction) + frame_support::traits::ConstU64, +>; + +/// Maximal outbound payload size of Millau -> RialtoParachain messages. +pub type ToRialtoParachainMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// Millau <-> RialtoParachain message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithRialtoParachainMessageBridge; + +impl MessageBridge for WithRialtoParachainMessageBridge { + const RELAYER_FEE_PERCENT: u32 = 10; + const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID; + const BRIDGED_CHAIN_ID: ChainId = RIALTO_PARACHAIN_CHAIN_ID; + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; + + type ThisChain = Millau; + type BridgedChain = RialtoParachain; + + fn bridged_balance_to_this_balance( + bridged_balance: bp_rialto_parachain::Balance, + bridged_to_this_conversion_rate_override: Option, + ) -> bp_millau::Balance { + let conversion_rate = bridged_to_this_conversion_rate_override + .unwrap_or_else(RialtoParachainToMillauConversionRate::get); + bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance)) + .unwrap_or(bp_millau::Balance::MAX) + } +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; + +impl messages::ChainWithMessages for Millau { + type Hash = bp_millau::Hash; + type AccountId = bp_millau::AccountId; + type Signer = bp_millau::AccountSigner; + type Signature = bp_millau::Signature; + type Weight = Weight; + type Balance = bp_millau::Balance; +} + +impl messages::ThisChainWithMessages for Millau { + type Call = crate::Call; + type Origin = crate::Origin; + type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation< + Self::AccountId, + { bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT }, + { bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE }, + { bp_millau::TX_EXTRA_BYTES }, + >; + + fn is_message_accepted(_send_origin: &Self::Origin, lane: &LaneId) -> bool { + *lane == DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN || *lane == [0, 0, 0, 1] + } + + fn maximal_pending_messages_at_outbound_lane() -> MessageNonce { + MessageNonce::MAX + } + + fn transaction_payment(transaction: MessageTransaction) -> bp_millau::Balance { + // `transaction` may represent transaction from the future, when multiplier value will + // be larger, so let's use slightly increased value + let multiplier = FixedU128::saturating_from_rational(110, 100) + .saturating_mul(pallet_transaction_payment::Pallet::::next_fee_multiplier()); + // in our testnets, both per-byte fee and weight-to-fee are 1:1 + messages::transaction_payment( + bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic, + 1, + multiplier, + |weight| weight as _, + transaction, + ) + } +} + +/// RialtoParachain chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct RialtoParachain; + +impl messages::ChainWithMessages for RialtoParachain { + type Hash = bp_rialto_parachain::Hash; + type AccountId = bp_rialto_parachain::AccountId; + type Signer = bp_rialto_parachain::AccountSigner; + type Signature = bp_rialto_parachain::Signature; + type Weight = Weight; + type Balance = bp_rialto_parachain::Balance; +} + +impl messages::BridgedChainWithMessages for RialtoParachain { + fn maximal_extrinsic_size() -> u32 { + bp_rialto_parachain::RialtoParachain::max_extrinsic_size() + } + + fn verify_dispatch_weight(_message_payload: &[u8]) -> bool { + true + } + + fn estimate_delivery_transaction( + message_payload: &[u8], + include_pay_dispatch_fee_cost: bool, + message_dispatch_weight: Weight, + ) -> MessageTransaction { + let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX); + let extra_bytes_in_payload = Weight::from(message_payload_len) + .saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH.into()); + + MessageTransaction { + dispatch_weight: extra_bytes_in_payload + .saturating_mul(bp_rialto_parachain::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT) + .saturating_add(bp_rialto_parachain::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT) + .saturating_sub(if include_pay_dispatch_fee_cost { + 0 + } else { + bp_rialto_parachain::PAY_INBOUND_DISPATCH_FEE_WEIGHT + }) + .saturating_add(message_dispatch_weight), + size: message_payload_len + .saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE) + .saturating_add(bp_rialto_parachain::TX_EXTRA_BYTES), + } + } + + fn transaction_payment( + transaction: MessageTransaction, + ) -> bp_rialto_parachain::Balance { + // we don't have a direct access to the value of multiplier at RialtoParachain chain + // => it is a messages module parameter + let multiplier = RialtoParachainFeeMultiplier::get(); + // in our testnets, both per-byte fee and weight-to-fee are 1:1 + messages::transaction_payment( + bp_rialto_parachain::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic, + 1, + multiplier, + |weight| weight as _, + transaction, + ) + } +} + +impl TargetHeaderChain + for RialtoParachain +{ + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof or one or several keys; + // - id of the lane we prove state of. + type MessagesDeliveryProof = ToRialtoParachainMessagesDeliveryProof; + + fn verify_message(payload: &ToRialtoParachainMessagePayload) -> Result<(), Self::Error> { + messages::source::verify_chain_message::(payload) + } + + fn verify_messages_delivery_proof( + proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error> { + messages::source::verify_messages_delivery_proof_from_parachain::< + WithRialtoParachainMessageBridge, + bp_rialto_parachain::Header, + Runtime, + crate::WithRialtoParachainsInstance, + >(ParaId(bp_rialto_parachain::RIALTO_PARACHAIN_ID), proof) + } +} + +impl SourceHeaderChain for RialtoParachain { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof or one or several keys; + // - id of the lane we prove messages for; + // - inclusive range of messages nonces that are proved. + type MessagesProof = FromRialtoParachainMessagesProof; + + fn verify_messages_proof( + proof: Self::MessagesProof, + messages_count: u32, + ) -> Result>, Self::Error> { + messages::target::verify_messages_proof_from_parachain::< + WithRialtoParachainMessageBridge, + bp_rialto_parachain::Header, + Runtime, + crate::WithRialtoParachainsInstance, + >(ParaId(bp_rialto_parachain::RIALTO_PARACHAIN_ID), proof, messages_count) + } +} + +/// Millau -> RialtoParachain message lane pallet parameters. +#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] +pub enum MillauToRialtoParachainMessagesParameter { + /// The conversion formula we use is: `MillauTokens = RialtoParachainTokens * conversion_rate`. + RialtoParachainToMillauConversionRate(FixedU128), +} + +impl MessagesParameter for MillauToRialtoParachainMessagesParameter { + fn save(&self) { + match *self { + MillauToRialtoParachainMessagesParameter::RialtoParachainToMillauConversionRate( + ref conversion_rate, + ) => RialtoParachainToMillauConversionRate::set(conversion_rate), + } + } +} diff --git a/bin/millau/runtime/src/xcm_config.rs b/bin/millau/runtime/src/xcm_config.rs new file mode 100644 index 0000000000..88398345d4 --- /dev/null +++ b/bin/millau/runtime/src/xcm_config.rs @@ -0,0 +1,326 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! XCM configurations for the Millau runtime. + +use super::{ + rialto_messages::{WithRialtoMessageBridge, DEFAULT_XCM_LANE_TO_RIALTO}, + rialto_parachain_messages::{ + WithRialtoParachainMessageBridge, DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN, + }, + AccountId, AllPalletsWithSystem, Balances, Call, Event, Origin, Runtime, + WithRialtoMessagesInstance, WithRialtoParachainMessagesInstance, XcmPallet, +}; +use bp_messages::LaneId; +use bp_millau::WeightToFee; +use bp_rialto_parachain::RIALTO_PARACHAIN_ID; +use bridge_runtime_common::{ + messages::source::{XcmBridge, XcmBridgeAdapter}, + CustomNetworkId, +}; +use frame_support::{ + parameter_types, + traits::{Everything, Nothing}, + weights::Weight, +}; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, + CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, +}; + +parameter_types! { + /// The location of the `MLAU` token, from the context of this chain. Since this token is native to this + /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to + /// the context". + pub const TokenLocation: MultiLocation = Here.into_location(); + /// The Millau network ID. + pub const ThisNetwork: NetworkId = CustomNetworkId::Millau.as_network_id(); + /// The Rialto network ID. + pub const RialtoNetwork: NetworkId = CustomNetworkId::Rialto.as_network_id(); + /// The RialtoParachain network ID. + pub const RialtoParachainNetwork: NetworkId = CustomNetworkId::RialtoParachain.as_network_id(); + + /// Our XCM location ancestry - i.e. our location within the Consensus Universe. + /// + /// Since Kusama is a top-level relay-chain with its own consensus, it's just our network ID. + pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); + /// The check account, which holds any native assets that have been teleported out and not back in (yet). + pub CheckAccount: AccountId = XcmPallet::check_account(); +} + +/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to +/// determine the sovereign account controlled by a location. +pub type SovereignAccountOf = ( + // We can directly alias an `AccountId32` into a local account. + AccountId32Aliases, +); + +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the +/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// +/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // We can convert the MultiLocations with our converter above: + SovereignAccountOf, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We track our teleports in/out to keep total issuance correct. + CheckAccount, +>; + +/// The means that we convert the XCM message origin location into a local dispatch origin. +type LocalOriginConverter = ( + // A `Signed` origin of the sovereign account that the original location controls. + SovereignSignedViaLocation, + // The AccountId32 location type can be expressed natively as a `Signed` origin. + SignedAccountId32AsNative, +); + +/// The amount of weight an XCM operation takes. This is a safe overestimate. +pub const BASE_XCM_WEIGHT: Weight = 1_000_000_000; + +parameter_types! { + /// The amount of weight an XCM operation takes. This is a safe overestimate. + pub const BaseXcmWeight: Weight = BASE_XCM_WEIGHT; + /// Maximum number of instructions in a single XCM fragment. A sanity check against weight + /// calculations getting too crazy. + pub const MaxInstructions: u32 = 100; +} + +/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our +/// individual routers. +pub type XcmRouter = ( + // Router to send messages to Rialto. + XcmBridgeAdapter, + // Router to send messages to RialtoParachains. + XcmBridgeAdapter, +); + +parameter_types! { + pub const MaxAssetsIntoHolding: u32 = 64; +} + +/// The barriers one of which must be passed for an XCM message to be executed. +pub type Barrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, +); + +/// XCM weigher type. +pub type XcmWeigher = xcm_builder::FixedWeightBounds; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type Call = Call; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = XcmWeigher; + // The weight trader piggybacks on the existing transaction-fee conversion logic. + type Trader = UsingComponents; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = Call; +} + +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. +pub type LocalOriginToLocation = ( + // Usual Signed origin to be used in XCM as a corresponding AccountId32 + SignedToAccountId32, +); + +impl pallet_xcm::Config for Runtime { + type Event = Event; + // We don't allow any messages to be sent via the transaction yet. This is basically safe to + // enable, (safe the possibility of someone spamming the parachain if they're willing to pay + // the DOT to send from the Relay-chain). But it's useless until we bring in XCM v3 which will + // make `DescendOrigin` a bit more useful. + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally. + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = xcm_executor::XcmExecutor; + // Anyone is able to use teleportation regardless of who they are and what they want to + // teleport. + type XcmTeleportFilter = Everything; + // Anyone is able to use reserve transfers regardless of who they are and what they want to + // transfer. + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type Origin = Origin; + type Call = Call; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = SovereignAccountOf; + type MaxLockers = frame_support::traits::ConstU32<8>; +} + +/// With-Rialto bridge. +pub struct ToRialtoBridge; + +impl XcmBridge for ToRialtoBridge { + type MessageBridge = WithRialtoMessageBridge; + type MessageSender = pallet_bridge_messages::Pallet; + + fn universal_location() -> InteriorMultiLocation { + UniversalLocation::get() + } + + fn verify_destination(dest: &MultiLocation) -> bool { + matches!(*dest, MultiLocation { parents: 1, interior: X1(GlobalConsensus(r)) } if r == RialtoNetwork::get()) + } + + fn build_destination() -> MultiLocation { + let dest: InteriorMultiLocation = RialtoNetwork::get().into(); + let here = UniversalLocation::get(); + dest.relative_to(&here) + } + + fn xcm_lane() -> LaneId { + DEFAULT_XCM_LANE_TO_RIALTO + } +} + +/// With-RialtoParachain bridge. +pub struct ToRialtoParachainBridge; + +impl XcmBridge for ToRialtoParachainBridge { + type MessageBridge = WithRialtoParachainMessageBridge; + type MessageSender = + pallet_bridge_messages::Pallet; + + fn universal_location() -> InteriorMultiLocation { + UniversalLocation::get() + } + + fn verify_destination(dest: &MultiLocation) -> bool { + matches!(*dest, MultiLocation { parents: 1, interior: X2(GlobalConsensus(r), Parachain(RIALTO_PARACHAIN_ID)) } if r == RialtoNetwork::get()) + } + + fn build_destination() -> MultiLocation { + let dest: InteriorMultiLocation = RialtoParachainNetwork::get().into(); + let here = UniversalLocation::get(); + dest.relative_to(&here) + } + + fn xcm_lane() -> LaneId { + DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + MessageKey, + }; + use bp_runtime::messages::MessageDispatchResult; + use bridge_runtime_common::messages::target::FromBridgedChainMessageDispatch; + use codec::Encode; + + fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::default().build_storage::().unwrap(), + ) + } + + #[test] + fn xcm_messages_are_sent_using_bridge_router() { + new_test_ext().execute_with(|| { + let xcm: Xcm<()> = vec![Instruction::Trap(42)].into(); + let expected_fee = MultiAssets::from((Here, 4_259_858_152_u64)); + let expected_hash = + ([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256); + + // message 1 to Rialto + let dest = (Parent, X1(GlobalConsensus(RialtoNetwork::get()))); + let send_result = send_xcm::(dest.into(), xcm.clone()); + assert_eq!(send_result, Ok((expected_hash, expected_fee.clone()))); + + // message 2 to RialtoParachain (expected hash is the same, since other lane is used) + let dest = + (Parent, X2(GlobalConsensus(RialtoNetwork::get()), Parachain(RIALTO_PARACHAIN_ID))); + let send_result = send_xcm::(dest.into(), xcm); + assert_eq!(send_result, Ok((expected_hash, expected_fee))); + }) + } + + #[test] + fn xcm_messages_from_rialto_are_dispatched() { + type XcmExecutor = xcm_executor::XcmExecutor; + type MessageDispatcher = FromBridgedChainMessageDispatch< + WithRialtoMessageBridge, + XcmExecutor, + XcmWeigher, + frame_support::traits::ConstU64, + >; + + new_test_ext().execute_with(|| { + let location: MultiLocation = + (Parent, X1(GlobalConsensus(RialtoNetwork::get()))).into(); + let xcm: Xcm = vec![Instruction::Trap(42)].into(); + + let mut incoming_message = DispatchMessage { + key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 }, + data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 }, + }; + + let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message); + assert_eq!(dispatch_weight, 1_000_000_000); + + let dispatch_result = + MessageDispatcher::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert_eq!( + dispatch_result, + MessageDispatchResult { + dispatch_result: true, + unspent_weight: 0, + dispatch_fee_paid_during_dispatch: false, + } + ); + }) + } +} diff --git a/bin/rialto-parachain/node/Cargo.toml b/bin/rialto-parachain/node/Cargo.toml index 41021a35ed..109be667c4 100644 --- a/bin/rialto-parachain/node/Cargo.toml +++ b/bin/rialto-parachain/node/Cargo.toml @@ -3,7 +3,6 @@ name = "rialto-parachain-collator" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" @@ -20,13 +19,18 @@ runtime-benchmarks = ['rialto-parachain-runtime/runtime-benchmarks'] [dependencies] clap = { version = "3.1", features = ["derive"] } derive_more = '0.99.2' -log = '0.4.14' -codec = { package = 'parity-scale-codec', version = '3.0.0' } +log = '0.4.17' +codec = { package = 'parity-scale-codec', version = '3.1.5' } serde = { version = '1.0', features = ['derive'] } hex-literal = '0.3.1' +# Bridge dependencies + +bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain" } +pallet-bridge-messages = { path = "../../../modules/messages" } + # RPC related Dependencies -jsonrpc-core = '18.0' +jsonrpsee = { version = "0.15.1", features = ["server"] } # Local Dependencies rialto-parachain-runtime = { path = '../runtime' } @@ -72,20 +76,20 @@ sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "mast sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } # Cumulus dependencies -cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-client-collator = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "master" } -cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-client-collator = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } +cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3" } # Polkadot dependencies -polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } \ No newline at end of file +polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } diff --git a/bin/rialto-parachain/node/src/chain_spec.rs b/bin/rialto-parachain/node/src/chain_spec.rs index 6a8e751677..a0306514c0 100644 --- a/bin/rialto-parachain/node/src/chain_spec.rs +++ b/bin/rialto-parachain/node/src/chain_spec.rs @@ -15,13 +15,24 @@ // along with Parity Bridges Common. If not, see . use cumulus_primitives_core::ParaId; -use rialto_parachain_runtime::{AccountId, AuraId, Signature}; +use rialto_parachain_runtime::{AccountId, AuraId, BridgeMillauMessagesConfig, Signature}; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; +/// "Names" of the authorities accounts at local testnet. +const LOCAL_AUTHORITIES_ACCOUNTS: [&str; 2] = ["Alice", "Bob"]; +/// "Names" of the authorities accounts at development testnet. +const DEV_AUTHORITIES_ACCOUNTS: [&str; 2] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Names" of all possible authorities accounts. +const ALL_AUTHORITIES_ACCOUNTS: [&str; 2] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Name" of the `sudo` account. +const SUDO_ACCOUNT: &str = "Sudo"; +/// "Name" of the account, which owns the with-Millau messages pallet. +const MILLAU_MESSAGES_PALLET_OWNER: &str = "Millau.MessagesOwner"; + /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; @@ -34,7 +45,9 @@ pub fn get_from_seed(seed: &str) -> ::Pu } /// The extensions for the [`ChainSpec`]. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] +#[derive( + Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, +)] #[serde(deny_unknown_fields)] pub struct Extensions { /// The relay chain of the Parachain. @@ -60,6 +73,40 @@ where AccountPublic::from(get_from_seed::(seed)).into_account() } +/// We're using the same set of endowed accounts on all RialtoParachain chains (dev/local) to make +/// sure that all accounts, required for bridge to be functional (e.g. relayers fund account, +/// accounts used by relayers in our test deployments, accounts used for demonstration +/// purposes), are all available on these chains. +fn endowed_accounts() -> Vec { + let all_authorities = ALL_AUTHORITIES_ACCOUNTS.iter().flat_map(|x| { + [ + get_account_id_from_seed::(x), + get_account_id_from_seed::(&format!("{}//stash", x)), + ] + }); + vec![ + // Sudo account + get_account_id_from_seed::(SUDO_ACCOUNT), + // Regular (unused) accounts + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + // Accounts, used by RialtoParachain<>Millau bridge + get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("Millau.HeadersAndMessagesRelay1"), + get_account_id_from_seed::("Millau.HeadersAndMessagesRelay2"), + get_account_id_from_seed::("Millau.MessagesSender"), + ] + .into_iter() + .chain(all_authorities) + .collect() +} + pub fn development_config(id: ParaId) -> ChainSpec { // Give your base currency a unit name and decimal places let mut properties = sc_chain_spec::Properties::new(); @@ -74,14 +121,9 @@ pub fn development_config(id: ParaId) -> ChainSpec { ChainType::Local, move || { testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![get_from_seed::("Alice"), get_from_seed::("Bob")], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - ], + get_account_id_from_seed::(SUDO_ACCOUNT), + DEV_AUTHORITIES_ACCOUNTS.into_iter().map(get_from_seed::).collect(), + endowed_accounts(), id, ) }, @@ -111,22 +153,9 @@ pub fn local_testnet_config(id: ParaId) -> ChainSpec { ChainType::Local, move || { testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![get_from_seed::("Alice"), get_from_seed::("Bob")], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], + get_account_id_from_seed::(SUDO_ACCOUNT), + LOCAL_AUTHORITIES_ACCOUNTS.into_iter().map(get_from_seed::).collect(), + endowed_accounts(), id, ) }, @@ -161,6 +190,9 @@ fn testnet_genesis( parachain_info: rialto_parachain_runtime::ParachainInfoConfig { parachain_id: id }, aura: rialto_parachain_runtime::AuraConfig { authorities: initial_authorities }, aura_ext: Default::default(), - // parachain_system: Default::default(), + bridge_millau_messages: BridgeMillauMessagesConfig { + owner: Some(get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER)), + ..Default::default() + }, } } diff --git a/bin/rialto-parachain/node/src/cli.rs b/bin/rialto-parachain/node/src/cli.rs index 89d049f022..bd45db9758 100644 --- a/bin/rialto-parachain/node/src/cli.rs +++ b/bin/rialto-parachain/node/src/cli.rs @@ -51,7 +51,7 @@ pub enum Subcommand { Revert(sc_cli::RevertCmd), /// The custom benchmark subcommmand benchmarking runtime pallets. - #[clap(name = "benchmark", about = "Benchmark runtime pallets.")] + #[clap(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), } @@ -59,7 +59,7 @@ pub enum Subcommand { #[derive(Debug, Parser)] pub struct ExportGenesisStateCommand { /// Output file name or stdout if unspecified. - #[clap(parse(from_os_str))] + #[clap(action)] pub output: Option, /// Id of the parachain this state is for. @@ -81,7 +81,7 @@ pub struct ExportGenesisStateCommand { #[derive(Debug, Parser)] pub struct ExportGenesisWasmCommand { /// Output file name or stdout if unspecified. - #[clap(parse(from_os_str))] + #[clap(action)] pub output: Option, /// Write output in binary. Default is to write in hex. diff --git a/bin/rialto-parachain/node/src/command.rs b/bin/rialto-parachain/node/src/command.rs index c47e742675..6afae824a7 100644 --- a/bin/rialto-parachain/node/src/command.rs +++ b/bin/rialto-parachain/node/src/command.rs @@ -20,10 +20,10 @@ use crate::{ service::{new_partial, ParachainRuntimeExecutor}, }; use codec::Encode; -use cumulus_client_service::genesis::generate_genesis_block; +use cumulus_client_cli::generate_genesis_block; use cumulus_primitives_core::ParaId; +use frame_benchmarking_cli::BenchmarkCmd; use log::info; -use polkadot_parachain::primitives::AccountIdConversion; use rialto_parachain_runtime::{Block, RuntimeApi}; use sc_cli::{ ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, @@ -31,7 +31,7 @@ use sc_cli::{ }; use sc_service::config::{BasePath, PrometheusConfig}; use sp_core::hexdisplay::HexDisplay; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{AccountIdConversion, Block as BlockT}; use std::{io::Write, net::SocketAddr}; fn load_spec( @@ -202,9 +202,11 @@ pub fn run() -> Result<()> { }) }, Some(Subcommand::Revert(cmd)) => { - construct_async_run!(|components, cli, cmd, config| Ok( - cmd.run(components.client, components.backend) - )) + construct_async_run!(|components, cli, cmd, config| Ok(cmd.run( + components.client, + components.backend, + None + ))) }, Some(Subcommand::ExportGenesisState(params)) => { let mut builder = sc_cli::LoggerBuilder::new(""); @@ -216,7 +218,7 @@ pub fn run() -> Result<()> { params.parachain_id.expect("Missing ParaId").into(), )?; let state_version = Cli::native_runtime_version(&spec).state_version(); - let block: Block = generate_genesis_block(&spec, state_version)?; + let block: Block = generate_genesis_block(&*spec, state_version)?; let raw_header = block.header().encode(); let output_buf = if params.raw { raw_header @@ -253,16 +255,22 @@ pub fn run() -> Result<()> { Ok(()) }, - Some(Subcommand::Benchmark(cmd)) => - if cfg!(feature = "runtime-benchmarks") { - let runner = cli.create_runner(cmd)?; - - runner.sync_run(|config| cmd.run::(config)) - } else { - Err("Benchmarking wasn't enabled when building the node. \ - You can enable it with `--features runtime-benchmarks`." - .into()) - }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner.sync_run(|config| cmd.run::(config)) + } else { + println!( + "Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + ); + Ok(()) + }, + _ => Err("Unsupported benchmarking subcommand".into()), + } + }, None => { let runner = cli.create_runner(&cli.run.normalize())?; let collator_options = cli.run.collator_options(); @@ -279,11 +287,11 @@ pub fn run() -> Result<()> { let id = ParaId::from(cli.parachain_id.or(para_id).expect("Missing ParaId")); let parachain_account = - AccountIdConversion::::into_account(&id); + AccountIdConversion::::into_account_truncating(&id); let state_version = RelayChainCli::native_runtime_version(&config.chain_spec).state_version(); - let block: Block = generate_genesis_block(&config.chain_spec, state_version) + let block: Block = generate_genesis_block(&*config.chain_spec, state_version) .map_err(|e| format!("{:?}", e))?; let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode())); @@ -393,12 +401,8 @@ impl CliConfiguration for RelayChainCli { self.base.base.role(is_dev) } - fn transaction_pool(&self) -> Result { - self.base.base.transaction_pool() - } - - fn state_cache_child_ratio(&self) -> Result> { - self.base.base.state_cache_child_ratio() + fn transaction_pool(&self, is_dev: bool) -> Result { + self.base.base.transaction_pool(is_dev) } fn rpc_methods(&self) -> Result { diff --git a/bin/rialto-parachain/node/src/service.rs b/bin/rialto-parachain/node/src/service.rs index a2299e1745..e55f89bacf 100644 --- a/bin/rialto-parachain/node/src/service.rs +++ b/bin/rialto-parachain/node/src/service.rs @@ -42,8 +42,8 @@ use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; // Substrate Imports use sc_client_api::ExecutorProvider; use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch}; -use sc_network::NetworkService; -use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager}; +use sc_network::{NetworkBlock, NetworkService}; +use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; use sp_api::ConstructRuntimeApi; use sp_keystore::SyncCryptoStorePtr; @@ -229,8 +229,9 @@ where TFullClient>, >, >, - ) -> jsonrpc_core::IoHandler + ) -> Result, sc_service::Error> + Send + + Clone + 'static, BIQ: FnOnce( Arc>>, @@ -261,10 +262,6 @@ where bool, ) -> Result>, sc_service::Error>, { - if matches!(parachain_config.role, Role::Light) { - return Err("Light client not supported!".into()) - } - let parachain_config = prepare_node_config(parachain_config); let params = new_partial::(¶chain_config, build_import_queue)?; @@ -276,6 +273,7 @@ where ¶chain_config, telemetry_worker_handle, &mut task_manager, + None, ) .map_err(|e| match e { RelayChainError::ServiceError(polkadot_service::Error::Sub(x)) => x, @@ -307,11 +305,11 @@ where let rpc_client = client.clone(); let rpc_transaction_pool = transaction_pool.clone(); let rpc_extensions_builder = Box::new(move |deny_unsafe, _| { - Ok(rpc_ext_builder(deny_unsafe, rpc_client.clone(), rpc_transaction_pool.clone())) + rpc_ext_builder(deny_unsafe, rpc_client.clone(), rpc_transaction_pool.clone()) }); sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_extensions_builder, + rpc_builder: rpc_extensions_builder.clone(), client: client.clone(), transaction_pool: transaction_pool.clone(), task_manager: &mut task_manager, @@ -441,18 +439,17 @@ pub async fn start_node( polkadot_config, collator_options, id, - |deny_unsafe, client, pool| { - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; - use substrate_frame_rpc_system::{FullSystem, SystemApi}; - - let mut io = jsonrpc_core::IoHandler::default(); - io.extend_with(SystemApi::to_delegate(FullSystem::new( - client.clone(), - pool, - deny_unsafe, - ))); - io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client))); - io + |_deny_unsafe, client, pool| { + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use sc_rpc::DenyUnsafe; + use substrate_frame_rpc_system::{System, SystemApiServer}; + + let mut io = jsonrpsee::RpcModule::new(()); + let map_err = |e| sc_service::Error::Other(format!("{}", e)); + io.merge(System::new(client.clone(), pool, DenyUnsafe::No).into_rpc()) + .map_err(map_err)?; + io.merge(TransactionPayment::new(client).into_rpc()).map_err(map_err)?; + Ok(io) }, parachain_build_import_queue, |client, diff --git a/bin/rialto-parachain/runtime/Cargo.toml b/bin/rialto-parachain/runtime/Cargo.toml index 1d0870fcbc..d125931220 100644 --- a/bin/rialto-parachain/runtime/Cargo.toml +++ b/bin/rialto-parachain/runtime/Cargo.toml @@ -3,7 +3,6 @@ name = "rialto-parachain-runtime" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" @@ -11,14 +10,22 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } [dependencies] -codec = { package = 'parity-scale-codec', version = '3.0.0', default-features = false, features = ['derive']} -log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false, features = ['derive']} +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = '1.0', optional = true, features = ['derive'] } # Bridge depedencies +bp-messages = { path = "../../../primitives/messages", default-features = false } +bp-millau = { path = "../../../primitives/chain-millau", default-features = false } +bp-relayers = { path = "../../../primitives/relayers", default-features = false } +bp-runtime = { path = "../../../primitives/runtime", default-features = false } bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain", default-features = false } +bridge-runtime-common = { path = "../../runtime-common", default-features = false } +pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../../modules/messages", default-features = false } +pallet-bridge-relayers = { path = "../../../modules/relayers", default-features = false } # Substrate Dependencies ## Substrate Primitive Dependencies @@ -38,7 +45,7 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master ## Substrate FRAME Dependencies frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -53,22 +60,22 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } # Cumulus Dependencies -cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -cumulus-primitives-utility = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } -parachain-info = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } +parachain-info = { git = "https://github.com/paritytech/cumulus", branch = "gav-xcm-v3", default-features = false } # Polkadot Dependencies -polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } -xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } -xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } -pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } [features] default = ['std'] @@ -82,7 +89,12 @@ runtime-benchmarks = [ 'pallet-timestamp/runtime-benchmarks', ] std = [ + "bp-messages/std", + "bp-millau/std", + "bp-relayers/std", + "bp-runtime/std", "bp-rialto-parachain/std", + "bridge-runtime-common/std", "codec/std", "log/std", "scale-info/std", @@ -102,11 +114,16 @@ std = [ "frame-executive/std", "frame-system/std", "pallet-balances/std", + "pallet-bridge-grandpa/std", + "pallet-bridge-messages/std", + "pallet-bridge-relayers/std", "pallet-randomness-collective-flip/std", "pallet-timestamp/std", "pallet-sudo/std", "pallet-transaction-payment/std", + "pallet-xcm/std", "parachain-info/std", + "polkadot-parachain/std", "cumulus-pallet-aura-ext/std", "cumulus-pallet-parachain-system/std", "cumulus-pallet-xcmp-queue/std", diff --git a/bin/rialto-parachain/runtime/src/lib.rs b/bin/rialto-parachain/runtime/src/lib.rs index 646521f329..885688d683 100644 --- a/bin/rialto-parachain/runtime/src/lib.rs +++ b/bin/rialto-parachain/runtime/src/lib.rs @@ -26,13 +26,22 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +use crate::millau_messages::{ + ToMillauMessagePayload, WithMillauMessageBridge, DEFAULT_XCM_LANE_TO_MILLAU, +}; + +use bridge_runtime_common::messages::{ + source::{estimate_message_dispatch_and_delivery_fee, XcmBridge, XcmBridgeAdapter}, + MessageBridge, +}; +use cumulus_pallet_parachain_system::AnyRelayNumber; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, + ApplyExtrinsicResult, FixedU128, }; use sp_std::prelude::*; @@ -41,9 +50,10 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. +use bp_runtime::{HeaderId, HeaderIdProvider}; pub use frame_support::{ construct_runtime, match_types, parameter_types, - traits::{Everything, IsInVec, Randomness}, + traits::{Everything, IsInVec, Nothing, Randomness}, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, DispatchClass, IdentityFee, Weight, @@ -52,6 +62,7 @@ pub use frame_support::{ }; pub use frame_system::{Call as SystemCall, EnsureRoot}; pub use pallet_balances::Call as BalancesCall; +pub use pallet_sudo::Call as SudoCall; pub use pallet_timestamp::Call as TimestampCall; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; #[cfg(any(feature = "std", test))] @@ -63,19 +74,26 @@ pub use bp_rialto_parachain::{ Index, Signature, MAXIMUM_BLOCK_WEIGHT, }; +pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall; +pub use pallet_bridge_messages::Call as MessagesCall; +pub use pallet_xcm::Call as XcmCall; + // Polkadot & XCM imports +use bridge_runtime_common::CustomNetworkId; use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, - EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, + EnsureXcmOrigin, FixedWeightBounds, IsConcrete, NativeAsset, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, }; use xcm_executor::{Config, XcmExecutor}; +pub mod millau_messages; + /// The address format for describing accounts. pub type Address = MultiAddress; /// Block type as expected by this runtime. @@ -88,6 +106,7 @@ pub type BlockId = generic::BlockId; pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, frame_system::CheckGenesis, frame_system::CheckEra, frame_system::CheckNonce, @@ -252,10 +271,11 @@ impl pallet_balances::Config for Runtime { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); + type Event = Event; } impl pallet_sudo::Config for Runtime { @@ -277,6 +297,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = AnyRelayNumber; } impl parachain_info::Config for Runtime {} @@ -287,9 +308,13 @@ impl pallet_randomness_collective_flip::Config for Runtime {} parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Polkadot; + pub const RelayNetwork: NetworkId = CustomNetworkId::Rialto.as_network_id(); pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); - pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); + pub UniversalLocation: InteriorMultiLocation = X1(Parachain(ParachainInfo::parachain_id().into())); + /// The Millau network ID. + pub const MillauNetwork: NetworkId = CustomNetworkId::Millau.as_network_id(); + /// The RialtoParachain network ID. + pub const ThisNetwork: NetworkId = CustomNetworkId::RialtoParachain.as_network_id(); } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -342,13 +367,19 @@ pub type XcmOriginToTransactDispatchOrigin = ( XcmPassthrough, ); +// TODO: until https://github.com/paritytech/parity-bridges-common/issues/1417 is fixed (in either way), +// the following constant must match the similar constant in the Millau runtime. + +/// One XCM operation is `1_000_000_000` weight - almost certainly a conservative estimate. +pub const BASE_XCM_WEIGHT: Weight = 1_000_000_000; + parameter_types! { - // One XCM operation is 1_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = 1_000_000; + pub UnitWeightCost: Weight = BASE_XCM_WEIGHT; // One UNIT buys 1 second of weight. pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), UNIT); pub const MaxInstructions: u32 = 100; pub const MaxAuthorities: u32 = 100_000; + pub MaxAssetsIntoHolding: u32 = 64; } match_types! { @@ -365,23 +396,33 @@ pub type Barrier = ( // ^^^ Parent & its unit plurality gets free execution ); +/// XCM weigher type. +pub type XcmWeigher = FixedWeightBounds; + pub struct XcmConfig; impl Config for XcmConfig { type Call = Call; type XcmSender = XcmRouter; - // How to withdraw and deposit an asset. type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of UNIT - type LocationInverter = LocationInverter; + type UniversalLocation = UniversalLocation; type Barrier = Barrier; - type Weigher = FixedWeightBounds; + type Weigher = XcmWeigher; type Trader = UsingComponents, RelayLocation, AccountId, Balances, ()>; type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetClaims = PolkadotXcm; type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = Call; } /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -390,12 +431,36 @@ pub type LocalOriginToLocation = SignedToAccountId32, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, + // Bridge is used to communicate with other relay chain (Millau). + XcmBridgeAdapter, ); +/// With-Millau bridge. +pub struct ToMillauBridge; + +impl XcmBridge for ToMillauBridge { + type MessageBridge = WithMillauMessageBridge; + type MessageSender = pallet_bridge_messages::Pallet; + + fn universal_location() -> InteriorMultiLocation { + UniversalLocation::get() + } + + fn verify_destination(dest: &MultiLocation) -> bool { + matches!(*dest, MultiLocation { parents: 1, interior: X1(GlobalConsensus(r)) } if r == MillauNetwork::get()) + } + + fn build_destination() -> MultiLocation { + let dest: InteriorMultiLocation = MillauNetwork::get().into(); + let here = UniversalLocation::get(); + dest.relative_to(&here) + } + + fn xcm_lane() -> bp_messages::LaneId { + DEFAULT_XCM_LANE_TO_MILLAU + } +} + impl pallet_xcm::Config for Runtime { type Event = Event; type SendXcmOrigin = EnsureXcmOrigin; @@ -405,12 +470,17 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type LocationInverter = LocationInverter; + type Weigher = XcmWeigher; type Origin = Origin; type Call = Call; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = frame_support::traits::ConstU32<8>; + type UniversalLocation = UniversalLocation; } impl cumulus_pallet_xcm::Config for Runtime { @@ -427,6 +497,7 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); + type PriceForSiblingDelivery = (); } impl cumulus_pallet_dmp_queue::Config for Runtime { @@ -441,10 +512,82 @@ impl pallet_aura::Config for Runtime { type MaxAuthorities = MaxAuthorities; } -// /// Configure the pallet template in pallets/template. -// impl template::Config for Runtime { -// type Event = Event; -// } +impl pallet_bridge_relayers::Config for Runtime { + type Event = Event; + type Reward = Balance; + type PaymentProcedure = bp_relayers::MintReward, AccountId>; + type WeightInfo = (); +} + +parameter_types! { + /// This is a pretty unscientific cap. + /// + /// Note that once this is hit the pallet will essentially throttle incoming requests down to one + /// call per block. + pub const MaxRequests: u32 = 50; + + /// Number of headers to keep. + /// + /// Assuming the worst case of every header being finalized, we will keep headers at least for a + /// week. + pub const HeadersToKeep: u32 = 7 * bp_millau::DAYS as u32; +} + +pub type MillauGrandpaInstance = (); +impl pallet_bridge_grandpa::Config for Runtime { + type BridgedChain = bp_millau::Millau; + type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; + type WeightInfo = pallet_bridge_grandpa::weights::MillauWeight; +} + +parameter_types! { + pub const MaxMessagesToPruneAtOnce: bp_messages::MessageNonce = 8; + pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + // `IdentityFee` is used by Rialto => we may use weight directly + pub const GetDeliveryConfirmationTransactionFee: Balance = + bp_rialto_parachain::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _; + pub const RootAccountForPayments: Option = None; + pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; +} + +/// Instance of the messages pallet used to relay messages to/from Millau chain. +pub type WithMillauMessagesInstance = (); + +impl pallet_bridge_messages::Config for Runtime { + type Event = Event; + type WeightInfo = pallet_bridge_messages::weights::MillauWeight; + type Parameter = millau_messages::RialtoParachainToMillauMessagesParameter; + type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize; + type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; + type OutboundMessageFee = Balance; + + type InboundPayload = crate::millau_messages::FromMillauMessagePayload; + type InboundMessageFee = bp_millau::Balance; + type InboundRelayer = bp_millau::AccountId; + + type TargetHeaderChain = crate::millau_messages::Millau; + type LaneMessageVerifier = crate::millau_messages::ToMillauMessageVerifier; + type MessageDeliveryAndDispatchPayment = + pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter< + Runtime, + WithMillauMessagesInstance, + GetDeliveryConfirmationTransactionFee, + >; + type OnMessageAccepted = (); + type OnDeliveryConfirmed = (); + + type SourceHeaderChain = crate::millau_messages::Millau; + type MessageDispatch = crate::millau_messages::FromMillauMessageDispatch; + type BridgedChainId = BridgedChainId; +} // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( @@ -457,7 +600,7 @@ construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 20, ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21, @@ -473,8 +616,10 @@ construct_runtime!( CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, - // //Template - // TemplatePallet: template::{Pallet, Call, Storage, Event}, + // Millau bridge modules. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage}, + BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, } ); @@ -587,6 +732,49 @@ impl_runtime_apis! { } } + impl bp_millau::MillauFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeMillauGrandpa::best_finalized().map(|header| header.id()) + } + } + + impl bp_millau::ToMillauOutboundLaneApi for Runtime { + fn estimate_message_delivery_and_dispatch_fee( + _lane_id: bp_messages::LaneId, + payload: ToMillauMessagePayload, + millau_to_this_conversion_rate: Option, + ) -> Option { + estimate_message_dispatch_and_delivery_fee::( + &payload, + WithMillauMessageBridge::RELAYER_FEE_PERCENT, + millau_to_this_conversion_rate, + ).ok() + } + + fn message_details( + lane: bp_messages::LaneId, + begin: bp_messages::MessageNonce, + end: bp_messages::MessageNonce, + ) -> Vec> { + bridge_runtime_common::messages_api::outbound_message_details::< + Runtime, + WithMillauMessagesInstance, + >(lane, begin, end) + } + } + + impl bp_millau::FromMillauInboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> Vec { + bridge_runtime_common::messages_api::inbound_message_details::< + Runtime, + WithMillauMessagesInstance, + >(lane, messages) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn dispatch_benchmark( @@ -650,3 +838,72 @@ cumulus_pallet_parachain_system::register_validate_block!( BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, CheckInherents = CheckInherents, ); + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + MessageKey, + }; + use bp_runtime::messages::MessageDispatchResult; + use bridge_runtime_common::messages::target::FromBridgedChainMessageDispatch; + use codec::Encode; + + fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::default().build_storage::().unwrap(), + ) + } + + #[test] + fn xcm_messages_to_millau_are_sent() { + new_test_ext().execute_with(|| { + // the encoded message (origin ++ xcm) is 0x010109020419A8 + let dest = (Parent, X1(GlobalConsensus(MillauNetwork::get()))); + let xcm: Xcm<()> = vec![Instruction::Trap(42)].into(); + + let send_result = send_xcm::(dest.into(), xcm); + let expected_fee = MultiAssets::from((Here, Fungibility::Fungible(4_259_858_152_u128))); + let expected_hash = + ([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256); + assert_eq!(send_result, Ok((expected_hash, expected_fee)),); + }) + } + + #[test] + fn xcm_messages_from_millau_are_dispatched() { + type XcmExecutor = xcm_executor::XcmExecutor; + type MessageDispatcher = FromBridgedChainMessageDispatch< + WithMillauMessageBridge, + XcmExecutor, + XcmWeigher, + frame_support::traits::ConstU64, + >; + + new_test_ext().execute_with(|| { + let location: MultiLocation = + (Parent, X1(GlobalConsensus(MillauNetwork::get()))).into(); + let xcm: Xcm = vec![Instruction::Trap(42)].into(); + + let mut incoming_message = DispatchMessage { + key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 }, + data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 }, + }; + + let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message); + assert_eq!(dispatch_weight, 1_000_000_000); + + let dispatch_result = + MessageDispatcher::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert_eq!( + dispatch_result, + MessageDispatchResult { + dispatch_result: true, + unspent_weight: 0, + dispatch_fee_paid_during_dispatch: false, + } + ); + }) + } +} diff --git a/bin/rialto-parachain/runtime/src/millau_messages.rs b/bin/rialto-parachain/runtime/src/millau_messages.rs new file mode 100644 index 0000000000..136b4343c1 --- /dev/null +++ b/bin/rialto-parachain/runtime/src/millau_messages.rs @@ -0,0 +1,315 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Everything required to serve Millau <-> RialtoParachain messages. + +// TODO: this is almost exact copy of `millau_messages.rs` from Rialto runtime. +// Should be extracted to a separate crate and reused here. + +use crate::{OriginCaller, Runtime}; + +use bp_messages::{ + source_chain::{SenderOrigin, TargetHeaderChain}, + target_chain::{ProvedMessages, SourceHeaderChain}, + InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, +}; +use bp_runtime::{Chain, ChainId, MILLAU_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID}; +use bridge_runtime_common::messages::{ + self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction, +}; +use codec::{Decode, Encode}; +use frame_support::{ + parameter_types, + weights::{DispatchClass, Weight}, + RuntimeDebug, +}; +use scale_info::TypeInfo; +use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; +use sp_std::convert::TryFrom; + +/// Default lane that is used to send messages to Millau. +pub const DEFAULT_XCM_LANE_TO_MILLAU: LaneId = [0, 0, 0, 0]; +/// Initial value of `MillauToRialtoParachainConversionRate` parameter. +pub const INITIAL_MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE: FixedU128 = + FixedU128::from_inner(FixedU128::DIV); +/// Initial value of `MillauFeeMultiplier` parameter. +pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = 2 * crate::BASE_XCM_WEIGHT; + +parameter_types! { + /// Millau to RialtoParachain conversion rate. Initially we treat both tokens as equal. + pub storage MillauToRialtoParachainConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE; + /// Fee multiplier value at Millau chain. + pub storage MillauFeeMultiplier: FixedU128 = INITIAL_MILLAU_FEE_MULTIPLIER; +} + +/// Message payload for RialtoParachain -> Millau messages. +pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for RialtoParachain -> Millau messages. +pub type ToMillauMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Message payload for Millau -> RialtoParachain messages. +pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Call-dispatch based message dispatch for Millau -> RialtoParachain messages. +pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDispatch< + WithMillauMessageBridge, + xcm_executor::XcmExecutor, + crate::XcmWeigher, + // 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + // (it is prepended with `UniversalOrigin` instruction) + frame_support::traits::ConstU64, +>; + +/// Messages proof for Millau -> RialtoParachain messages. +pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesProof; + +/// Messages delivery proof for RialtoParachain -> Millau messages. +pub type ToMillauMessagesDeliveryProof = + messages::source::FromBridgedChainMessagesDeliveryProof; + +/// Maximal outbound payload size of Rialto -> Millau messages. +pub type ToMillauMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// Millau <-> RialtoParachain message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithMillauMessageBridge; + +impl MessageBridge for WithMillauMessageBridge { + const RELAYER_FEE_PERCENT: u32 = 10; + const THIS_CHAIN_ID: ChainId = RIALTO_PARACHAIN_CHAIN_ID; + const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID; + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = + bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME; + + type ThisChain = RialtoParachain; + type BridgedChain = Millau; + + fn bridged_balance_to_this_balance( + bridged_balance: bp_millau::Balance, + bridged_to_this_conversion_rate_override: Option, + ) -> bp_rialto_parachain::Balance { + let conversion_rate = bridged_to_this_conversion_rate_override + .unwrap_or_else(MillauToRialtoParachainConversionRate::get); + bp_rialto_parachain::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance)) + .unwrap_or(bp_rialto_parachain::Balance::MAX) + } +} + +/// RialtoParachain chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct RialtoParachain; + +impl messages::ChainWithMessages for RialtoParachain { + type Hash = bp_rialto_parachain::Hash; + type AccountId = bp_rialto_parachain::AccountId; + type Signer = bp_rialto_parachain::AccountSigner; + type Signature = bp_rialto_parachain::Signature; + type Weight = Weight; + type Balance = bp_rialto_parachain::Balance; +} + +impl messages::ThisChainWithMessages for RialtoParachain { + type Call = crate::Call; + type Origin = crate::Origin; + type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation< + Self::AccountId, + { bp_rialto_parachain::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT }, + { bp_millau::EXTRA_STORAGE_PROOF_SIZE }, + { bp_rialto_parachain::TX_EXTRA_BYTES }, + >; + + fn is_message_accepted(send_origin: &Self::Origin, lane: &LaneId) -> bool { + let here_location = xcm::v3::MultiLocation::from(crate::UniversalLocation::get()); + match send_origin.caller { + OriginCaller::PolkadotXcm(pallet_xcm::Origin::Xcm(ref location)) + if *location == here_location => + { + log::trace!(target: "runtime::bridge", "Verifying message sent using XCM pallet to Millau"); + }, + _ => { + // keep in mind that in this case all messages are free (in term of fees) + // => it's just to keep testing bridge on our test deployments until we'll have a + // better option + log::trace!(target: "runtime::bridge", "Verifying message sent using messages pallet to Millau"); + }, + } + + *lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1] + } + + fn maximal_pending_messages_at_outbound_lane() -> MessageNonce { + MessageNonce::MAX + } + + fn transaction_payment( + transaction: MessageTransaction, + ) -> bp_rialto_parachain::Balance { + // `transaction` may represent transaction from the future, when multiplier value will + // be larger, so let's use slightly increased value + let multiplier = FixedU128::saturating_from_rational(110, 100) + .saturating_mul(pallet_transaction_payment::Pallet::::next_fee_multiplier()); + // in our testnets, both per-byte fee and weight-to-fee are 1:1 + messages::transaction_payment( + bp_rialto_parachain::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic, + 1, + multiplier, + |weight| weight as _, + transaction, + ) + } +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; + +impl messages::ChainWithMessages for Millau { + type Hash = bp_millau::Hash; + type AccountId = bp_millau::AccountId; + type Signer = bp_millau::AccountSigner; + type Signature = bp_millau::Signature; + type Weight = Weight; + type Balance = bp_millau::Balance; +} + +impl messages::BridgedChainWithMessages for Millau { + fn maximal_extrinsic_size() -> u32 { + bp_millau::Millau::max_extrinsic_size() + } + + fn verify_dispatch_weight(_message_payload: &[u8]) -> bool { + true + } + + fn estimate_delivery_transaction( + message_payload: &[u8], + include_pay_dispatch_fee_cost: bool, + message_dispatch_weight: Weight, + ) -> MessageTransaction { + let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX); + let extra_bytes_in_payload = Weight::from(message_payload_len) + .saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH.into()); + + MessageTransaction { + dispatch_weight: extra_bytes_in_payload + .saturating_mul(bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT) + .saturating_add(bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT) + .saturating_sub(if include_pay_dispatch_fee_cost { + 0 + } else { + bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT + }) + .saturating_add(message_dispatch_weight), + size: message_payload_len + .saturating_add(bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE) + .saturating_add(bp_millau::TX_EXTRA_BYTES), + } + } + + fn transaction_payment(transaction: MessageTransaction) -> bp_millau::Balance { + // we don't have a direct access to the value of multiplier at Millau chain + // => it is a messages module parameter + let multiplier = MillauFeeMultiplier::get(); + // in our testnets, both per-byte fee and weight-to-fee are 1:1 + messages::transaction_payment( + bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic, + 1, + multiplier, + |weight| weight as _, + transaction, + ) + } +} + +impl TargetHeaderChain for Millau { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof of one or several keys; + // - id of the lane we prove state of. + type MessagesDeliveryProof = ToMillauMessagesDeliveryProof; + + fn verify_message(payload: &ToMillauMessagePayload) -> Result<(), Self::Error> { + messages::source::verify_chain_message::(payload) + } + + fn verify_messages_delivery_proof( + proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error> { + messages::source::verify_messages_delivery_proof::< + WithMillauMessageBridge, + Runtime, + crate::MillauGrandpaInstance, + >(proof) + } +} + +impl SourceHeaderChain for Millau { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof of one or several keys; + // - id of the lane we prove messages for; + // - inclusive range of messages nonces that are proved. + type MessagesProof = FromMillauMessagesProof; + + fn verify_messages_proof( + proof: Self::MessagesProof, + messages_count: u32, + ) -> Result>, Self::Error> { + messages::target::verify_messages_proof::< + WithMillauMessageBridge, + Runtime, + crate::MillauGrandpaInstance, + >(proof, messages_count) + } +} + +impl SenderOrigin for crate::Origin { + fn linked_account(&self) -> Option { + match self.caller { + crate::OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) => + Some(submitter.clone()), + _ => None, + } + } +} + +/// RialtoParachain -> Millau message lane pallet parameters. +#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] +pub enum RialtoParachainToMillauMessagesParameter { + /// The conversion formula we use is: `RialtoParachainTokens = MillauTokens * conversion_rate`. + MillauToRialtoParachainConversionRate(FixedU128), +} + +impl MessagesParameter for RialtoParachainToMillauMessagesParameter { + fn save(&self) { + match *self { + RialtoParachainToMillauMessagesParameter::MillauToRialtoParachainConversionRate( + ref conversion_rate, + ) => MillauToRialtoParachainConversionRate::set(conversion_rate), + } + } +} diff --git a/bin/rialto/node/Cargo.toml b/bin/rialto/node/Cargo.toml index e44ceb45fa..fe2186ea3f 100644 --- a/bin/rialto/node/Cargo.toml +++ b/bin/rialto/node/Cargo.toml @@ -5,7 +5,6 @@ version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" build = "build.rs" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" @@ -16,7 +15,7 @@ jsonrpc-core = "18.0" kvdb = "0.11" kvdb-rocksdb = "0.15" lru = "0.7" -serde_json = "1.0.59" +serde_json = "1.0.79" thiserror = "1.0" # Bridge dependencies @@ -35,7 +34,6 @@ frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" } node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" } -pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -66,6 +64,7 @@ sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -76,10 +75,10 @@ substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate # Polkadot Dependencies -polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, features = [ "full-node", "polkadot-native" ] } +polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false, features = [ "full-node", "polkadot-native" ] } [build-dependencies] substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/bin/rialto/node/src/chain_spec.rs b/bin/rialto/node/src/chain_spec.rs index 10315e33c8..41958aaf39 100644 --- a/bin/rialto/node/src/chain_spec.rs +++ b/bin/rialto/node/src/chain_spec.rs @@ -15,7 +15,6 @@ // along with Parity Bridges Common. If not, see . use beefy_primitives::crypto::AuthorityId as BeefyId; -use bp_rialto::derive_account_from_millau_id; use polkadot_primitives::v2::{AssignmentId, ValidatorId}; use rialto_runtime::{ AccountId, BabeConfig, BalancesConfig, BeefyConfig, BridgeMillauMessagesConfig, @@ -29,6 +28,17 @@ use sp_core::{sr25519, Pair, Public}; use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; +/// "Names" of the authorities accounts at local testnet. +const LOCAL_AUTHORITIES_ACCOUNTS: [&str; 5] = ["Alice", "Bob", "Charlie", "Dave", "Eve"]; +/// "Names" of the authorities accounts at development testnet. +const DEV_AUTHORITIES_ACCOUNTS: [&str; 1] = [LOCAL_AUTHORITIES_ACCOUNTS[0]]; +/// "Names" of all possible authorities accounts. +const ALL_AUTHORITIES_ACCOUNTS: [&str; 5] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Name" of the `sudo` account. +const SUDO_ACCOUNT: &str = "Sudo"; +/// "Name" of the account, which owns the with-Millau messages pallet. +const MILLAU_MESSAGES_PALLET_OWNER: &str = "Millau.MessagesOwner"; + /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. pub type ChainSpec = sc_service::GenericChainSpec; @@ -95,8 +105,11 @@ impl Alternative { sc_service::ChainType::Development, || { testnet_genesis( - vec![get_authority_keys_from_seed("Alice")], - get_account_id_from_seed::("Alice"), + DEV_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), endowed_accounts(), true, ) @@ -114,14 +127,11 @@ impl Alternative { sc_service::ChainType::Local, || { testnet_genesis( - vec![ - get_authority_keys_from_seed("Alice"), - get_authority_keys_from_seed("Bob"), - get_authority_keys_from_seed("Charlie"), - get_authority_keys_from_seed("Dave"), - get_authority_keys_from_seed("Eve"), - ], - get_account_id_from_seed::("Alice"), + LOCAL_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), endowed_accounts(), true, ) @@ -142,48 +152,28 @@ impl Alternative { /// accounts used by relayers in our test deployments, accounts used for demonstration /// purposes), are all available on these chains. fn endowed_accounts() -> Vec { + let all_authorities = ALL_AUTHORITIES_ACCOUNTS.iter().flat_map(|x| { + [ + get_account_id_from_seed::(x), + get_account_id_from_seed::(&format!("{}//stash", x)), + ] + }); vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), + // Sudo account + get_account_id_from_seed::(SUDO_ACCOUNT), + // Regular (unused) accounts get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("George"), - get_account_id_from_seed::("Harry"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), get_account_id_from_seed::("Ferdie//stash"), - get_account_id_from_seed::("George//stash"), - get_account_id_from_seed::("Harry//stash"), - get_account_id_from_seed::("MillauMessagesOwner"), - get_account_id_from_seed::("WithMillauTokenSwap"), - pallet_bridge_messages::relayer_fund_account_id::< - bp_rialto::AccountId, - bp_rialto::AccountIdConverter, - >(), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Alice"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Bob"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Charlie"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Dave"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Eve"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Ferdie"), - )), + // Accounts, used by Rialto<>Millau bridge + get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("Millau.HeadersAndMessagesRelay"), + get_account_id_from_seed::("Millau.OutboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Millau.InboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Millau.MessagesSender"), ] + .into_iter() + .chain(all_authorities) + .collect() } fn session_keys( @@ -287,16 +277,9 @@ fn testnet_genesis( }, paras: Default::default(), bridge_millau_messages: BridgeMillauMessagesConfig { - owner: Some(get_account_id_from_seed::("MillauMessagesOwner")), + owner: Some(get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER)), ..Default::default() }, + xcm_pallet: Default::default(), } } - -#[test] -fn derived_dave_account_is_as_expected() { - let dave = get_account_id_from_seed::("Dave"); - let derived: AccountId = - derive_account_from_millau_id(bp_runtime::SourceAccount::Account(dave)); - assert_eq!(derived.to_string(), "5HZhdv53gSJmWWtD8XR5Ypu4PgbT5JNWwGw2mkE75cN61w9t".to_string()); -} diff --git a/bin/rialto/node/src/cli.rs b/bin/rialto/node/src/cli.rs index bb7f54998d..0cdd25417e 100644 --- a/bin/rialto/node/src/cli.rs +++ b/bin/rialto/node/src/cli.rs @@ -67,6 +67,7 @@ pub enum Subcommand { Inspect(node_inspect::cli::InspectCmd), /// Benchmark runtime pallets. + #[clap(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// FOR INTERNAL USE: analog of the "prepare-worker" command of the polkadot binary. diff --git a/bin/rialto/node/src/command.rs b/bin/rialto/node/src/command.rs index da92837f06..852acb5955 100644 --- a/bin/rialto/node/src/command.rs +++ b/bin/rialto/node/src/command.rs @@ -15,8 +15,9 @@ // along with Parity Bridges Common. If not, see . use crate::cli::{Cli, Subcommand}; +use frame_benchmarking_cli::BenchmarkCmd; use rialto_runtime::{Block, RuntimeApi}; -use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; +use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -86,18 +87,22 @@ pub fn run() -> sc_cli::Result<()> { )); match &cli.subcommand { - Some(Subcommand::Benchmark(cmd)) => - if cfg!(feature = "runtime-benchmarks") { - let runner = cli.create_runner(cmd)?; - - runner.sync_run(|config| cmd.run::(config)) - } else { - println!( - "Benchmarking wasn't enabled when building the node. \ - You can enable it with `--features runtime-benchmarks`." - ); - Ok(()) - }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner.sync_run(|config| cmd.run::(config)) + } else { + println!( + "Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + ); + Ok(()) + }, + _ => Err("Unsupported benchmarking subcommand".into()), + } + }, Some(Subcommand::Key(cmd)) => cmd.run(&cli), Some(Subcommand::Sign(cmd)) => cmd.run(), Some(Subcommand::Verify(cmd)) => cmd.run(), @@ -147,7 +152,7 @@ pub fn run() -> sc_cli::Result<()> { runner.async_run(|mut config| { let (client, backend, _, task_manager) = polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; - Ok((cmd.run(client, backend), task_manager)) + Ok((cmd.run(client, backend, None), task_manager)) }) }, Some(Subcommand::Inspect(cmd)) => { @@ -181,34 +186,30 @@ pub fn run() -> sc_cli::Result<()> { // let is_collator = crate::service::IsCollator::No; let overseer_gen = polkadot_service::overseer::RealOverseerGen; runner.run_node_until_exit(|config| async move { - match config.role { - Role::Light => Err(sc_cli::Error::Service(sc_service::Error::Other( - "Light client is not supported by this node".into(), - ))), - _ => { - let is_collator = polkadot_service::IsCollator::No; - let grandpa_pause = None; - let enable_beefy = true; - let jaeger_agent = None; - let telemetry_worker_handle = None; - let program_path = None; - let overseer_enable_anyways = false; - - polkadot_service::new_full::( - config, - is_collator, - grandpa_pause, - enable_beefy, - jaeger_agent, - telemetry_worker_handle, - program_path, - overseer_enable_anyways, - overseer_gen, - ) - .map(|full| full.task_manager) - .map_err(service_error) - }, - } + let is_collator = polkadot_service::IsCollator::No; + let grandpa_pause = None; + let enable_beefy = true; + let jaeger_agent = None; + let telemetry_worker_handle = None; + let program_path = None; + let overseer_enable_anyways = false; + + polkadot_service::new_full::( + config, + is_collator, + grandpa_pause, + enable_beefy, + jaeger_agent, + telemetry_worker_handle, + program_path, + overseer_enable_anyways, + overseer_gen, + None, + None, + None, + ) + .map(|full| full.task_manager) + .map_err(service_error) }) }, } diff --git a/bin/rialto/runtime/Cargo.toml b/bin/rialto/runtime/Cargo.toml index 59b9a8e9b5..8d90f1f329 100644 --- a/bin/rialto/runtime/Cargo.toml +++ b/bin/rialto/runtime/Cargo.toml @@ -3,30 +3,29 @@ name = "rialto-runtime" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } hex-literal = "0.3" libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac"] } -log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge dependencies bp-header-chain = { path = "../../../primitives/header-chain", default-features = false } -bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false } bp-messages = { path = "../../../primitives/messages", default-features = false } bp-millau = { path = "../../../primitives/chain-millau", default-features = false } +bp-relayers = { path = "../../../primitives/relayers", default-features = false } bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false } bp-runtime = { path = "../../../primitives/runtime", default-features = false } bridge-runtime-common = { path = "../../runtime-common", default-features = false } -pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false } pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../../modules/messages", default-features = false } +pallet-bridge-relayers = { path = "../../../modules/relayers", default-features = false } pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false } # Substrate Dependencies @@ -44,7 +43,6 @@ pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "mast pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -58,6 +56,7 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -68,12 +67,17 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master # Polkadot (parachain) Dependencies -polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } -polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } -polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } [dev-dependencies] bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test"] } +env_logger = "0.8" libsecp256k1 = { version = "0.7", features = ["hmac"] } static_assertions = "1.1" @@ -85,9 +89,9 @@ default = ["std"] std = [ "beefy-primitives/std", "bp-header-chain/std", - "bp-message-dispatch/std", "bp-messages/std", "bp-millau/std", + "bp-relayers/std", "bp-rialto/std", "bp-runtime/std", "bridge-runtime-common/std", @@ -103,12 +107,13 @@ std = [ "pallet-balances/std", "pallet-beefy/std", "pallet-beefy-mmr/std", - "pallet-bridge-dispatch/std", "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", + "pallet-bridge-relayers/std", "pallet-grandpa/std", "pallet-mmr/std", - "pallet-mmr-primitives/std", + "pallet-xcm/std", + "sp-mmr-primitives/std", "pallet-shift-session-manager/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -134,6 +139,9 @@ std = [ "sp-transaction-pool/std", "sp-trie/std", "sp-version/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", ] runtime-benchmarks = [ "bridge-runtime-common/runtime-benchmarks", @@ -142,5 +150,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "libsecp256k1", "pallet-bridge-messages/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", ] diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs index 87cddf5e26..3729ab7863 100644 --- a/bin/rialto/runtime/src/lib.rs +++ b/bin/rialto/runtime/src/lib.rs @@ -30,28 +30,31 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod millau_messages; pub mod parachains; +pub mod xcm_config; use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge}; use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet}; +use bp_runtime::{HeaderId, HeaderIdProvider}; use bridge_runtime_common::messages::{ source::estimate_message_dispatch_and_delivery_fee, MessageBridge, }; use pallet_grandpa::{ fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; -use pallet_mmr_primitives::{ - DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof, -}; +use pallet_mmr::primitives as mmr; use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo}; use sp_api::impl_runtime_apis; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_mmr_primitives::{ + DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof, +}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perquintill, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perquintill, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; #[cfg(feature = "std")] @@ -68,10 +71,11 @@ pub use frame_support::{ pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; -pub use pallet_bridge_grandpa::Call as BridgeGrandpaMillauCall; +pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall; pub use pallet_bridge_messages::Call as MessagesCall; pub use pallet_sudo::Call as SudoCall; pub use pallet_timestamp::Call as TimestampCall; +pub use pallet_xcm::Call as XcmCall; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -249,18 +253,8 @@ impl pallet_babe::Config for Runtime { impl pallet_beefy::Config for Runtime { type BeefyId = BeefyId; -} - -impl pallet_bridge_dispatch::Config for Runtime { - type Event = Event; - type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce); - type Call = Call; - type CallFilter = frame_support::traits::Everything; - type EncodedCall = crate::millau_messages::FromMillauEncodedCall; - type SourceChainAccountId = bp_millau::AccountId; - type TargetChainAccountPublic = MultiSigner; - type TargetChainSignature = MultiSignature; - type AccountIdConverter = bp_rialto::AccountIdConverter; + type MaxAuthorities = MaxAuthorities; + type OnNewValidatorSet = MmrLeaf; } impl pallet_grandpa::Config for Runtime { @@ -279,6 +273,9 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); } +type MmrHash = ::Output; +type MmrHashing = ::Hashing; + impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = b"mmr"; type Hashing = Keccak256; @@ -305,10 +302,17 @@ parameter_types! { pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0); } +pub struct BeefyDummyDataProvider; + +impl beefy_primitives::mmr::BeefyDataProvider<()> for BeefyDummyDataProvider { + fn extra_data() {} +} + impl pallet_beefy_mmr::Config for Runtime { type LeafVersion = LeafVersion; type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; - type ParachainHeads = (); + type LeafExtra = (); + type BeefyDataProvider = BeefyDummyDataProvider; } parameter_types! { @@ -360,15 +364,16 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = bp_rialto::WeightToFee; + type LengthToFee = bp_rialto::WeightToFee; type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< Runtime, TargetBlockFullness, AdjustmentVariable, MinimumMultiplier, >; + type Event = Event; } impl pallet_sudo::Config for Runtime { @@ -393,6 +398,13 @@ impl pallet_authority_discovery::Config for Runtime { type MaxAuthorities = MaxAuthorities; } +impl pallet_bridge_relayers::Config for Runtime { + type Event = Event; + type Reward = Balance; + type PaymentProcedure = bp_relayers::MintReward, AccountId>; + type WeightInfo = (); +} + parameter_types! { /// This is a pretty unscientific cap. /// @@ -427,7 +439,7 @@ parameter_types! { pub const GetDeliveryConfirmationTransactionFee: Balance = bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _; pub const RootAccountForPayments: Option = None; - pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; + pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; } /// Instance of the messages pallet used to relay messages to/from Millau chain. @@ -441,6 +453,7 @@ impl pallet_bridge_messages::Config for Runtime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize; type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; type OutboundMessageFee = Balance; @@ -448,15 +461,12 @@ impl pallet_bridge_messages::Config for Runtime { type InboundMessageFee = bp_millau::Balance; type InboundRelayer = bp_millau::AccountId; - type AccountIdConverter = bp_rialto::AccountIdConverter; - type TargetHeaderChain = crate::millau_messages::Millau; type LaneMessageVerifier = crate::millau_messages::ToMillauMessageVerifier; type MessageDeliveryAndDispatchPayment = - pallet_bridge_messages::instant_payments::InstantCurrencyPayments< + pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter< Runtime, WithMillauMessagesInstance, - pallet_balances::Pallet, GetDeliveryConfirmationTransactionFee, >; type OnMessageAccepted = (); @@ -481,7 +491,7 @@ construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, // Consensus support. AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config}, @@ -495,8 +505,8 @@ construct_runtime!( MmrLeaf: pallet_beefy_mmr::{Pallet, Storage}, // Millau bridge modules. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage}, - BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event}, BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, // Parachain modules. @@ -517,6 +527,9 @@ construct_runtime!( Registrar: polkadot_runtime_common::paras_registrar::{Pallet, Call, Storage, Event}, Slots: polkadot_runtime_common::slots::{Pallet, Call, Storage, Event}, ParasSudoWrapper: polkadot_runtime_common::paras_sudo_wrapper::{Pallet, Call}, + + // Pallet for sending XCM. + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, } ); @@ -610,12 +623,15 @@ impl_runtime_apis! { } } - impl pallet_mmr_primitives::MmrApi for Runtime { + impl sp_mmr_primitives::MmrApi for Runtime { fn generate_proof(leaf_index: u64) -> Result<(EncodableOpaqueLeaf, MmrProof), MmrError> { - Mmr::generate_proof(leaf_index) - .map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof)) + Mmr::generate_batch_proof(vec![leaf_index]) + .and_then(|(leaves, proof)| Ok(( + mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), + mmr::BatchProof::into_single_leaf_proof(proof)? + ))) } fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof) @@ -629,7 +645,7 @@ impl_runtime_apis! { .into_opaque_leaf() .try_decode() .ok_or(MmrError::Verify)?; - Mmr::verify_leaf(leaf, proof) + Mmr::verify_leaves(vec![leaf], mmr::Proof::into_batch_proof(proof)) } fn verify_proof_stateless( @@ -637,16 +653,51 @@ impl_runtime_apis! { leaf: EncodableOpaqueLeaf, proof: MmrProof ) -> Result<(), MmrError> { - type MmrHashing = ::Hashing; let node = DataOrHash::Data(leaf.into_opaque_leaf()); - pallet_mmr::verify_leaf_proof::(root, node, proof) + pallet_mmr::verify_leaves_proof::( + root, + vec![node], + pallet_mmr::primitives::Proof::into_batch_proof(proof), + ) + } + + fn mmr_root() -> Result { + Ok(Mmr::mmr_root()) + } + + fn generate_batch_proof(leaf_indices: Vec) + -> Result<(Vec, mmr::BatchProof), mmr::Error> + { + Mmr::generate_batch_proof(leaf_indices) + .map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof)) + } + + fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) + -> Result<(), mmr::Error> + { + type Leaf = < + ::LeafData as LeafDataProvider + >::LeafData; + let leaves = leaves.into_iter().map(|leaf| + leaf.into_opaque_leaf() + .try_decode() + .ok_or(mmr::Error::Verify)).collect::, mmr::Error>>()?; + Mmr::verify_leaves(leaves, proof) + } + + fn verify_batch_proof_stateless( + root: MmrHash, + leaves: Vec, + proof: mmr::BatchProof + ) -> Result<(), mmr::Error> { + let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); + pallet_mmr::verify_leaves_proof::(root, nodes, proof) } } impl bp_millau::MillauFinalityApi for Runtime { - fn best_finalized() -> (bp_millau::BlockNumber, bp_millau::Hash) { - let header = BridgeMillauGrandpa::best_finalized(); - (header.number, header.hash()) + fn best_finalized() -> Option> { + BridgeMillauGrandpa::best_finalized().map(|header| header.id()) } } @@ -715,7 +766,7 @@ impl_runtime_apis! { } } - impl polkadot_primitives::v2::ParachainHost for Runtime { + impl polkadot_primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { polkadot_runtime_parachains::runtime_api_impl::v2::validators::() } @@ -809,6 +860,10 @@ impl_runtime_apis! { { polkadot_runtime_parachains::runtime_api_impl::v2::validation_code_hash::(para_id, assumption) } + + fn staging_get_disputes() -> Vec<(polkadot_primitives::v2::SessionIndex, polkadot_primitives::v2::CandidateHash, polkadot_primitives::v2::DisputeState)> { + unimplemented!() + } } impl sp_authority_discovery::AuthorityDiscoveryApi for Runtime { @@ -893,38 +948,25 @@ impl_runtime_apis! { lane: bp_messages::LaneId, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, - ) -> Vec> { + ) -> Vec> { bridge_runtime_common::messages_api::outbound_message_details::< Runtime, WithMillauMessagesInstance, - WithMillauMessageBridge, >(lane, begin, end) } } -} -/// Millau account ownership digest from Rialto. -/// -/// The byte vector returned by this function should be signed with a Millau account private key. -/// This way, the owner of `rialto_account_id` on Rialto proves that the 'millau' account private -/// key is also under his control. -pub fn rialto_to_millau_account_ownership_digest( - millau_call: &Call, - rialto_account_id: AccountId, - millau_spec_version: SpecVersion, -) -> sp_std::vec::Vec -where - Call: codec::Encode, - AccountId: codec::Encode, - SpecVersion: codec::Encode, -{ - pallet_bridge_dispatch::account_ownership_digest( - millau_call, - rialto_account_id, - millau_spec_version, - bp_runtime::RIALTO_CHAIN_ID, - bp_runtime::MILLAU_CHAIN_ID, - ) + impl bp_millau::FromMillauInboundLaneApi for Runtime { + fn message_details( + lane: bp_messages::LaneId, + messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, + ) -> Vec { + bridge_runtime_common::messages_api::inbound_message_details::< + Runtime, + WithMillauMessagesInstance, + >(lane, messages) + } + } } #[cfg(test)] diff --git a/bin/rialto/runtime/src/millau_messages.rs b/bin/rialto/runtime/src/millau_messages.rs index 44348383f1..1267cbd06e 100644 --- a/bin/rialto/runtime/src/millau_messages.rs +++ b/bin/rialto/runtime/src/millau_messages.rs @@ -16,7 +16,7 @@ //! Everything required to serve Millau <-> Rialto messages. -use crate::Runtime; +use crate::{Call, OriginCaller, Runtime}; use bp_messages::{ source_chain::{SenderOrigin, TargetHeaderChain}, @@ -24,7 +24,9 @@ use bp_messages::{ InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, }; use bp_runtime::{Chain, ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID}; -use bridge_runtime_common::messages::{self, MessageBridge, MessageTransaction}; +use bridge_runtime_common::messages::{ + self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction, +}; use codec::{Decode, Encode}; use frame_support::{ parameter_types, @@ -33,13 +35,17 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; -use sp_std::{convert::TryFrom, ops::RangeInclusive}; +use sp_std::convert::TryFrom; /// Initial value of `MillauToRialtoConversionRate` parameter. pub const INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE: FixedU128 = FixedU128::from_inner(FixedU128::DIV); /// Initial value of `MillauFeeMultiplier` parameter. pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = 2 * crate::xcm_config::BASE_XCM_WEIGHT; parameter_types! { /// Millau to Rialto conversion rate. Initially we treat both tokens as equal. @@ -49,26 +55,22 @@ parameter_types! { } /// Message payload for Rialto -> Millau messages. -pub type ToMillauMessagePayload = - messages::source::FromThisChainMessagePayload; +pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload; /// Message verifier for Rialto -> Millau messages. pub type ToMillauMessageVerifier = messages::source::FromThisChainMessageVerifier; /// Message payload for Millau -> Rialto messages. -pub type FromMillauMessagePayload = - messages::target::FromBridgedChainMessagePayload; - -/// Encoded Rialto Call as it comes from Millau. -pub type FromMillauEncodedCall = messages::target::FromBridgedChainEncodedMessageCall; +pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload; /// Call-dispatch based message dispatch for Millau -> Rialto messages. pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDispatch< WithMillauMessageBridge, - crate::Runtime, - pallet_balances::Pallet, - (), + xcm_executor::XcmExecutor, + crate::xcm_config::XcmWeigher, + // + frame_support::traits::ConstU64, >; /// Messages proof for Millau -> Rialto messages. @@ -78,6 +80,10 @@ pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesPro pub type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof; +/// Maximal outbound payload size of Rialto -> Millau messages. +pub type ToMillauMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + /// Millau <-> Rialto message bridge. #[derive(RuntimeDebug, Clone, Copy)] pub struct WithMillauMessageBridge; @@ -96,7 +102,7 @@ impl MessageBridge for WithMillauMessageBridge { bridged_to_this_conversion_rate_override: Option, ) -> bp_rialto::Balance { let conversion_rate = bridged_to_this_conversion_rate_override - .unwrap_or_else(|| MillauToRialtoConversionRate::get()); + .unwrap_or_else(MillauToRialtoConversionRate::get); bp_rialto::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance)) .unwrap_or(bp_rialto::Balance::MAX) } @@ -118,31 +124,37 @@ impl messages::ChainWithMessages for Rialto { impl messages::ThisChainWithMessages for Rialto { type Origin = crate::Origin; type Call = crate::Call; + type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation< + Self::AccountId, + { bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT }, + { bp_millau::EXTRA_STORAGE_PROOF_SIZE }, + { bp_rialto::TX_EXTRA_BYTES }, + >; fn is_message_accepted(send_origin: &Self::Origin, lane: &LaneId) -> bool { - send_origin.linked_account().is_some() && (*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1]) + let here_location = + xcm::v3::MultiLocation::from(crate::xcm_config::UniversalLocation::get()); + match send_origin.caller { + OriginCaller::XcmPallet(pallet_xcm::Origin::Xcm(ref location)) + if *location == here_location => + { + log::trace!(target: "runtime::bridge", "Verifying message sent using XCM pallet to Millau"); + }, + _ => { + // keep in mind that in this case all messages are free (in term of fees) + // => it's just to keep testing bridge on our test deployments until we'll have a + // better option + log::trace!(target: "runtime::bridge", "Verifying message sent using messages pallet to Millau"); + }, + } + + *lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1] } fn maximal_pending_messages_at_outbound_lane() -> MessageNonce { MessageNonce::MAX } - fn estimate_delivery_confirmation_transaction() -> MessageTransaction { - let inbound_data_size = InboundLaneData::::encoded_size_hint( - bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); - - MessageTransaction { - dispatch_weight: bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT, - size: inbound_data_size - .saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE) - .saturating_add(bp_rialto::TX_EXTRA_BYTES), - } - } - fn transaction_payment(transaction: MessageTransaction) -> bp_rialto::Balance { // `transaction` may represent transaction from the future, when multiplier value will // be larger, so let's use slightly increased value @@ -177,19 +189,8 @@ impl messages::BridgedChainWithMessages for Millau { bp_millau::Millau::max_extrinsic_size() } - fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive { - // we don't want to relay too large messages + keep reserve for future upgrades - let upper_limit = messages::target::maximal_incoming_message_dispatch_weight( - bp_millau::Millau::max_extrinsic_weight(), - ); - - // we're charging for payload bytes in `WithMillauMessageBridge::transaction_payment` - // function - // - // this bridge may be used to deliver all kind of messages, so we're not making any - // assumptions about minimal dispatch weight here - - 0..=upper_limit + fn verify_dispatch_weight(_message_payload: &[u8]) -> bool { + true } fn estimate_delivery_transaction( @@ -278,14 +279,8 @@ impl SourceHeaderChain for Millau { impl SenderOrigin for crate::Origin { fn linked_account(&self) -> Option { - match self.caller { - crate::OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) => - Some(submitter.clone()), - crate::OriginCaller::system(frame_system::RawOrigin::Root) | - crate::OriginCaller::system(frame_system::RawOrigin::None) => - crate::RootAccountForPayments::get(), - _ => None, - } + // XCM deals wit fees in our deployments + None } } @@ -308,100 +303,15 @@ impl MessagesParameter for RialtoToMillauMessagesParameter { #[cfg(test)] mod tests { use super::*; - use crate::{ - AccountId, Call, DbWeight, ExistentialDeposit, MillauGrandpaInstance, Runtime, SystemCall, - SystemConfig, WithMillauMessagesInstance, VERSION, - }; - use bp_message_dispatch::CallOrigin; - use bp_messages::{ - target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - MessageKey, - }; - use bp_runtime::{derive_account_id, messages::DispatchFeePayment, Chain, SourceAccount}; + use crate::{DbWeight, MillauGrandpaInstance, Runtime, WithMillauMessagesInstance}; + use bp_runtime::Chain; use bridge_runtime_common::{ assert_complete_bridge_types, integrity::{ assert_complete_bridge_constants, AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, AssertCompleteBridgeConstants, }, - messages::target::{FromBridgedChainEncodedMessageCall, FromBridgedChainMessagePayload}, - }; - use frame_support::{ - traits::Currency, - weights::{GetDispatchInfo, WeightToFeePolynomial}, }; - use sp_runtime::traits::Convert; - - #[test] - fn transfer_happens_when_dispatch_fee_is_paid_at_target_chain() { - // this test actually belongs to the `bridge-runtime-common` crate, but there we have no - // mock runtime. Making another one there just for this test, given that both crates - // live n single repo is an overkill - let mut ext: sp_io::TestExternalities = - SystemConfig::default().build_storage::().unwrap().into(); - ext.execute_with(|| { - let bridge = MILLAU_CHAIN_ID; - let call: Call = SystemCall::set_heap_pages { pages: 64 }.into(); - let dispatch_weight = call.get_dispatch_info().weight; - let dispatch_fee = ::WeightToFee::calc( - &dispatch_weight, - ); - assert!(dispatch_fee > 0); - - // create relayer account with minimal balance - let relayer_account: AccountId = [1u8; 32].into(); - let initial_amount = ExistentialDeposit::get(); - let _ = as Currency>::deposit_creating( - &relayer_account, - initial_amount, - ); - - // create dispatch account with minimal balance + dispatch fee - let dispatch_account = derive_account_id::< - ::SourceChainAccountId, - >(bridge, SourceAccount::Root); - let dispatch_account = - ::AccountIdConverter::convert( - dispatch_account, - ); - let _ = as Currency>::deposit_creating( - &dispatch_account, - initial_amount + dispatch_fee, - ); - - // dispatch message with intention to pay dispatch fee at the target chain - FromMillauMessageDispatch::dispatch( - &relayer_account, - DispatchMessage { - key: MessageKey { lane_id: Default::default(), nonce: 0 }, - data: DispatchMessageData { - payload: Ok(FromBridgedChainMessagePayload:: { - spec_version: VERSION.spec_version, - weight: dispatch_weight, - origin: CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtTargetChain, - call: FromBridgedChainEncodedMessageCall::new(call.encode()), - }), - fee: 1, - }, - }, - ); - - // ensure that fee has been transferred from dispatch to relayer account - assert_eq!( - as Currency>::free_balance( - &relayer_account - ), - initial_amount + dispatch_fee, - ); - assert_eq!( - as Currency>::free_balance( - &dispatch_account - ), - initial_amount, - ); - }); - } #[test] fn ensure_rialto_message_lane_weights_are_correct() { @@ -428,12 +338,10 @@ mod tests { ); let max_incoming_inbound_lane_data_proof_size = - bp_messages::InboundLaneData::<()>::encoded_size_hint( - bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, + bp_messages::InboundLaneData::<()>::encoded_size_hint_u32( bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as _, bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as _, - ) - .unwrap_or(u32::MAX); + ); pallet_bridge_messages::ensure_able_to_receive_confirmation::( bp_rialto::Rialto::max_extrinsic_size(), bp_rialto::Rialto::max_extrinsic_weight(), @@ -453,7 +361,6 @@ mod tests { bridge: WithMillauMessageBridge, this_chain: bp_rialto::Rialto, bridged_chain: bp_millau::Millau, - this_chain_account_id_converter: bp_rialto::AccountIdConverter ); assert_complete_bridge_constants::< @@ -490,69 +397,4 @@ mod tests { .0, ); } - - #[test] - #[ignore] - fn no_stack_overflow_when_decoding_nested_call_during_dispatch() { - // this test is normally ignored, because it only makes sense to run it in release mode - - let mut ext: sp_io::TestExternalities = - SystemConfig::default().build_storage::().unwrap().into(); - ext.execute_with(|| { - let bridge = MILLAU_CHAIN_ID; - - let mut call: Call = SystemCall::set_heap_pages { pages: 64 }.into(); - - for _i in 0..3000 { - call = Call::Sudo(pallet_sudo::Call::sudo { call: Box::new(call) }); - } - - let dispatch_weight = 500; - let dispatch_fee = ::WeightToFee::calc( - &dispatch_weight, - ); - assert!(dispatch_fee > 0); - - // create relayer account with minimal balance - let relayer_account: AccountId = [1u8; 32].into(); - let initial_amount = ExistentialDeposit::get(); - let _ = as Currency>::deposit_creating( - &relayer_account, - initial_amount, - ); - - // create dispatch account with minimal balance + dispatch fee - let dispatch_account = derive_account_id::< - ::SourceChainAccountId, - >(bridge, SourceAccount::Root); - let dispatch_account = - ::AccountIdConverter::convert( - dispatch_account, - ); - let _ = as Currency>::deposit_creating( - &dispatch_account, - initial_amount + dispatch_fee, - ); - - // dispatch message with intention to pay dispatch fee at the target chain - // - // this is where the stack overflow has happened before the fix has been applied - FromMillauMessageDispatch::dispatch( - &relayer_account, - DispatchMessage { - key: MessageKey { lane_id: Default::default(), nonce: 0 }, - data: DispatchMessageData { - payload: Ok(FromBridgedChainMessagePayload:: { - spec_version: VERSION.spec_version, - weight: dispatch_weight, - origin: CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtTargetChain, - call: FromBridgedChainEncodedMessageCall::new(call.encode()), - }), - fee: 1, - }, - }, - ); - }); - } } diff --git a/bin/rialto/runtime/src/parachains.rs b/bin/rialto/runtime/src/parachains.rs index 20a9aeb28c..d6267bca23 100644 --- a/bin/rialto/runtime/src/parachains.rs +++ b/bin/rialto/runtime/src/parachains.rs @@ -18,7 +18,7 @@ use crate::{ AccountId, Babe, Balance, Balances, BlockNumber, Call, Event, Origin, Registrar, Runtime, - Slots, UncheckedExtrinsic, + ShiftSessionManager, Slots, UncheckedExtrinsic, }; use frame_support::{parameter_types, weights::Weight}; @@ -95,7 +95,9 @@ impl parachains_paras_inherent::Config for Runtime { impl parachains_scheduler::Config for Runtime {} -impl parachains_session_info::Config for Runtime {} +impl parachains_session_info::Config for Runtime { + type ValidatorSet = ShiftSessionManager; +} impl parachains_shared::Config for Runtime {} diff --git a/bin/rialto/runtime/src/xcm_config.rs b/bin/rialto/runtime/src/xcm_config.rs new file mode 100644 index 0000000000..ab0029302a --- /dev/null +++ b/bin/rialto/runtime/src/xcm_config.rs @@ -0,0 +1,283 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! XCM configurations for the Rialto runtime. + +use super::{ + millau_messages::WithMillauMessageBridge, AccountId, AllPalletsWithSystem, Balances, Call, + Event, Origin, Runtime, WithMillauMessagesInstance, XcmPallet, +}; +use bp_rialto::WeightToFee; +use bridge_runtime_common::{ + messages::source::{XcmBridge, XcmBridgeAdapter}, + CustomNetworkId, +}; +use frame_support::{ + parameter_types, + traits::{Everything, Nothing}, + weights::Weight, +}; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, + CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, +}; + +parameter_types! { + /// The location of the `MLAU` token, from the context of this chain. Since this token is native to this + /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to + /// the context". + pub const TokenLocation: MultiLocation = Here.into_location(); + /// The Rialto network ID. + pub const ThisNetwork: NetworkId = CustomNetworkId::Rialto.as_network_id(); + /// The Millau network ID. + pub const MillauNetwork: NetworkId = CustomNetworkId::Millau.as_network_id(); + + /// Our XCM location ancestry - i.e. our location within the Consensus Universe. + /// + /// Since Polkadot is a top-level relay-chain with its own consensus, it's just our network ID. + pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); + /// The check account, which holds any native assets that have been teleported out and not back in (yet). + pub CheckAccount: AccountId = XcmPallet::check_account(); +} + +/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to +/// determine the sovereign account controlled by a location. +pub type SovereignAccountOf = ( + // We can directly alias an `AccountId32` into a local account. + AccountId32Aliases, +); + +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the +/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// +/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // We can convert the MultiLocations with our converter above: + SovereignAccountOf, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We track our teleports in/out to keep total issuance correct. + CheckAccount, +>; + +/// The means that we convert the XCM message origin location into a local dispatch origin. +type LocalOriginConverter = ( + // A `Signed` origin of the sovereign account that the original location controls. + SovereignSignedViaLocation, + // The AccountId32 location type can be expressed natively as a `Signed` origin. + SignedAccountId32AsNative, +); + +/// The amount of weight an XCM operation takes. This is a safe overestimate. +pub const BASE_XCM_WEIGHT: Weight = 1_000_000_000; + +parameter_types! { + /// The amount of weight an XCM operation takes. This is a safe overestimate. + pub const BaseXcmWeight: Weight = BASE_XCM_WEIGHT; + /// Maximum number of instructions in a single XCM fragment. A sanity check against weight + /// calculations getting too crazy. + pub const MaxInstructions: u32 = 100; +} + +/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our +/// individual routers. +pub type XcmRouter = ( + // Router to send messages to Millau. + XcmBridgeAdapter, +); + +parameter_types! { + pub const MaxAssetsIntoHolding: u32 = 64; +} + +/// The barriers one of which must be passed for an XCM message to be executed. +pub type Barrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, +); + +/// Incoming XCM weigher type. +pub type XcmWeigher = xcm_builder::FixedWeightBounds; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type Call = Call; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = XcmWeigher; + // The weight trader piggybacks on the existing transaction-fee conversion logic. + type Trader = UsingComponents; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = Call; +} + +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. +pub type LocalOriginToLocation = ( + // Usual Signed origin to be used in XCM as a corresponding AccountId32 + SignedToAccountId32, +); + +impl pallet_xcm::Config for Runtime { + type Event = Event; + // We don't allow any messages to be sent via the transaction yet. This is basically safe to + // enable, (safe the possibility of someone spamming the parachain if they're willing to pay + // the DOT to send from the Relay-chain). But it's useless until we bring in XCM v3 which will + // make `DescendOrigin` a bit more useful. + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally. + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = xcm_executor::XcmExecutor; + // Anyone is able to use teleportation regardless of who they are and what they want to + // teleport. + type XcmTeleportFilter = Everything; + // Anyone is able to use reserve transfers regardless of who they are and what they want to + // transfer. + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + type UniversalLocation = UniversalLocation; + type Origin = Origin; + type Call = Call; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = SovereignAccountOf; + type MaxLockers = frame_support::traits::ConstU32<8>; +} + +/// With-Millau bridge. +pub struct ToMillauBridge; + +impl XcmBridge for ToMillauBridge { + type MessageBridge = WithMillauMessageBridge; + type MessageSender = pallet_bridge_messages::Pallet; + + fn universal_location() -> InteriorMultiLocation { + UniversalLocation::get() + } + + fn verify_destination(dest: &MultiLocation) -> bool { + matches!(*dest, MultiLocation { parents: 1, interior: X1(GlobalConsensus(r)) } if r == MillauNetwork::get()) + } + + fn build_destination() -> MultiLocation { + let dest: InteriorMultiLocation = MillauNetwork::get().into(); + let here = UniversalLocation::get(); + dest.relative_to(&here) + } + + fn xcm_lane() -> bp_messages::LaneId { + [0, 0, 0, 0] + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + MessageKey, + }; + use bp_runtime::messages::MessageDispatchResult; + use bridge_runtime_common::messages::target::FromBridgedChainMessageDispatch; + use codec::Encode; + + fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::default().build_storage::().unwrap(), + ) + } + + #[test] + fn xcm_messages_to_millau_are_sent() { + new_test_ext().execute_with(|| { + // the encoded message (origin ++ xcm) is 0x010109030419A8 + let dest = (Parent, X1(GlobalConsensus(MillauNetwork::get()))); + let xcm: Xcm<()> = vec![Instruction::Trap(42)].into(); + + let send_result = send_xcm::(dest.into(), xcm); + let expected_fee = MultiAssets::from((Here, 4_259_858_152_u128)); + let expected_hash = + ([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256); + assert_eq!(send_result, Ok((expected_hash, expected_fee)),); + }) + } + + #[test] + fn xcm_messages_from_millau_are_dispatched() { + type XcmExecutor = xcm_executor::XcmExecutor; + type MessageDispatcher = FromBridgedChainMessageDispatch< + WithMillauMessageBridge, + XcmExecutor, + XcmWeigher, + frame_support::traits::ConstU64, + >; + + new_test_ext().execute_with(|| { + let location: MultiLocation = + (Parent, X1(GlobalConsensus(MillauNetwork::get()))).into(); + let xcm: Xcm = vec![Instruction::Trap(42)].into(); + + let mut incoming_message = DispatchMessage { + key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 }, + data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 }, + }; + + let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message); + assert_eq!(dispatch_weight, 1_000_000_000); + + let dispatch_result = + MessageDispatcher::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert_eq!( + dispatch_result, + MessageDispatchResult { + dispatch_result: true, + unspent_weight: 0, + dispatch_fee_paid_during_dispatch: false, + } + ); + }) + } +} diff --git a/bin/runtime-common/Cargo.toml b/bin/runtime-common/Cargo.toml index abd84364ce..bb75d828d2 100644 --- a/bin/runtime-common/Cargo.toml +++ b/bin/runtime-common/Cargo.toml @@ -3,25 +3,26 @@ name = "bridge-runtime-common" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" -homepage = "https://substrate.dev" repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -ed25519-dalek = { version = "1.0", default-features = false, optional = true } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } hash-db = { version = "0.15.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +log = { version = "0.4.17", default-features = false } +num-traits = { version = "0.2", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } # Bridge dependencies -bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false } bp-messages = { path = "../../primitives/messages", default-features = false } +bp-parachains = { path = "../../primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } bp-runtime = { path = "../../primitives/runtime", default-features = false } -pallet-bridge-dispatch = { path = "../../modules/dispatch", default-features = false } pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../modules/messages", default-features = false } +pallet-bridge-parachains = { path = "../../modules/parachains", default-features = false } # Substrate dependencies @@ -31,41 +32,60 @@ pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "m pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +# Polkadot dependencies + +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } + +[dev-dependencies] +millau-runtime = { path = "../millau/runtime" } + [features] default = ["std"] std = [ - "bp-message-dispatch/std", "bp-messages/std", + "bp-parachains/std", + "bp-polkadot-core/std", "bp-runtime/std", "codec/std", "frame-support/std", "frame-system/std", "hash-db/std", - "pallet-bridge-dispatch/std", + "log/std", + "num-traits/std", "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", + "pallet-bridge-parachains/std", "pallet-transaction-payment/std", + "pallet-xcm/std", "scale-info/std", "sp-api/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-state-machine/std", "sp-std/std", "sp-trie/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", ] runtime-benchmarks = [ - "ed25519-dalek/u64_backend", "pallet-balances", "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", "sp-state-machine", "sp-version", + "xcm-builder/runtime-benchmarks", ] integrity-test = [ "static_assertions", diff --git a/bin/runtime-common/README.md b/bin/runtime-common/README.md deleted file mode 100644 index 5f2298cd78..0000000000 --- a/bin/runtime-common/README.md +++ /dev/null @@ -1,181 +0,0 @@ -# Helpers for Messages Module Integration - -The [`messages`](./src/messages.rs) module of this crate contains a bunch of helpers for integrating -messages module into your runtime. Basic prerequisites of these helpers are: -- we're going to bridge Substrate-based chain with another Substrate-based chain; -- both chains have [messages module](../../modules/messages/README.md), Substrate bridge - module and the [call dispatch module](../../modules/dispatch/README.md); -- all message lanes are identical and may be used to transfer the same messages; -- the messages sent over the bridge are dispatched using - [call dispatch module](../../modules/dispatch/README.md); -- the messages are `bp_message_dispatch::MessagePayload` structures, where `call` field is - encoded `Call` of the target chain. This means that the `Call` is opaque to the - [messages module](../../modules/messages/README.md) instance at the source chain. - It is pre-encoded by the message submitter; -- all proofs in the [messages module](../../modules/messages/README.md) transactions are - based on the storage proofs from the bridged chain: storage proof of the outbound message (value - from the `pallet_bridge_messages::Store::MessagePayload` map), storage proof of the outbound lane - state (value from the `pallet_bridge_messages::Store::OutboundLanes` map) and storage proof of the - inbound lane state (value from the `pallet_bridge_messages::Store::InboundLanes` map); -- storage proofs are built at the finalized headers of the corresponding chain. So all message lane - transactions with proofs are verifying storage proofs against finalized chain headers from - Substrate bridge module. - -**IMPORTANT NOTE**: after reading this document, you may refer to our test runtimes -([rialto_messages.rs](../millau/runtime/src/rialto_messages.rs) and/or -[millau_messages.rs](../rialto/runtime/src/millau_messages.rs)) to see how to use these helpers. - -## Contents -- [`MessageBridge` Trait](#messagebridge-trait) -- [`ChainWithMessages` Trait ](#ChainWithMessages-trait) -- [Helpers for the Source Chain](#helpers-for-the-source-chain) -- [Helpers for the Target Chain](#helpers-for-the-target-chain) - -## `MessageBridge` Trait - -The essence of your integration will be a struct that implements a `MessageBridge` trait. It has -single method (`MessageBridge::bridged_balance_to_this_balance`), used to convert from bridged chain -tokens into this chain tokens. The bridge also requires two associated types to be specified - -`ThisChain` and `BridgedChain`. - -Worth to say that if you're going to use hardcoded constant (conversion rate) in the -`MessageBridge::bridged_balance_to_this_balance` method (or in any other method of -`ThisChainWithMessages` or `BridgedChainWithMessages` traits), then you should take a -look at the -[messages parameters functionality](../../modules/messages/README.md#Non-Essential-Functionality). -They allow pallet owner to update constants more frequently than runtime upgrade happens. - -## `ChainWithMessages` Trait - -The trait is quite simple and can easily be implemented - you just need to specify types used at the -corresponding chain. There is single exception, though (it may be changed in the future): - -- `ChainWithMessages::MessagesInstance`: this is used to compute runtime storage keys. There - may be several instances of messages pallet, included in the Runtime. Every instance stores - messages and these messages stored under different keys. When we are verifying storage proofs from - the bridged chain, we should know which instance we're talking to. This is fine, but there's - significant inconvenience with that - this chain runtime must have the same messages pallet - instance. This does not necessarily mean that we should use the same instance on both chains - - this instance may be used to bridge with another chain/instance, or may not be used at all. - -## `ThisChainWithMessages` Trait - -This trait represents this chain from bridge point of view. Let's review every method of this trait: - -- `ThisChainWithMessages::is_message_accepted`: is used to check whether given lane accepts - messages. The send-message origin is passed to the function, so you may e.g. verify that only - given pallet is able to send messages over selected lane. **IMPORTANT**: if you assume that the - message must be paid by the sender, you must ensure that the sender origin has linked the account - for paying message delivery and dispatch fee. - -- `ThisChainWithMessages::maximal_pending_messages_at_outbound_lane`: you should return maximal - number of pending (undelivered) messages from this function. Returning small values would require - relayers to operate faster and could make message sending logic more complicated. On the other - hand, returning large values could lead to chain state growth. - -- `ThisChainWithMessages::estimate_delivery_confirmation_transaction`: you'll need to return - estimated size and dispatch weight of the delivery confirmation transaction (that happens on - this chain) from this function. - -- `ThisChainWithMessages::transaction_payment`: you'll need to return fee that the submitter - must pay for given transaction on this chain. Normally, you would use transaction payment pallet - for this. However, if your chain has non-zero fee multiplier set, this would mean that the - payment will be computed using current value of this multiplier. But since this transaction - will be submitted in the future, you may want to choose other value instead. Otherwise, - non-altruistic relayer may choose not to submit this transaction until number of transactions - will decrease. - -## `BridgedChainWithMessages` Trait - -This trait represents this chain from bridge point of view. Let's review every method of this trait: - -- `BridgedChainWithMessages::maximal_extrinsic_size`: you will need to return the maximal - extrinsic size of the target chain from this function. - -- `MessageBridge::message_weight_limits`: you'll need to return a range of - dispatch weights that the outbound message may take at the target chain. Please keep in mind that - our helpers assume that the message is an encoded call of the target chain. But we never decode - this call at the source chain. So you can't simply get dispatch weight from pre-dispatch - information. Instead there are two options to prepare this range: if you know which calls are to - be sent over your bridge, then you may just return weight ranges for these particular calls. - Otherwise, if you're going to accept all kinds of calls, you may just return range `[0; maximal - incoming message dispatch weight]`. If you choose the latter, then you shall remember that the - delivery transaction itself has some weight, so you can't accept messages with weight equal to - maximal weight of extrinsic at the target chain. In our test chains, we reject all messages that - have declared dispatch weight larger than 50% of the maximal bridged extrinsic weight. - -- `MessageBridge::estimate_delivery_transaction`: you will need to return estimated dispatch weight and - size of the delivery transaction that delivers a given message to the target chain. The transaction - weight must or must not include the weight of pay-dispatch-fee operation, depending on the value - of `include_pay_dispatch_fee_cost` argument. - -- `MessageBridge::transaction_payment`: you'll need to return fee that the submitter - must pay for given transaction on bridged chain. The best case is when you have the same conversion - formula on both chains - then you may just reuse the `ThisChainWithMessages::transaction_payment` - implementation. Otherwise, you'll need to hardcode this formula into your runtime. - -## Helpers for the Source Chain - -The helpers for the Source Chain reside in the `source` submodule of the -[`messages`](./src/messages.rs) module. The structs are: `FromThisChainMessagePayload`, -`FromBridgedChainMessagesDeliveryProof`, `FromThisChainMessageVerifier`. And the helper functions -are: `maximal_message_size`, `verify_chain_message`, `verify_messages_delivery_proof` and -`estimate_message_dispatch_and_delivery_fee`. - -`FromThisChainMessagePayload` is a message that the sender sends through our bridge. It is the -`bp_message_dispatch::MessagePayload`, where `call` field is encoded target chain call. So -at this chain we don't see internals of this call - we just know its size. - -`FromThisChainMessageVerifier` is an implementation of `bp_messages::LaneMessageVerifier`. It -has following checks in its `verify_message` method: - -1. it'll verify that the used outbound lane is enabled in our runtime; - -1. it'll reject messages if there are too many undelivered outbound messages at this lane. The - sender need to wait while relayers will do their work before sending the message again; - -1. it'll reject a message if it has the wrong dispatch origin declared. Like if the submitter is not - the root of this chain, but it tries to dispatch the message at the target chain using - `bp_message_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature - in the `bp_message_dispatch::CallOrigin::TargetAccount` origin; - -1. it'll reject a message if the delivery and dispatch fee that the submitter wants to pay is lesser - than the fee that is computed using the `estimate_message_dispatch_and_delivery_fee` function. - -`estimate_message_dispatch_and_delivery_fee` returns a minimal fee that the submitter needs to pay -for sending a given message. The fee includes: payment for the delivery transaction at the target -chain, payment for delivery confirmation transaction on this chain, payment for `Call` dispatch at -the target chain and relayer interest. - -`FromBridgedChainMessagesDeliveryProof` holds the lane identifier and the storage proof of this -inbound lane state at the bridged chain. This also holds the hash of the target chain header, that -was used to generate this storage proof. The proof is verified by the -`verify_messages_delivery_proof`, which simply checks that the target chain header is finalized -(using Substrate bridge module) and then reads the inbound lane state from the proof. - -`verify_chain_message` function checks that the message may be delivered to the bridged chain. There -are two main checks: - -1. that the message size is less than or equal to the `2/3` of maximal extrinsic size at the target - chain. We leave `1/3` for signed extras and for the storage proof overhead; - -1. that the message dispatch weight is less than or equal to the `1/2` of maximal normal extrinsic - weight at the target chain. We leave `1/2` for the delivery transaction overhead. - -## Helpers for the Target Chain - -The helpers for the target chain reside in the `target` submodule of the -[`messages`](./src/messages.rs) module. The structs are: `FromBridgedChainMessagePayload`, -`FromBridgedChainMessagesProof`, `FromBridgedChainMessagesProof`. And the helper functions are: -`maximal_incoming_message_dispatch_weight`, `maximal_incoming_message_size` and -`verify_messages_proof`. - -`FromBridgedChainMessagePayload` corresponds to the `FromThisChainMessagePayload` at the bridged -chain. We expect that messages with this payload are stored in the `OutboundMessages` storage map of -the [messages module](../../modules/messages/README.md). This map is used to build -`FromBridgedChainMessagesProof`. The proof holds the lane id, range of message nonces included in -the proof, storage proof of `OutboundMessages` entries and the hash of bridged chain header that has -been used to build the proof. Additionally, there's storage proof may contain the proof of outbound -lane state. It may be required to prune `relayers` entries at this chain (see -[messages module documentation](../../modules/messages/README.md#What-about-other-Constants-in-the-Messages-Module-Configuration-Trait) -for details). This proof is verified by the `verify_messages_proof` function. diff --git a/bin/runtime-common/src/integrity.rs b/bin/runtime-common/src/integrity.rs index ab517566a0..850c71181e 100644 --- a/bin/runtime-common/src/integrity.rs +++ b/bin/runtime-common/src/integrity.rs @@ -105,8 +105,7 @@ macro_rules! assert_bridge_messages_pallet_types( ( runtime: $r:path, with_bridged_chain_messages_instance: $i:path, - bridge: $bridge:path, - this_chain_account_id_converter: $this_converter:path + bridge: $bridge:path ) => { { // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard @@ -115,20 +114,18 @@ macro_rules! assert_bridge_messages_pallet_types( use $crate::messages::{ source::FromThisChainMessagePayload, target::FromBridgedChainMessagePayload, - AccountIdOf, BalanceOf, BridgedChain, ThisChain, WeightOf, + AccountIdOf, BalanceOf, BridgedChain, CallOf, ThisChain, WeightOf, }; use pallet_bridge_messages::Config as MessagesConfig; use static_assertions::assert_type_eq_all; - assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload<$bridge>); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload); assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundMessageFee, BalanceOf>); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, FromBridgedChainMessagePayload<$bridge>); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, FromBridgedChainMessagePayload>>); assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundMessageFee, BalanceOf>); assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundRelayer, AccountIdOf>); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::AccountIdConverter, $this_converter); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::TargetHeaderChain, BridgedChain<$bridge>); assert_type_eq_all!(<$r as MessagesConfig<$i>>::SourceHeaderChain, BridgedChain<$bridge>); } @@ -148,7 +145,6 @@ macro_rules! assert_complete_bridge_types( bridge: $bridge:path, this_chain: $this:path, bridged_chain: $bridged:path, - this_chain_account_id_converter: $this_converter:path ) => { $crate::assert_chain_types!(runtime: $r, this_chain: $this); $crate::assert_bridge_types!(bridge: $bridge, this_chain: $this, bridged_chain: $bridged); @@ -160,8 +156,7 @@ macro_rules! assert_complete_bridge_types( $crate::assert_bridge_messages_pallet_types!( runtime: $r, with_bridged_chain_messages_instance: $mi, - bridge: $bridge, - this_chain_account_id_converter: $this_converter + bridge: $bridge ); } ); diff --git a/bin/runtime-common/src/lib.rs b/bin/runtime-common/src/lib.rs index c7fb98aba7..a8f2434fc7 100644 --- a/bin/runtime-common/src/lib.rs +++ b/bin/runtime-common/src/lib.rs @@ -18,9 +18,201 @@ #![cfg_attr(not(feature = "std"), no_std)] +use bp_runtime::FilterCall; +use sp_runtime::transaction_validity::TransactionValidity; +use xcm::v3::NetworkId; + pub mod messages; pub mod messages_api; pub mod messages_benchmarking; +pub mod messages_extension; +pub mod parachains_benchmarking; #[cfg(feature = "integrity-test")] pub mod integrity; + +/// A duplication of the `FilterCall` trait. +/// +/// We need this trait in order to be able to implement it for the messages pallet, +/// since the implementation is done outside of the pallet crate. +pub trait BridgeRuntimeFilterCall { + /// Checks if a runtime call is valid. + fn validate(call: &Call) -> TransactionValidity; +} + +impl BridgeRuntimeFilterCall for pallet_bridge_grandpa::Pallet +where + pallet_bridge_grandpa::Pallet: FilterCall, +{ + fn validate(call: &Call) -> TransactionValidity { + as FilterCall>::validate(call) + } +} + +impl BridgeRuntimeFilterCall for pallet_bridge_parachains::Pallet +where + pallet_bridge_parachains::Pallet: FilterCall, +{ + fn validate(call: &Call) -> TransactionValidity { + as FilterCall>::validate(call) + } +} + +/// Declares a runtime-specific `BridgeRejectObsoleteHeadersAndMessages` signed extension. +/// +/// ## Example +/// +/// ```nocompile +/// generate_bridge_reject_obsolete_headers_and_messages!{ +/// Call, AccountId +/// BridgeRialtoGrandpa, BridgeWestendGrandpa, +/// BridgeRialtoParachains +/// } +/// ``` +/// +/// The goal of this extension is to avoid "mining" transactions that provide outdated bridged +/// headers and messages. Without that extension, even honest relayers may lose their funds if +/// there are multiple relays running and submitting the same information. +#[macro_export] +macro_rules! generate_bridge_reject_obsolete_headers_and_messages { + ($call:ty, $account_id:ty, $($filter_call:ty),*) => { + #[derive(Clone, codec::Decode, codec::Encode, Eq, PartialEq, frame_support::RuntimeDebug, scale_info::TypeInfo)] + pub struct BridgeRejectObsoleteHeadersAndMessages; + impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteHeadersAndMessages { + const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; + type AccountId = $account_id; + type Call = $call; + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed(&self) -> sp_std::result::Result< + (), + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } + + fn validate( + &self, + _who: &Self::AccountId, + call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> sp_runtime::transaction_validity::TransactionValidity { + let valid = sp_runtime::transaction_validity::ValidTransaction::default(); + $( + let valid = valid + .combine_with(<$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?); + )* + Ok(valid) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(drop) + } + } + }; +} + +/// A mapping over `NetworkId`. +/// Since `NetworkId` doesn't include `Millau`, `Rialto` and `RialtoParachain`, we create some +/// synthetic associations between these chains and `NetworkId` chains. +pub enum CustomNetworkId { + /// The Millau network ID, associated with Kusama. + Millau, + /// The Rialto network ID, associated with Polkadot. + Rialto, + /// The RialtoParachain network ID, associated with Westend. + RialtoParachain, +} + +impl CustomNetworkId { + pub const fn as_network_id(&self) -> NetworkId { + match *self { + CustomNetworkId::Millau => NetworkId::Kusama, + CustomNetworkId::Rialto => NetworkId::Polkadot, + CustomNetworkId::RialtoParachain => NetworkId::Westend, + } + } +} + +#[cfg(test)] +mod tests { + use crate::BridgeRuntimeFilterCall; + use frame_support::{assert_err, assert_ok}; + use sp_runtime::{ + traits::SignedExtension, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + }; + + pub struct MockCall { + data: u32, + } + + impl sp_runtime::traits::Dispatchable for MockCall { + type Origin = (); + type Config = (); + type Info = (); + type PostInfo = (); + + fn dispatch( + self, + _origin: Self::Origin, + ) -> sp_runtime::DispatchResultWithInfo { + unimplemented!() + } + } + + struct FirstFilterCall; + impl BridgeRuntimeFilterCall for FirstFilterCall { + fn validate(call: &MockCall) -> TransactionValidity { + if call.data <= 1 { + return InvalidTransaction::Custom(1).into() + } + + Ok(ValidTransaction { priority: 1, ..Default::default() }) + } + } + + struct SecondFilterCall; + impl BridgeRuntimeFilterCall for SecondFilterCall { + fn validate(call: &MockCall) -> TransactionValidity { + if call.data <= 2 { + return InvalidTransaction::Custom(2).into() + } + + Ok(ValidTransaction { priority: 2, ..Default::default() }) + } + } + + #[test] + fn test() { + generate_bridge_reject_obsolete_headers_and_messages!( + MockCall, + (), + FirstFilterCall, + SecondFilterCall + ); + + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 1 }, &(), 0), + InvalidTransaction::Custom(1) + ); + + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 2 }, &(), 0), + InvalidTransaction::Custom(2) + ); + + assert_ok!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 3 }, &(), 0), + ValidTransaction { priority: 3, ..Default::default() } + ) + } +} diff --git a/bin/runtime-common/src/messages.rs b/bin/runtime-common/src/messages.rs index 250b68ceff..a7ad19dc1f 100644 --- a/bin/runtime-common/src/messages.rs +++ b/bin/runtime-common/src/messages.rs @@ -20,33 +20,24 @@ //! pallet is used to dispatch incoming messages. Message identified by a tuple //! of to elements - message lane id and message nonce. -use bp_message_dispatch::MessageDispatch as _; use bp_messages::{ source_chain::LaneMessageVerifier, target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages}, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData, }; -use bp_runtime::{ - messages::{DispatchFeePayment, MessageDispatchResult}, - ChainId, Size, StorageProofChecker, -}; -use codec::{Decode, DecodeLimit, Encode}; -use frame_support::{ - traits::{Currency, ExistenceRequirement}, - weights::{Weight, WeightToFeePolynomial}, - RuntimeDebug, -}; +use bp_polkadot_core::parachains::{ParaHash, ParaHasher, ParaId}; +use bp_runtime::{messages::MessageDispatchResult, ChainId, Size, StorageProofChecker}; +use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; +use frame_support::{traits::Get, weights::Weight, RuntimeDebug}; use hash_db::Hasher; use scale_info::TypeInfo; use sp_runtime::{ - traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Saturating, Zero}, + traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Header as HeaderT}, FixedPointNumber, FixedPointOperand, FixedU128, }; -use sp_std::{ - cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive, - vec::Vec, -}; +use sp_std::{cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, vec::Vec}; use sp_trie::StorageProof; +use xcm::latest::prelude::*; /// Bidirectional message bridge. pub trait MessageBridge { @@ -79,7 +70,7 @@ pub trait ChainWithMessages { /// Hash used in the chain. type Hash: Decode; /// Accound id on the chain. - type AccountId: Encode + Decode; + type AccountId: Encode + Decode + MaxEncodedLen; /// Public key of the chain account that may be used to verify signatures. type Signer: Encode + Decode; /// Signature type used on the chain. @@ -109,12 +100,54 @@ pub struct MessageTransaction { pub size: u32, } +/// Helper trait for estimating the size and weight of a single message delivery confirmation +/// transaction. +pub trait ConfirmationTransactionEstimation { + // Estimate size and weight of single message delivery confirmation transaction. + fn estimate_delivery_confirmation_transaction() -> MessageTransaction; +} + +/// Default implementation for `ConfirmationTransactionEstimation`. +pub struct BasicConfirmationTransactionEstimation< + AccountId: MaxEncodedLen, + const MAX_CONFIRMATION_TX_WEIGHT: Weight, + const EXTRA_STORAGE_PROOF_SIZE: u32, + const TX_EXTRA_BYTES: u32, +>(PhantomData); + +impl< + AccountId: MaxEncodedLen, + const MAX_CONFIRMATION_TX_WEIGHT: Weight, + const EXTRA_STORAGE_PROOF_SIZE: u32, + const TX_EXTRA_BYTES: u32, + > ConfirmationTransactionEstimation + for BasicConfirmationTransactionEstimation< + AccountId, + MAX_CONFIRMATION_TX_WEIGHT, + EXTRA_STORAGE_PROOF_SIZE, + TX_EXTRA_BYTES, + > +{ + fn estimate_delivery_confirmation_transaction() -> MessageTransaction { + let inbound_data_size = InboundLaneData::::encoded_size_hint_u32(1, 1); + MessageTransaction { + dispatch_weight: MAX_CONFIRMATION_TX_WEIGHT, + size: inbound_data_size + .saturating_add(EXTRA_STORAGE_PROOF_SIZE) + .saturating_add(TX_EXTRA_BYTES), + } + } +} + /// This chain that has `pallet-bridge-messages` and `dispatch` modules. pub trait ThisChainWithMessages: ChainWithMessages { /// Call origin on the chain. type Origin; /// Call type on the chain. type Call: Encode + Decode; + /// Helper for estimating the size and weight of a single message delivery confirmation + /// transaction at this chain. + type ConfirmationTransactionEstimation: ConfirmationTransactionEstimation>; /// Do we accept message sent by given origin to given lane? fn is_message_accepted(origin: &Self::Origin, lane: &LaneId) -> bool; @@ -125,7 +158,9 @@ pub trait ThisChainWithMessages: ChainWithMessages { fn maximal_pending_messages_at_outbound_lane() -> MessageNonce; /// Estimate size and weight of single message delivery confirmation transaction at This chain. - fn estimate_delivery_confirmation_transaction() -> MessageTransaction>; + fn estimate_delivery_confirmation_transaction() -> MessageTransaction> { + Self::ConfirmationTransactionEstimation::estimate_delivery_confirmation_transaction() + } /// Returns minimal transaction fee that must be paid for given transaction at This chain. fn transaction_payment(transaction: MessageTransaction>) -> BalanceOf; @@ -136,16 +171,9 @@ pub trait BridgedChainWithMessages: ChainWithMessages { /// Maximal extrinsic size at Bridged chain. fn maximal_extrinsic_size() -> u32; - /// Returns feasible weights range for given message payload at the Bridged chain. - /// - /// If message is being sent with the weight that is out of this range, then it - /// should be rejected. - /// - /// Weights returned from this function shall not include transaction overhead - /// (like weight of signature and signed extensions verification), because they're - /// already accounted by the `weight_of_delivery_transaction`. So this function should - /// return pure call dispatch weights range. - fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive; + /// Returns `true` if message dispatch weight is withing expected limits. `false` means + /// that the message is too heavy to be sent over the bridge and shall be rejected. + fn verify_dispatch_weight(message_payload: &[u8]) -> bool; /// Estimate size and weight of single message delivery transaction at the Bridged chain. fn estimate_delivery_transaction( @@ -214,16 +242,17 @@ pub fn transaction_payment( pub mod source { use super::*; - /// Encoded Call of the Bridged chain. We never try to decode it on This chain. - pub type BridgedChainOpaqueCall = Vec; - /// Message payload for This -> Bridged chain messages. - pub type FromThisChainMessagePayload = bp_message_dispatch::MessagePayload< - AccountIdOf>, - SignerOf>, - SignatureOf>, - BridgedChainOpaqueCall, - >; + pub type FromThisChainMessagePayload = Vec; + + /// Maximal size of outbound message payload. + pub struct FromThisChainMaximalOutboundPayloadSize(PhantomData); + + impl Get for FromThisChainMaximalOutboundPayloadSize { + fn get() -> u32 { + maximal_message_size::() + } + } /// Messages delivery proof from bridged chain: /// @@ -241,7 +270,7 @@ pub mod source { } impl Size for FromBridgedChainMessagesDeliveryProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from( self.storage_proof .iter() @@ -260,7 +289,6 @@ pub mod source { /// This verifier assumes following: /// /// - all message lanes are equivalent, so all checks are the same; - /// - messages are being dispatched using `pallet-bridge-dispatch` pallet on the target chain. /// /// Following checks are made: /// @@ -288,7 +316,7 @@ pub mod source { LaneMessageVerifier< OriginOf>, AccountIdOf>, - FromThisChainMessagePayload, + FromThisChainMessagePayload, BalanceOf>, > for FromThisChainMessageVerifier where @@ -305,7 +333,7 @@ pub mod source { delivery_and_dispatch_fee: &BalanceOf>, lane: &LaneId, lane_outbound_data: &OutboundLaneData, - payload: &FromThisChainMessagePayload, + payload: &FromThisChainMessagePayload, ) -> Result<(), Self::Error> { // reject message if lane is blocked if !ThisChain::::is_message_accepted(submitter, lane) { @@ -321,26 +349,6 @@ pub mod source { return Err(TOO_MANY_PENDING_MESSAGES) } - // Do the dispatch-specific check. We assume that the target chain uses - // `Dispatch`, so we verify the message accordingly. - let raw_origin_or_err: Result< - frame_system::RawOrigin>>, - OriginOf>, - > = submitter.clone().into(); - match raw_origin_or_err { - Ok(raw_origin) => - pallet_bridge_dispatch::verify_message_origin(&raw_origin, payload) - .map(drop) - .map_err(|_| BAD_ORIGIN)?, - Err(_) => { - // so what it means that we've failed to convert origin to the - // `frame_system::RawOrigin`? now it means that the custom pallet origin has - // been used to send the message. Do we need to verify it? The answer is no, - // because pallet may craft any origin (e.g. root) && we can't verify whether it - // is valid, or not. - }, - }; - let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::( payload, B::RELAYER_FEE_PERCENT, @@ -367,10 +375,9 @@ pub mod source { /// may be 'mined' by the target chain. But the lane may have its own checks (e.g. fee /// check) that would reject message (see `FromThisChainMessageVerifier`). pub fn verify_chain_message( - payload: &FromThisChainMessagePayload, + payload: &FromThisChainMessagePayload, ) -> Result<(), &'static str> { - let weight_limits = BridgedChain::::message_weight_limits(&payload.call); - if !weight_limits.contains(&payload.weight.into()) { + if !BridgedChain::::verify_dispatch_weight(payload) { return Err("Incorrect message weight declared") } @@ -384,7 +391,7 @@ pub mod source { // is enormously large, it should be several dozens/hundreds of bytes. The delivery // transaction also contains signatures and signed extensions. Because of this, we reserve // 1/3 of the the maximal extrinsic weight for this data. - if payload.call.len() > maximal_message_size::() as usize { + if payload.len() > maximal_message_size::() as usize { return Err("The message is too large to be sent over the lane") } @@ -397,7 +404,7 @@ pub mod source { /// The fee is paid in This chain Balance, but we use Bridged chain balance to avoid additional /// conversions. Returns `None` if overflow has happened. pub fn estimate_message_dispatch_and_delivery_fee( - payload: &FromThisChainMessagePayload, + payload: &FromThisChainMessagePayload, relayer_fee_percent: u32, bridged_to_this_conversion_rate: Option, ) -> Result>, &'static str> { @@ -405,13 +412,8 @@ pub mod source { // // if we're going to pay dispatch fee at the target chain, then we don't include weight // of the message dispatch in the delivery transaction cost - let pay_dispatch_fee_at_target_chain = - payload.dispatch_fee_payment == DispatchFeePayment::AtTargetChain; - let delivery_transaction = BridgedChain::::estimate_delivery_transaction( - &payload.encode(), - pay_dispatch_fee_at_target_chain, - if pay_dispatch_fee_at_target_chain { 0.into() } else { payload.weight.into() }, - ); + let delivery_transaction = + BridgedChain::::estimate_delivery_transaction(&payload.encode(), true, 0.into()); let delivery_transaction_fee = BridgedChain::::transaction_payment(delivery_transaction); // the fee (in This tokens) of all transactions that are made on This chain @@ -440,6 +442,9 @@ pub mod source { } /// Verify proof of This -> Bridged chain messages delivery. + /// + /// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged + /// parachains, please use the `verify_messages_delivery_proof_from_parachain`. pub fn verify_messages_delivery_proof( proof: FromBridgedChainMessagesDeliveryProof>>, ) -> Result, &'static str> @@ -456,43 +461,211 @@ pub mod source { pallet_bridge_grandpa::Pallet::::parse_finalized_storage_proof( bridged_header_hash.into(), StorageProof::new(storage_proof), - |storage| { - // Messages delivery proof is just proof of single storage key read => any error - // is fatal. - let storage_inbound_lane_data_key = - bp_messages::storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane); - let raw_inbound_lane_data = storage - .read_value(storage_inbound_lane_data_key.0.as_ref()) - .map_err(|_| "Failed to read inbound lane state from storage proof")? - .ok_or("Inbound lane state is missing from the messages proof")?; - let inbound_lane_data = InboundLaneData::decode(&mut &raw_inbound_lane_data[..]) - .map_err(|_| "Failed to decode inbound lane state from the proof")?; - - Ok((lane, inbound_lane_data)) - }, + |storage| do_verify_messages_delivery_proof::< + B, + bp_runtime::HasherOf< + >::BridgedChain, + >, + >(lane, storage), + ) + .map_err(<&'static str>::from)? + } + + /// Verify proof of This -> Bridged chain messages delivery. + /// + /// This function is used when Bridged chain is using parachain finality. For Bridged + /// chains with direct GRANDPA finality, please use the `verify_messages_delivery_proof`. + /// + /// This function currently only supports parachains, which are using header type that + /// implements `sp_runtime::traits::Header` trait. + pub fn verify_messages_delivery_proof_from_parachain< + B, + BridgedHeader, + ThisRuntime, + ParachainsInstance: 'static, + >( + bridged_parachain: ParaId, + proof: FromBridgedChainMessagesDeliveryProof>>, + ) -> Result, &'static str> + where + B: MessageBridge, + B::BridgedChain: ChainWithMessages, + BridgedHeader: HeaderT>>, + ThisRuntime: pallet_bridge_parachains::Config, + { + let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = + proof; + pallet_bridge_parachains::Pallet::::parse_finalized_storage_proof( + bridged_parachain, + bridged_header_hash, + StorageProof::new(storage_proof), + |para_head| BridgedHeader::decode(&mut ¶_head.0[..]).ok().map(|h| *h.state_root()), + |storage| do_verify_messages_delivery_proof::(lane, storage), ) .map_err(<&'static str>::from)? } + + /// The essense of This -> Bridged chain messages delivery proof verification. + fn do_verify_messages_delivery_proof( + lane: LaneId, + storage: bp_runtime::StorageProofChecker, + ) -> Result, &'static str> { + // Messages delivery proof is just proof of single storage key read => any error + // is fatal. + let storage_inbound_lane_data_key = bp_messages::storage_keys::inbound_lane_data_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + &lane, + ); + let raw_inbound_lane_data = storage + .read_value(storage_inbound_lane_data_key.0.as_ref()) + .map_err(|_| "Failed to read inbound lane state from storage proof")? + .ok_or("Inbound lane state is missing from the messages proof")?; + let inbound_lane_data = InboundLaneData::decode(&mut &raw_inbound_lane_data[..]) + .map_err(|_| "Failed to decode inbound lane state from the proof")?; + + Ok((lane, inbound_lane_data)) + } + + /// XCM bridge. + pub trait XcmBridge { + /// Runtime message bridge configuration. + type MessageBridge: MessageBridge; + /// Runtime message sender adapter. + type MessageSender: bp_messages::source_chain::MessagesBridge< + OriginOf>, + AccountIdOf>, + BalanceOf>, + FromThisChainMessagePayload, + >; + + /// Our location within the Consensus Universe. + fn universal_location() -> InteriorMultiLocation; + /// Verify that the adapter is responsible for handling given XCM destination. + fn verify_destination(dest: &MultiLocation) -> bool; + /// Build route from this chain to the XCM destination. + fn build_destination() -> MultiLocation; + /// Return message lane used to deliver XCM messages. + fn xcm_lane() -> LaneId; + } + + /// XCM bridge adapter for `bridge-messages` pallet. + pub struct XcmBridgeAdapter(PhantomData); + + impl SendXcm for XcmBridgeAdapter + where + BalanceOf>: Into, + OriginOf>: From, + { + type Ticket = (BalanceOf>, FromThisChainMessagePayload); + + fn validate( + dest: &mut Option, + msg: &mut Option>, + ) -> SendResult { + let d = dest.take().ok_or(SendError::MissingArgument)?; + if !T::verify_destination(&d) { + *dest = Some(d); + return Err(SendError::NotApplicable) + } + + let route = T::build_destination(); + let msg = (route, msg.take().ok_or(SendError::MissingArgument)?).encode(); + + let fee = estimate_message_dispatch_and_delivery_fee::( + &msg, + T::MessageBridge::RELAYER_FEE_PERCENT, + None, + ); + let fee = match fee { + Ok(fee) => fee, + Err(e) => { + log::trace!( + target: "runtime::bridge", + "Failed to comupte fee for XCM message to {:?}: {:?}", + T::MessageBridge::BRIDGED_CHAIN_ID, + e, + ); + *dest = Some(d); + return Err(SendError::Transport(e)) + }, + }; + let fee_assets = MultiAssets::from((Here, fee)); + + Ok(((fee, msg), fee_assets)) + } + + fn deliver(ticket: Self::Ticket) -> Result { + use bp_messages::source_chain::MessagesBridge; + + let lane = T::xcm_lane(); + let (fee, msg) = ticket; + let result = T::MessageSender::send_message( + pallet_xcm::Origin::from(MultiLocation::from(T::universal_location())).into(), + lane, + msg, + fee, + ); + result + .map(|artifacts| { + let hash = (lane, artifacts.nonce).using_encoded(sp_io::hashing::blake2_256); + log::debug!( + target: "runtime::bridge", + "Sent XCM message {:?}/{} to {:?}: {:?}", + lane, + artifacts.nonce, + T::MessageBridge::BRIDGED_CHAIN_ID, + hash, + ); + hash + }) + .map_err(|e| { + log::debug!( + target: "runtime::bridge", + "Failed to send XCM message over lane {:?} to {:?}: {:?}", + lane, + T::MessageBridge::BRIDGED_CHAIN_ID, + e, + ); + SendError::Transport("Bridge has rejected the message") + }) + } + } } /// Sub-module that is declaring types required for processing Bridged -> This chain messages. pub mod target { use super::*; - /// Call origin for Bridged -> This chain messages. - pub type FromBridgedChainMessageCallOrigin = bp_message_dispatch::CallOrigin< - AccountIdOf>, - SignerOf>, - SignatureOf>, - >; - /// Decoded Bridged -> This message payload. - pub type FromBridgedChainMessagePayload = bp_message_dispatch::MessagePayload< - AccountIdOf>, - SignerOf>, - SignatureOf>, - FromBridgedChainEncodedMessageCall>>, - >; + #[derive(RuntimeDebug, PartialEq, Eq)] + pub struct FromBridgedChainMessagePayload { + /// Data that is actually sent over the wire. + pub xcm: (xcm::v3::MultiLocation, xcm::v3::Xcm), + /// Weight of the message, computed by the weigher. Unknown initially. + pub weight: Option, + } + + impl Decode for FromBridgedChainMessagePayload { + fn decode(input: &mut I) -> Result { + let _: codec::Compact = Decode::decode(input)?; + type XcmPairType = (xcm::v3::MultiLocation, xcm::v3::Xcm); + Ok(FromBridgedChainMessagePayload { + xcm: XcmPairType::::decode_with_depth_limit( + sp_api::MAX_EXTRINSIC_DEPTH, + input, + )?, + weight: None, + }) + } + } + + impl From<(xcm::v3::MultiLocation, xcm::v3::Xcm)> + for FromBridgedChainMessagePayload + { + fn from(xcm: (xcm::v3::MultiLocation, xcm::v3::Xcm)) -> Self { + FromBridgedChainMessagePayload { xcm, weight: None } + } + } /// Messages proof from bridged chain: /// @@ -506,6 +679,7 @@ pub mod target { pub bridged_header_hash: BridgedHeaderHash, /// A storage trie proof of messages being delivered. pub storage_proof: RawStorageProof, + /// Messages in this proof are sent over this lane. pub lane: LaneId, /// Nonce of the first message being delivered. pub nonces_start: MessageNonce, @@ -514,7 +688,7 @@ pub mod target { } impl Size for FromBridgedChainMessagesProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from( self.storage_proof .iter() @@ -524,101 +698,89 @@ pub mod target { } } - /// Encoded Call of This chain as it is transferred over bridge. - /// - /// Our Call is opaque (`Vec`) for Bridged chain. So it is encoded, prefixed with - /// vector length. Custom decode implementation here is exactly to deal with this. - #[derive(Decode, Encode, RuntimeDebug, PartialEq)] - pub struct FromBridgedChainEncodedMessageCall { - encoded_call: Vec, - _marker: PhantomData, - } - - impl FromBridgedChainEncodedMessageCall { - /// Create encoded call. - pub fn new(encoded_call: Vec) -> Self { - FromBridgedChainEncodedMessageCall { encoded_call, _marker: PhantomData::default() } - } - } - - impl From> - for Result - { - fn from(encoded_call: FromBridgedChainEncodedMessageCall) -> Self { - DecodedCall::decode_with_depth_limit( - sp_api::MAX_EXTRINSIC_DEPTH, - &mut &encoded_call.encoded_call[..], - ) - .map_err(drop) - } - } - /// Dispatching Bridged -> This chain messages. #[derive(RuntimeDebug, Clone, Copy)] - pub struct FromBridgedChainMessageDispatch { - _marker: PhantomData<(B, ThisRuntime, ThisCurrency, ThisDispatchInstance)>, + pub struct FromBridgedChainMessageDispatch { + _marker: PhantomData<(B, XcmExecutor, XcmWeigher, WeightCredit)>, } - impl + impl MessageDispatch>, BalanceOf>> - for FromBridgedChainMessageDispatch + for FromBridgedChainMessageDispatch where - BalanceOf>: Saturating + FixedPointOperand, - ThisDispatchInstance: 'static, - ThisRuntime: pallet_bridge_dispatch::Config< - ThisDispatchInstance, - BridgeMessageId = (LaneId, MessageNonce), - > + pallet_transaction_payment::Config, - ::OnChargeTransaction: - pallet_transaction_payment::OnChargeTransaction< - ThisRuntime, - Balance = BalanceOf>, - >, - ThisCurrency: Currency>, Balance = BalanceOf>>, - pallet_bridge_dispatch::Pallet: - bp_message_dispatch::MessageDispatch< - AccountIdOf>, - (LaneId, MessageNonce), - Message = FromBridgedChainMessagePayload, - >, + XcmExecutor: xcm::v3::ExecuteXcm>>, + XcmWeigher: xcm_executor::traits::WeightBounds>>, + WeightCredit: Get, { - type DispatchPayload = FromBridgedChainMessagePayload; + type DispatchPayload = FromBridgedChainMessagePayload>>; fn dispatch_weight( - message: &DispatchMessage>>, + message: &mut DispatchMessage>>, ) -> frame_support::weights::Weight { - message.data.payload.as_ref().map(|payload| payload.weight).unwrap_or(0) + match message.data.payload { + Ok(ref mut payload) => { + // I have no idea why this method takes `&mut` reference and there's nothing + // about that in documentation. Hope it'll only mutate iff error is returned. + let weight = XcmWeigher::weight(&mut payload.xcm.1); + let weight = weight.unwrap_or_else(|e| { + log::debug!( + target: "runtime::bridge-dispatch", + "Failed to compute dispatch weight of incoming XCM message {:?}/{}: {:?}", + message.key.lane_id, + message.key.nonce, + e, + ); + + // we shall return 0 and then the XCM executor will fail to execute XCM + // if we'll return something else (e.g. maximal value), the lane may stuck + 0 + }); + + payload.weight = Some(weight); + weight + }, + _ => 0, + } } fn dispatch( - relayer_account: &AccountIdOf>, + _relayer_account: &AccountIdOf>, message: DispatchMessage>>, ) -> MessageDispatchResult { let message_id = (message.key.lane_id, message.key.nonce); - pallet_bridge_dispatch::Pallet::::dispatch( - B::BRIDGED_CHAIN_ID, - B::THIS_CHAIN_ID, - message_id, - message.data.payload.map_err(drop), - |dispatch_origin, dispatch_weight| { - let unadjusted_weight_fee = ThisRuntime::WeightToFee::calc(&dispatch_weight); - let fee_multiplier = - pallet_transaction_payment::Pallet::::next_fee_multiplier(); - let adjusted_weight_fee = - fee_multiplier.saturating_mul_int(unadjusted_weight_fee); - if !adjusted_weight_fee.is_zero() { - ThisCurrency::transfer( - dispatch_origin, - relayer_account, - adjusted_weight_fee, - ExistenceRequirement::AllowDeath, - ) - .map_err(drop) - } else { - Ok(()) - } - }, - ) + let do_dispatch = move || -> sp_std::result::Result { + let FromBridgedChainMessagePayload { xcm: (location, xcm), weight: weight_limit } = + message.data.payload?; + log::trace!( + target: "runtime::bridge-dispatch", + "Going to execute message {:?} (weight limit: {:?}): {:?} {:?}", + message_id, + weight_limit, + location, + xcm, + ); + let hash = message_id.using_encoded(sp_io::hashing::blake2_256); + + // if this cod will end up in production, this most likely needs to be set to zero + let weight_credit = WeightCredit::get(); + + let xcm_outcome = XcmExecutor::execute_xcm_in_credit( + location, + xcm, + hash, + weight_limit.unwrap_or(0), + weight_credit, + ); + Ok(xcm_outcome) + }; + + let xcm_outcome = do_dispatch(); + log::trace!(target: "runtime::bridge-dispatch", "Incoming message {:?} dispatched with result: {:?}", message_id, xcm_outcome); + MessageDispatchResult { + dispatch_result: true, + unspent_weight: 0, + dispatch_fee_paid_during_dispatch: false, + } } } @@ -634,6 +796,9 @@ pub mod target { /// Verify proof of Bridged -> This chain messages. /// + /// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged + /// parachains, please use the `verify_messages_proof_from_parachain`. + /// /// The `messages_count` argument verification (sane limits) is supposed to be made /// outside of this function. This function only verifies that the proof declares exactly /// `messages_count` messages. @@ -668,7 +833,55 @@ pub mod target { .map_err(Into::into) } - #[derive(Debug, PartialEq)] + /// Verify proof of Bridged -> This chain messages. + /// + /// This function is used when Bridged chain is using parachain finality. For Bridged + /// chains with direct GRANDPA finality, please use the `verify_messages_proof`. + /// + /// The `messages_count` argument verification (sane limits) is supposed to be made + /// outside of this function. This function only verifies that the proof declares exactly + /// `messages_count` messages. + /// + /// This function currently only supports parachains, which are using header type that + /// implements `sp_runtime::traits::Header` trait. + pub fn verify_messages_proof_from_parachain< + B, + BridgedHeader, + ThisRuntime, + ParachainsInstance: 'static, + >( + bridged_parachain: ParaId, + proof: FromBridgedChainMessagesProof>>, + messages_count: u32, + ) -> Result>>>, &'static str> + where + B: MessageBridge, + B::BridgedChain: ChainWithMessages, + BridgedHeader: HeaderT>>, + ThisRuntime: pallet_bridge_parachains::Config, + { + verify_messages_proof_with_parser::( + proof, + messages_count, + |bridged_header_hash, bridged_storage_proof| { + pallet_bridge_parachains::Pallet::::parse_finalized_storage_proof( + bridged_parachain, + bridged_header_hash, + StorageProof::new(bridged_storage_proof), + |para_head| BridgedHeader::decode(&mut ¶_head.0[..]).ok().map(|h| *h.state_root()), + |storage_adapter| storage_adapter, + ) + .map(|storage| StorageProofCheckerAdapter::<_, B> { + storage, + _dummy: Default::default(), + }) + .map_err(|err| MessageProofError::Custom(err.into())) + }, + ) + .map_err(Into::into) + } + + #[derive(Debug, PartialEq, Eq)] pub(crate) enum MessageProofError { Empty, MessagesCountMismatch, @@ -795,7 +1008,7 @@ pub mod target { return Err(MessageProofError::Empty) } - // We only support single lane messages in this schema + // We only support single lane messages in this generated_schema let mut proved_messages = ProvedMessages::new(); proved_messages.insert(lane, proved_lane_messages); @@ -803,6 +1016,112 @@ pub mod target { } } +pub use xcm_copy::*; + +// copy of private types from xcm-builder/src/universal_exports.rs +pub mod xcm_copy { + use codec::{Decode, Encode}; + use frame_support::{ensure, traits::Get}; + use sp_std::{convert::TryInto, marker::PhantomData, prelude::*}; + use xcm::prelude::*; + use xcm_executor::traits::ExportXcm; + + pub trait DispatchBlob { + /// Dispatches an incoming blob and returns the unexpectable weight consumed by the + /// dispatch. + fn dispatch_blob(blob: Vec) -> Result<(), DispatchBlobError>; + } + + pub trait HaulBlob { + /// Sends a blob over some point-to-point link. This will generally be implemented by a + /// bridge. + fn haul_blob(blob: Vec); + } + + #[derive(Clone, Encode, Decode)] + pub struct BridgeMessage { + /// The message destination as a *Universal Location*. This means it begins with a + /// `GlobalConsensus` junction describing the network under which global consensus happens. + /// If this does not match our global consensus then it's a fatal error. + universal_dest: VersionedInteriorMultiLocation, + message: VersionedXcm<()>, + } + + pub enum DispatchBlobError { + Unbridgable, + InvalidEncoding, + UnsupportedLocationVersion, + UnsupportedXcmVersion, + RoutingError, + NonUniversalDestination, + WrongGlobal, + } + + pub struct BridgeBlobDispatcher(PhantomData<(Router, OurPlace)>); + impl> DispatchBlob + for BridgeBlobDispatcher + { + fn dispatch_blob(blob: Vec) -> Result<(), DispatchBlobError> { + let our_universal = OurPlace::get(); + let our_global = + our_universal.global_consensus().map_err(|()| DispatchBlobError::Unbridgable)?; + let BridgeMessage { universal_dest, message } = + Decode::decode(&mut &blob[..]).map_err(|_| DispatchBlobError::InvalidEncoding)?; + let universal_dest: InteriorMultiLocation = universal_dest + .try_into() + .map_err(|_| DispatchBlobError::UnsupportedLocationVersion)?; + // `universal_dest` is the desired destination within the universe: first we need to + // check we're in the right global consensus. + let intended_global = universal_dest + .global_consensus() + .map_err(|()| DispatchBlobError::NonUniversalDestination)?; + ensure!(intended_global == our_global, DispatchBlobError::WrongGlobal); + let dest = universal_dest.relative_to(&our_universal); + let message: Xcm<()> = + message.try_into().map_err(|_| DispatchBlobError::UnsupportedXcmVersion)?; + send_xcm::(dest, message).map_err(|_| DispatchBlobError::RoutingError)?; + Ok(()) + } + } + + pub struct HaulBlobExporter( + PhantomData<(Bridge, BridgedNetwork, Price)>, + ); + impl, Price: Get> ExportXcm + for HaulBlobExporter + { + type Ticket = (Vec, XcmHash); + + fn validate( + network: NetworkId, + _channel: u32, + destination: &mut Option, + message: &mut Option>, + ) -> Result<((Vec, XcmHash), MultiAssets), SendError> { + let bridged_network = BridgedNetwork::get(); + ensure!(network == bridged_network, SendError::NotApplicable); + // We don't/can't use the `channel` for this adapter. + let dest = destination.take().ok_or(SendError::MissingArgument)?; + let universal_dest = match dest.pushed_front_with(GlobalConsensus(bridged_network)) { + Ok(d) => d.into(), + Err((dest, _)) => { + *destination = Some(dest); + return Err(SendError::NotApplicable) + }, + }; + let message = VersionedXcm::from(message.take().ok_or(SendError::MissingArgument)?); + let hash = message.using_encoded(sp_io::hashing::blake2_256); + let blob = BridgeMessage { universal_dest, message }.encode(); + Ok(((blob, hash), Price::get())) + } + + fn deliver((blob, hash): (Vec, XcmHash)) -> Result { + Bridge::haul_blob(blob); + Ok(hash) + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -815,7 +1134,8 @@ mod tests { const THIS_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 2; const BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 4; const BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE: u32 = 6; - const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: Weight = 2048; + const BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT: usize = 5; + const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: usize = 2048; const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; /// Bridge that is deployed on ThisChain and allows sending/receiving messages to/from @@ -865,13 +1185,13 @@ mod tests { } } - #[derive(Debug, PartialEq, Decode, Encode, Clone)] + #[derive(Debug, PartialEq, Eq, Decode, Encode, Clone, MaxEncodedLen)] struct ThisChainAccountId(u32); - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode)] struct ThisChainSigner(u32); - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode)] struct ThisChainSignature(u32); - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode)] enum ThisChainCall { #[codec(index = 42)] Transfer, @@ -891,13 +1211,13 @@ mod tests { } } - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode, MaxEncodedLen)] struct BridgedChainAccountId(u32); - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode)] struct BridgedChainSigner(u32); - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode)] struct BridgedChainSignature(u32); - #[derive(Debug, PartialEq, Decode, Encode)] + #[derive(Debug, PartialEq, Eq, Decode, Encode)] enum BridgedChainCall {} #[derive(Clone, Debug)] struct BridgedChainOrigin; @@ -914,7 +1234,7 @@ mod tests { macro_rules! impl_wrapped_balance { ($name:ident) => { - #[derive(Debug, PartialEq, Decode, Encode, Clone, Copy)] + #[derive(Debug, PartialEq, Eq, Decode, Encode, Clone, Copy)] struct $name(u32); impl From for $name { @@ -990,6 +1310,12 @@ mod tests { impl ThisChainWithMessages for ThisChain { type Origin = ThisChainOrigin; type Call = ThisChainCall; + type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation< + ::AccountId, + { DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT }, + 0, + 0, + >; fn is_message_accepted(_send_origin: &Self::Origin, lane: &LaneId) -> bool { lane == TEST_LANE_ID @@ -999,13 +1325,6 @@ mod tests { MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE } - fn estimate_delivery_confirmation_transaction() -> MessageTransaction> { - MessageTransaction { - dispatch_weight: DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT, - size: 0, - } - } - fn transaction_payment(transaction: MessageTransaction>) -> BalanceOf { ThisChainBalance( transaction.dispatch_weight as u32 * THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u32, @@ -1018,7 +1337,7 @@ mod tests { unreachable!() } - fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive { + fn verify_dispatch_weight(_message_payload: &[u8]) -> bool { unreachable!() } @@ -1051,6 +1370,12 @@ mod tests { impl ThisChainWithMessages for BridgedChain { type Origin = BridgedChainOrigin; type Call = BridgedChainCall; + type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation< + ::AccountId, + 0, + 0, + 0, + >; fn is_message_accepted(_send_origin: &Self::Origin, _lane: &LaneId) -> bool { unreachable!() @@ -1060,10 +1385,6 @@ mod tests { unreachable!() } - fn estimate_delivery_confirmation_transaction() -> MessageTransaction> { - unreachable!() - } - fn transaction_payment( _transaction: MessageTransaction>, ) -> BalanceOf { @@ -1076,10 +1397,9 @@ mod tests { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } - fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive { - let begin = - std::cmp::min(BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, message_payload.len() as Weight); - begin..=BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + fn verify_dispatch_weight(message_payload: &[u8]) -> bool { + message_payload.len() >= BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT && + message_payload.len() <= BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT } fn estimate_delivery_transaction( @@ -1104,57 +1424,16 @@ mod tests { OutboundLaneData::default() } - #[test] - fn message_from_bridged_chain_is_decoded() { - // the message is encoded on the bridged chain - let message_on_bridged_chain = - source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: 100, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtTargetChain, - call: ThisChainCall::Transfer.encode(), - } - .encode(); - - // and sent to this chain where it is decoded - let message_on_this_chain = - target::FromBridgedChainMessagePayload::::decode( - &mut &message_on_bridged_chain[..], - ) - .unwrap(); - assert_eq!( - message_on_this_chain, - target::FromBridgedChainMessagePayload:: { - spec_version: 1, - weight: 100, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtTargetChain, - call: target::FromBridgedChainEncodedMessageCall::::new( - ThisChainCall::Transfer.encode(), - ), - } - ); - assert_eq!(Ok(ThisChainCall::Transfer), message_on_this_chain.call.into()); - } - const TEST_LANE_ID: &LaneId = b"test"; const MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE: MessageNonce = 32; - fn regular_outbound_message_payload() -> source::FromThisChainMessagePayload - { - source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: 100, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![42], - } + fn regular_outbound_message_payload() -> source::FromThisChainMessagePayload { + vec![42] } #[test] fn message_fee_is_checked_by_verifier() { - const EXPECTED_MINIMAL_FEE: u32 = 5500; + const EXPECTED_MINIMAL_FEE: u32 = 2860; // payload of the This -> Bridged chain message let payload = regular_outbound_message_payload(); @@ -1169,25 +1448,6 @@ mod tests { Ok(ThisChainBalance(EXPECTED_MINIMAL_FEE)), ); - // let's check if estimation is less than hardcoded, if dispatch is paid at target chain - let mut payload_with_pay_on_target = regular_outbound_message_payload(); - payload_with_pay_on_target.dispatch_fee_payment = DispatchFeePayment::AtTargetChain; - let fee_at_source = - source::estimate_message_dispatch_and_delivery_fee::( - &payload_with_pay_on_target, - OnThisChainBridge::RELAYER_FEE_PERCENT, - None, - ) - .expect( - "estimate_message_dispatch_and_delivery_fee failed for pay-at-target-chain message", - ); - assert!( - fee_at_source < EXPECTED_MINIMAL_FEE.into(), - "Computed fee {:?} without prepaid dispatch must be less than the fee with prepaid dispatch {}", - fee_at_source, - EXPECTED_MINIMAL_FEE, - ); - // and now check that the verifier checks the fee assert_eq!( source::FromThisChainMessageVerifier::::verify_message( @@ -1209,80 +1469,6 @@ mod tests { .is_ok(),); } - #[test] - fn should_disallow_root_calls_from_regular_accounts() { - // payload of the This -> Bridged chain message - let payload = source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: 100, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![42], - }; - - // and now check that the verifier checks the fee - assert_eq!( - source::FromThisChainMessageVerifier::::verify_message( - &ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(0)))), - &ThisChainBalance(1_000_000), - TEST_LANE_ID, - &test_lane_outbound_data(), - &payload, - ), - Err(source::BAD_ORIGIN) - ); - assert_eq!( - source::FromThisChainMessageVerifier::::verify_message( - &ThisChainOrigin(Ok(frame_system::RawOrigin::None)), - &ThisChainBalance(1_000_000), - TEST_LANE_ID, - &test_lane_outbound_data(), - &payload, - ), - Err(source::BAD_ORIGIN) - ); - assert!(source::FromThisChainMessageVerifier::::verify_message( - &ThisChainOrigin(Ok(frame_system::RawOrigin::Root)), - &ThisChainBalance(1_000_000), - TEST_LANE_ID, - &test_lane_outbound_data(), - &payload, - ) - .is_ok(),); - } - - #[test] - fn should_verify_source_and_target_origin_matching() { - // payload of the This -> Bridged chain message - let payload = source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: 100, - origin: bp_message_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)), - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![42], - }; - - // and now check that the verifier checks the fee - assert_eq!( - source::FromThisChainMessageVerifier::::verify_message( - &ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(0)))), - &ThisChainBalance(1_000_000), - TEST_LANE_ID, - &test_lane_outbound_data(), - &payload, - ), - Err(source::BAD_ORIGIN) - ); - assert!(source::FromThisChainMessageVerifier::::verify_message( - &ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(1)))), - &ThisChainBalance(1_000_000), - TEST_LANE_ID, - &test_lane_outbound_data(), - &payload, - ) - .is_ok(),); - } - #[test] fn message_is_rejected_when_sent_using_disabled_lane() { assert_eq!( @@ -1317,58 +1503,42 @@ mod tests { #[test] fn verify_chain_message_rejects_message_with_too_small_declared_weight() { - assert!(source::verify_chain_message::( - &source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: 5, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![1, 2, 3, 4, 5, 6], - }, - ) + assert!(source::verify_chain_message::(&vec![ + 42; + BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT - + 1 + ]) .is_err()); } #[test] fn verify_chain_message_rejects_message_with_too_large_declared_weight() { - assert!(source::verify_chain_message::( - &source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + 1, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![1, 2, 3, 4, 5, 6], - }, - ) + assert!(source::verify_chain_message::(&vec![ + 42; + BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT - + 1 + ]) .is_err()); } #[test] fn verify_chain_message_rejects_message_too_large_message() { - assert!(source::verify_chain_message::( - &source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![0; source::maximal_message_size::() as usize + 1], - }, - ) + assert!(source::verify_chain_message::(&vec![ + 0; + source::maximal_message_size::() + as usize + 1 + ],) .is_err()); } #[test] fn verify_chain_message_accepts_maximal_message() { assert_eq!( - source::verify_chain_message::( - &source::FromThisChainMessagePayload:: { - spec_version: 1, - weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, - origin: bp_message_dispatch::CallOrigin::SourceRoot, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: vec![0; source::maximal_message_size::() as _], - }, - ), + source::verify_chain_message::(&vec![ + 0; + source::maximal_message_size::() + as _ + ],), Ok(()), ); } diff --git a/bin/runtime-common/src/messages_api.rs b/bin/runtime-common/src/messages_api.rs index b09a88e627..68465fa16e 100644 --- a/bin/runtime-common/src/messages_api.rs +++ b/bin/runtime-common/src/messages_api.rs @@ -16,36 +16,54 @@ //! Helpers for implementing various message-related runtime API mthods. -use crate::messages::{source::FromThisChainMessagePayload, MessageBridge}; - -use bp_messages::{LaneId, MessageDetails, MessageNonce}; -use codec::Decode; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; use sp_std::vec::Vec; /// Implementation of the `To*OutboundLaneApi::message_details`. -pub fn outbound_message_details( +pub fn outbound_message_details( lane: LaneId, begin: MessageNonce, end: MessageNonce, -) -> Vec> +) -> Vec> where Runtime: pallet_bridge_messages::Config, MessagesPalletInstance: 'static, - BridgeConfig: MessageBridge, { (begin..=end) .filter_map(|nonce| { let message_data = pallet_bridge_messages::Pallet::::outbound_message_data(lane, nonce)?; - let decoded_payload = - FromThisChainMessagePayload::::decode(&mut &message_data.payload[..]).ok()?; - Some(MessageDetails { + Some(OutboundMessageDetails { nonce, - dispatch_weight: decoded_payload.weight, + // dispatch message weight is always zero at the source chain, since we're paying for + // dispatch at the target chain + dispatch_weight: 0, size: message_data.payload.len() as _, delivery_and_dispatch_fee: message_data.fee, - dispatch_fee_payment: decoded_payload.dispatch_fee_payment, + // we're delivering XCM messages here, so fee is always paid at the target chain + dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtTargetChain, }) }) .collect() } + +/// Implementation of the `To*InboundLaneApi::message_details`. +pub fn inbound_message_details( + lane: LaneId, + messages: Vec<(MessagePayload, OutboundMessageDetails)>, +) -> Vec +where + Runtime: pallet_bridge_messages::Config, + MessagesPalletInstance: 'static, +{ + messages + .into_iter() + .map(|(payload, details)| { + pallet_bridge_messages::Pallet::::inbound_message_data( + lane, payload, details, + ) + }) + .collect() +} diff --git a/bin/runtime-common/src/messages_benchmarking.rs b/bin/runtime-common/src/messages_benchmarking.rs index 7c9f50e8ea..68f58d76b8 100644 --- a/bin/runtime-common/src/messages_benchmarking.rs +++ b/bin/runtime-common/src/messages_benchmarking.rs @@ -27,63 +27,26 @@ use crate::messages::{ }; use bp_messages::{storage_keys, MessageData, MessageKey, MessagePayload}; -use bp_runtime::{messages::DispatchFeePayment, ChainId}; +use bp_runtime::{record_all_trie_keys, StorageProofSize}; use codec::Encode; -use ed25519_dalek::{PublicKey, SecretKey, Signer, KEYPAIR_LENGTH, SECRET_KEY_LENGTH}; -use frame_support::{ - traits::Currency, - weights::{GetDispatchInfo, Weight}, -}; +use frame_support::weights::{GetDispatchInfo, Weight}; use pallet_bridge_messages::benchmarking::{ - MessageDeliveryProofParams, MessageParams, MessageProofParams, ProofSize, + MessageDeliveryProofParams, MessageParams, MessageProofParams, }; use sp_core::Hasher; use sp_runtime::traits::{Header, IdentifyAccount, MaybeSerializeDeserialize, Zero}; use sp_std::{fmt::Debug, prelude::*}; -use sp_trie::{record_all_keys, trie_types::TrieDBMutV1, LayoutV1, MemoryDB, Recorder, TrieMut}; -use sp_version::RuntimeVersion; - -/// Return this chain account, used to dispatch message. -pub fn dispatch_account() -> AccountIdOf> -where - B: MessageBridge, - SignerOf>: - From + IdentifyAccount>>, -{ - let this_raw_public = PublicKey::from(&dispatch_account_secret()); - let this_public: SignerOf> = - sp_core::ed25519::Public::from_raw(this_raw_public.to_bytes()).into(); - this_public.into_account() -} - -/// Return public key of this chain account, used to dispatch message. -pub fn dispatch_account_secret() -> SecretKey { - // key from the repo example (https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.SecretKey.html) - SecretKey::from_bytes(&[ - 157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073, - 197, 105, 123, 050, 105, 025, 112, 059, 172, 003, 028, 174, 127, 096, - ]) - .expect("harcoded key is valid") -} +use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut}; /// Prepare outbound message for the `send_message` call. pub fn prepare_outbound_message( params: MessageParams>>, -) -> FromThisChainMessagePayload +) -> FromThisChainMessagePayload where B: MessageBridge, BalanceOf>: From, { - let message_payload = vec![0; params.size as usize]; - let dispatch_origin = bp_message_dispatch::CallOrigin::SourceAccount(params.sender_account); - - FromThisChainMessagePayload:: { - spec_version: 0, - weight: params.size as _, - origin: dispatch_origin, - call: message_payload, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - } + vec![0; params.size as usize] } /// Prepare proof of messages for the `receive_messages_proof` call. @@ -92,14 +55,12 @@ where /// proof. pub fn prepare_message_proof( params: MessageProofParams, - version: &RuntimeVersion, - endow_amount: BalanceOf>, ) -> (FromBridgedChainMessagesProof>>, Weight) where R: frame_system::Config>> + pallet_balances::Config>> + pallet_bridge_grandpa::Config, - R::BridgedChain: bp_runtime::Chain
, + R::BridgedChain: bp_runtime::Chain>, Header = BH>, B: MessageBridge, BI: 'static, FI: 'static, @@ -115,56 +76,15 @@ where + From + IdentifyAccount>>, { - // we'll be dispatching the same call at This chain - let remark = match params.size { - ProofSize::Minimal(ref size) => vec![0u8; *size as _], + let message_payload = match params.size { + StorageProofSize::Minimal(ref size) => vec![0u8; *size as _], _ => vec![], }; - let call: CallOf> = frame_system::Call::remark { remark }.into(); - let call_weight = call.get_dispatch_info().weight; - - // message payload needs to be signed, because we use `TargetAccount` call origin - // (which is 'heaviest' to verify) - let bridged_account_id: AccountIdOf> = [0u8; 32].into(); - let (this_raw_public, this_raw_signature) = ed25519_sign( - &call, - &bridged_account_id, - version.spec_version, - B::BRIDGED_CHAIN_ID, - B::THIS_CHAIN_ID, - ); - let this_public: SignerOf> = - sp_core::ed25519::Public::from_raw(this_raw_public).into(); - let this_signature: SignatureOf> = - sp_core::ed25519::Signature::from_raw(this_raw_signature).into(); - - // if dispatch fee is paid at this chain, endow relayer account - if params.dispatch_fee_payment == DispatchFeePayment::AtTargetChain { - assert_eq!(this_public.clone().into_account(), dispatch_account::()); - pallet_balances::Pallet::::make_free_balance_be( - &this_public.clone().into_account(), - endow_amount, - ); - } - - // prepare message payload that is stored in the Bridged chain storage - let message_payload = bp_message_dispatch::MessagePayload { - spec_version: version.spec_version, - weight: call_weight, - origin: bp_message_dispatch::CallOrigin::< - AccountIdOf>, - SignerOf>, - SignatureOf>, - >::TargetAccount(bridged_account_id, this_public, this_signature), - dispatch_fee_payment: params.dispatch_fee_payment.clone(), - call: call.encode(), - } - .encode(); // finally - prepare storage proof and update environment let (state_root, storage_proof) = prepare_messages_storage_proof::(¶ms, message_payload); - let bridged_header_hash = insert_bridged_chain_header::(state_root); + let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); ( FromBridgedChainMessagesProof { @@ -174,11 +94,7 @@ where nonces_start: *params.message_nonces.start(), nonces_end: *params.message_nonces.end(), }, - call_weight - .checked_mul( - params.message_nonces.end().saturating_sub(*params.message_nonces.start()) + 1, - ) - .expect("too many messages requested by benchmark"), + 0, ) } @@ -188,7 +104,7 @@ pub fn prepare_message_delivery_proof( ) -> FromBridgedChainMessagesDeliveryProof>> where R: pallet_bridge_grandpa::Config, - R::BridgedChain: bp_runtime::Chain
, + R::BridgedChain: bp_runtime::Chain>, Header = BH>, FI: 'static, B: MessageBridge, BH: Header>>, @@ -201,7 +117,7 @@ where let mut root = Default::default(); let mut mdb = MemoryDB::default(); { - let mut trie = TrieDBMutV1::::new(&mut mdb, &mut root); + let mut trie = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); trie.insert(&storage_key, ¶ms.inbound_lane_data.encode()) .map_err(|_| "TrieMut::insert has failed") .expect("TrieMut::insert should not fail in benchmarks"); @@ -209,14 +125,14 @@ where root = grow_trie(root, &mut mdb, params.size); // generate storage proof to be delivered to This chain - let mut proof_recorder = Recorder::::new(); - record_all_keys::, _>(&mdb, &root, &mut proof_recorder) - .map_err(|_| "record_all_keys has failed") - .expect("record_all_keys should not fail in benchmarks"); + let mut proof_recorder = Recorder::>::new(); + record_all_trie_keys::, _>(&mdb, &root, &mut proof_recorder) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); // finally insert header with given state root to our storage - let bridged_header_hash = insert_bridged_chain_header::(root); + let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(root); FromBridgedChainMessagesDeliveryProof { bridged_header_hash: bridged_header_hash.into(), @@ -244,7 +160,7 @@ where let mut root = Default::default(); let mut mdb = MemoryDB::default(); { - let mut trie = TrieDBMutV1::::new(&mut mdb, &mut root); + let mut trie = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); // insert messages for nonce in params.message_nonces.clone() { @@ -279,96 +195,62 @@ where root = grow_trie(root, &mut mdb, params.size); // generate storage proof to be delivered to This chain - let mut proof_recorder = Recorder::::new(); - record_all_keys::, _>(&mdb, &root, &mut proof_recorder) - .map_err(|_| "record_all_keys has failed") - .expect("record_all_keys should not fail in benchmarks"); + let mut proof_recorder = Recorder::>::new(); + record_all_trie_keys::, _>(&mdb, &root, &mut proof_recorder) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); (root, storage_proof) } -/// Insert Bridged chain header with given state root into storage of GRANDPA pallet at This chain. -fn insert_bridged_chain_header( - state_root: HashOf>, -) -> HashOf> +/// Insert header to the bridge GRANDPA pallet. +pub(crate) fn insert_header_to_grandpa_pallet( + state_root: bp_runtime::HashOf, +) -> (bp_runtime::BlockNumberOf, bp_runtime::HashOf) where - R: pallet_bridge_grandpa::Config, - R::BridgedChain: bp_runtime::Chain
, - FI: 'static, - B: MessageBridge, - BH: Header>>, - HashOf>: Default, + R: pallet_bridge_grandpa::Config, + GI: 'static, + R::BridgedChain: bp_runtime::Chain, { - let bridged_header = BH::new( - Zero::zero(), + let bridged_block_number = Zero::zero(); + let bridged_header = bp_runtime::HeaderOf::::new( + bridged_block_number, Default::default(), state_root, Default::default(), Default::default(), ); let bridged_header_hash = bridged_header.hash(); - pallet_bridge_grandpa::initialize_for_benchmarks::(bridged_header); - bridged_header_hash -} - -/// Generate ed25519 signature to be used in -/// `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`. -/// -/// Returns public key of the signer and the signature itself. -fn ed25519_sign( - target_call: &impl Encode, - source_account_id: &impl Encode, - target_spec_version: u32, - source_chain_id: ChainId, - target_chain_id: ChainId, -) -> ([u8; 32], [u8; 64]) { - let target_secret = dispatch_account_secret(); - let target_public: PublicKey = (&target_secret).into(); - - let mut target_pair_bytes = [0u8; KEYPAIR_LENGTH]; - target_pair_bytes[..SECRET_KEY_LENGTH].copy_from_slice(&target_secret.to_bytes()); - target_pair_bytes[SECRET_KEY_LENGTH..].copy_from_slice(&target_public.to_bytes()); - let target_pair = - ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid"); - - let signature_message = pallet_bridge_dispatch::account_ownership_digest( - target_call, - source_account_id, - target_spec_version, - source_chain_id, - target_chain_id, - ); - let target_origin_signature = target_pair - .try_sign(&signature_message) - .expect("Ed25519 try_sign should not fail in benchmarks"); - - (target_public.to_bytes(), target_origin_signature.to_bytes()) + pallet_bridge_grandpa::initialize_for_benchmarks::(bridged_header); + (bridged_block_number, bridged_header_hash) } /// Populate trie with dummy keys+values until trie has at least given size. -fn grow_trie(mut root: H::Out, mdb: &mut MemoryDB, trie_size: ProofSize) -> H::Out { +pub fn grow_trie( + mut root: H::Out, + mdb: &mut MemoryDB, + trie_size: StorageProofSize, +) -> H::Out { let (iterations, leaf_size, minimal_trie_size) = match trie_size { - ProofSize::Minimal(_) => return root, - ProofSize::HasLargeLeaf(size) => (1, size, size), - ProofSize::HasExtraNodes(size) => (8, 1, size), + StorageProofSize::Minimal(_) => return root, + StorageProofSize::HasLargeLeaf(size) => (1, size, size), + StorageProofSize::HasExtraNodes(size) => (8, 1, size), }; let mut key_index = 0; loop { // generate storage proof to be delivered to This chain - let mut proof_recorder = Recorder::::new(); - record_all_keys::, _>(mdb, &root, &mut proof_recorder) - .map_err(|_| "record_all_keys has failed") - .expect("record_all_keys should not fail in benchmarks"); + let mut proof_recorder = Recorder::>::new(); + record_all_trie_keys::, _>(mdb, &root, &mut proof_recorder) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); let size: usize = proof_recorder.drain().into_iter().map(|n| n.data.len()).sum(); if size > minimal_trie_size as _ { return root } - let mut trie = TrieDBMutV1::::from_existing(mdb, &mut root) - .map_err(|_| "TrieDBMutV1::from_existing has failed") - .expect("TrieDBMutV1::from_existing should not fail in benchmarks"); + let mut trie = TrieDBMutBuilderV1::::from_existing(mdb, &mut root).build(); for _ in 0..iterations { trie.insert(&key_index.encode(), &vec![42u8; leaf_size as _]) .map_err(|_| "TrieMut::insert has failed") diff --git a/bin/runtime-common/src/messages_extension.rs b/bin/runtime-common/src/messages_extension.rs new file mode 100644 index 0000000000..bcaadd60ca --- /dev/null +++ b/bin/runtime-common/src/messages_extension.rs @@ -0,0 +1,232 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use crate::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + }, + BridgeRuntimeFilterCall, +}; +use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; +use pallet_bridge_messages::{Config, Pallet}; +use sp_runtime::transaction_validity::TransactionValidity; + +/// Validate messages in order to avoid "mining" messages delivery and delivery confirmation +/// transactions, that are delivering outdated messages/confirmations. Without this validation, +/// even honest relayers may lose their funds if there are multiple relays running and submitting +/// the same messages/confirmations. +impl< + BridgedHeaderHash, + SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain< + >::InboundMessageFee, + MessagesProof = FromBridgedChainMessagesProof, + >, + TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain< + >::OutboundPayload, + ::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof, + >, + Call: IsSubType, T>>, + T: frame_system::Config + + Config, + I: 'static, + > BridgeRuntimeFilterCall for Pallet +{ + fn validate(call: &Call) -> TransactionValidity { + match call.is_sub_type() { + Some(pallet_bridge_messages::Call::::receive_messages_proof { + ref proof, + .. + }) => { + let inbound_lane_data = + pallet_bridge_messages::InboundLanes::::get(proof.lane); + if proof.nonces_end <= inbound_lane_data.last_delivered_nonce() { + log::trace!( + target: pallet_bridge_messages::LOG_TARGET, + "Rejecting obsolete messages delivery transaction: \ + lane {:?}, bundled {:?}, best {:?}", + proof.lane, + proof.nonces_end, + inbound_lane_data.last_delivered_nonce(), + ); + + return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() + } + }, + Some(pallet_bridge_messages::Call::::receive_messages_delivery_proof { + ref proof, + ref relayers_state, + .. + }) => { + let latest_delivered_nonce = relayers_state.last_delivered_nonce; + + let outbound_lane_data = + pallet_bridge_messages::OutboundLanes::::get(proof.lane); + if latest_delivered_nonce <= outbound_lane_data.latest_received_nonce { + log::trace!( + target: pallet_bridge_messages::LOG_TARGET, + "Rejecting obsolete messages confirmation transaction: \ + lane {:?}, bundled {:?}, best {:?}", + proof.lane, + latest_delivered_nonce, + outbound_lane_data.latest_received_nonce, + ); + + return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() + } + }, + _ => {}, + } + + Ok(sp_runtime::transaction_validity::ValidTransaction::default()) + } +} + +#[cfg(test)] +mod tests { + use bp_messages::UnrewardedRelayersState; + use millau_runtime::{ + bridge_runtime_common::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, + target::FromBridgedChainMessagesProof, + }, + BridgeRuntimeFilterCall, + }, + Call, Runtime, WithRialtoMessagesInstance, + }; + + fn deliver_message_10() { + pallet_bridge_messages::InboundLanes::::insert( + [0, 0, 0, 0], + bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 }, + ); + } + + fn validate_message_delivery( + nonces_start: bp_messages::MessageNonce, + nonces_end: bp_messages::MessageNonce, + ) -> bool { + pallet_bridge_messages::Pallet::::validate( + &Call::BridgeRialtoMessages( + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: [0u8; 32].into(), + messages_count: (nonces_end - nonces_start + 1) as u32, + dispatch_weight: 0, + proof: FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: vec![], + lane: [0, 0, 0, 0], + nonces_start, + nonces_end, + }, + }, + ), + ) + .is_ok() + } + + #[test] + fn extension_rejects_obsolete_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver message#5 => tx + // is rejected + deliver_message_10(); + assert!(!validate_message_delivery(8, 9)); + }); + } + + #[test] + fn extension_rejects_same_message() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to import message#10 => tx + // is rejected + deliver_message_10(); + assert!(!validate_message_delivery(8, 10)); + }); + } + + #[test] + fn extension_accepts_new_message() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver message#15 => + // tx is accepted + deliver_message_10(); + assert!(validate_message_delivery(10, 15)); + }); + } + + fn confirm_message_10() { + pallet_bridge_messages::OutboundLanes::::insert( + [0, 0, 0, 0], + bp_messages::OutboundLaneData { + oldest_unpruned_nonce: 0, + latest_received_nonce: 10, + latest_generated_nonce: 10, + }, + ); + } + + fn validate_message_confirmation(last_delivered_nonce: bp_messages::MessageNonce) -> bool { + pallet_bridge_messages::Pallet::::validate( + &Call::BridgeRialtoMessages(pallet_bridge_messages::Call::< + Runtime, + WithRialtoMessagesInstance, + >::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: Vec::new(), + lane: [0, 0, 0, 0], + }, + relayers_state: UnrewardedRelayersState { + last_delivered_nonce, + ..Default::default() + }, + }), + ) + .is_ok() + } + + #[test] + fn extension_rejects_obsolete_confirmations() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best confirmed is message#10 and we're trying to confirm message#5 => tx + // is rejected + confirm_message_10(); + assert!(!validate_message_confirmation(5)); + }); + } + + #[test] + fn extension_rejects_same_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best confirmed is message#10 and we're trying to confirm message#10 => + // tx is rejected + confirm_message_10(); + assert!(!validate_message_confirmation(10)); + }); + } + + #[test] + fn extension_accepts_new_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best confirmed is message#10 and we're trying to confirm message#15 => + // tx is accepted + confirm_message_10(); + assert!(validate_message_confirmation(15)); + }); + } +} diff --git a/bin/runtime-common/src/parachains_benchmarking.rs b/bin/runtime-common/src/parachains_benchmarking.rs new file mode 100644 index 0000000000..59e2ef6962 --- /dev/null +++ b/bin/runtime-common/src/parachains_benchmarking.rs @@ -0,0 +1,83 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Everything required to run benchmarks of parachains finality module. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::messages_benchmarking::{grow_trie, insert_header_to_grandpa_pallet}; + +use bp_parachains::parachain_head_storage_key_at_source; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use bp_runtime::{record_all_trie_keys, StorageProofSize}; +use codec::Encode; +use frame_support::traits::Get; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use sp_std::prelude::*; +use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut}; + +/// Prepare proof of messages for the `receive_messages_proof` call. +/// +/// In addition to returning valid messages proof, environment is prepared to verify this message +/// proof. +pub fn prepare_parachain_heads_proof( + parachains: &[ParaId], + parachain_head_size: u32, + size: StorageProofSize, +) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) +where + R: pallet_bridge_parachains::Config + + pallet_bridge_grandpa::Config, + PI: 'static, + >::BridgedChain: + bp_runtime::Chain, +{ + let parachain_head = ParaHead(vec![0u8; parachain_head_size as usize]); + + // insert all heads to the trie + let mut parachain_heads = Vec::with_capacity(parachains.len()); + let mut storage_keys = Vec::with_capacity(parachains.len()); + let mut state_root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = + TrieDBMutBuilderV1::::new(&mut mdb, &mut state_root).build(); + + // insert parachain heads + for parachain in parachains { + let storage_key = + parachain_head_storage_key_at_source(R::ParasPalletName::get(), *parachain); + trie.insert(&storage_key.0, ¶chain_head.encode()) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + parachain_heads.push((*parachain, parachain_head.hash())) + } + } + state_root = grow_trie(state_root, &mut mdb, size); + + // generate heads storage proof + let mut proof_recorder = Recorder::>::new(); + record_all_trie_keys::, _>(&mdb, &state_root, &mut proof_recorder) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); + let proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); + + let (relay_block_number, relay_block_hash) = + insert_header_to_grandpa_pallet::(state_root); + + (relay_block_number, relay_block_hash, ParaHeadsProof(proof), parachain_heads) +} diff --git a/deployments/BridgeDeps.Dockerfile b/deployments/BridgeDeps.Dockerfile deleted file mode 100644 index 6d3b3fa170..0000000000 --- a/deployments/BridgeDeps.Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -# Image with dependencies required to build projects from the bridge repo. -# -# This image is meant to be used as a building block when building images for -# the various components in the bridge repo, such as nodes and relayers. -FROM docker.io/library/ubuntu:20.04 - -ENV LAST_DEPS_UPDATE 2021-04-01 -ENV DEBIAN_FRONTEND=noninteractive - -RUN set -eux; \ - apt-get update && \ - apt-get install -y curl ca-certificates && \ - apt-get install -y cmake pkg-config libssl-dev git clang libclang-dev - -ENV LAST_CERTS_UPDATE 2021-04-01 - -RUN update-ca-certificates && \ - curl https://sh.rustup.rs -sSf | sh -s -- -y - -ENV PATH="/root/.cargo/bin:${PATH}" -ENV LAST_RUST_UPDATE 2021-04-01 - -RUN rustup update stable && \ - rustup install nightly && \ - rustup target add wasm32-unknown-unknown --toolchain nightly - -RUN rustc -vV && \ - cargo -V && \ - gcc -v && \ - cmake --version - -ENV RUST_BACKTRACE 1 diff --git a/deployments/README.md b/deployments/README.md index 920935d5fd..2f804b3ad3 100644 --- a/deployments/README.md +++ b/deployments/README.md @@ -43,14 +43,15 @@ and Grafana. We cover these in more details in the [Monitoring](#monitoring) sec the monitoring Compose file is _not_ optional, and must be included for bridge deployments. ### Running and Updating Deployments -We currently support two bridge deployments +We currently support three bridge deployments 1. Rialto Substrate to Millau Substrate +2. Rialto Parachain Substrate to Millau Substrate 2. Westend Substrate to Millau Substrate These bridges can be deployed using our [`./run.sh`](./run.sh) script. -The first argument it takes is the name of the bridge you want to run. Right now we only support two -bridges: `rialto-millau` and `westend-millau`. +The first argument it takes is the name of the bridge you want to run. Right now we only support three +bridges: `rialto-millau`, `rialto-parachain-millau` and `westend-millau`. ```bash ./run.sh rialto-millau @@ -81,11 +82,15 @@ not strictly required. Rialto authorities are named: `Alice`, `Bob`, `Charlie`, `Dave`, `Eve`. Millau authorities are named: `Alice`, `Bob`, `Charlie`, `Dave`, `Eve`. +RialtoParachain authorities are named: `Alice`, `Bob`. + +`Sudo` is a sudo account on all chains. Both authorities and following accounts have enough funds (for test purposes) on corresponding Substrate chains: -- on Rialto: `Ferdie`, `George`, `Harry`. -- on Millau: `Ferdie`, `George`, `Harry`. +- on Rialto: `Ferdie`. +- on Millau: `Ferdie`. +- on RialtoParachain: `Charlie`, `Dave`, `Eve`, `Ferdie`. Names of accounts on Substrate (Rialto and Millau) chains may be prefixed with `//` and used as seeds for the `sr25519` keys. This seed may also be used in the signer argument in Substrate relays. @@ -97,7 +102,7 @@ Example: --source-port 9944 \ --target-host millau-node-alice \ --target-port 9944 \ - --source-signer //Harry \ + --source-signer //Ferdie \ --prometheus-host=0.0.0.0 ``` @@ -106,20 +111,29 @@ is not recommended, because this may lead to nonces conflict. Following accounts are used when `rialto-millau` bridge is running: -- Millau's `Charlie` signs complex headers+messages relay transactions on Millau chain; -- Rialto's `Charlie` signs complex headers+messages relay transactions on Rialto chain; -- Millau's `Dave` signs Millau transactions which contain messages for Rialto; -- Rialto's `Dave` signs Rialto transactions which contain messages for Millau; -- Millau's `Eve` signs relay transactions with message delivery confirmations (lane 00000001) from Rialto to Millau; -- Rialto's `Eve` signs relay transactions with messages (lane 00000001) from Millau to Rialto; -- Millau's `Ferdie` signs relay transactions with messages (lane 00000001) from Rialto to Millau; -- Rialto's `Ferdie` signs relay transactions with message delivery confirmations (lane 00000001) from Millau to Rialto; -- Millau's `RialtoMessagesOwner` signs relay transactions with updated Rialto -> Millau conversion rate; -- Rialto's `MillauMessagesOwner` signs relay transactions with updated Millau -> Rialto conversion rate. +- Millau's `Rialto.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on Millau chain; +- Rialto's `Millau.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on Rialto chain; +- Millau's `Rialto.MessagesSender` signs Millau transactions which contain messages for Rialto; +- Rialto's `Millau.MessagesSender` signs Rialto transactions which contain messages for Millau; +- Millau's `Rialto.OutboundMessagesRelay.Lane00000001` signs relay transactions with message delivery confirmations (lane 00000001) from Rialto to Millau; +- Rialto's `Millau.InboundMessagesRelay.Lane00000001` signs relay transactions with messages (lane 00000001) from Millau to Rialto; +- Millau's `Millau.OutboundMessagesRelay.Lane00000001` signs relay transactions with messages (lane 00000001) from Rialto to Millau; +- Rialto's `Rialto.InboundMessagesRelay.Lane00000001` signs relay transactions with message delivery confirmations (lane 00000001) from Millau to Rialto; +- Millau's `Rialto.MessagesOwner` signs relay transactions with updated Rialto -> Millau conversion rate; +- Rialto's `Millau.MessagesOwner` signs relay transactions with updated Millau -> Rialto conversion rate. Following accounts are used when `westend-millau` bridge is running: -- Millau's `George` signs relay transactions with new Westend headers. +- Millau's `Westend.GrandpaOwner` is signing with-Westend GRANDPA pallet initialization transaction. +- Millau's `Westend.HeadersRelay1` and `Westend.HeadersRelay2` are signing transactions with new Westend headers. +- Millau's `Westend.WestmintHeaders1` and `Westend.WestmintHeaders2` is signing transactions with new Westming headers. + +Following accounts are used when `rialto-parachain-millau` bridge is running: + +- RialtoParachain's `Millau.MessagesSender` signs RialtoParachain transactions which contain messages for Millau; +- Millau's `RialtoParachain.MessagesSender` signs Millau transactions which contain messages for RialtoParachain; +- Millau's `RialtoParachain.HeadersAndMessagesRelay` signs complex headers+parachains+messages relay transactions on Millau chain; +- RialtoParachain's `Millau.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on RialtoParachain chain. ### Docker Usage When the network is running you can query logs from individual nodes using: @@ -145,7 +159,7 @@ docker-compose up -d # Start the nodes in detached mode. docker-compose down # Stop the network. ``` -Note that for the you'll need to add the appropriate `-f` arguments that were mentioned in the +Note that you'll also need to add the appropriate `-f` arguments that were mentioned in the [Bridges](#bridges) section. You can read more about using multiple Compose files [here](https://docs.docker.com/compose/extends/#multiple-compose-files). One thing worth noting is that the _order_ the compose files are specified in matters. A different order will result in a @@ -172,7 +186,7 @@ docker build . -t local/ --build-arg=PROJECT= This will build a local image of a particular component with a tag of `local/`. This tag can be used in Docker Compose files. -You can configure the build using using Docker +You can configure the build using Docker [build arguments](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg). Here are the arguments currently supported: - `BRIDGE_REPO`: Git repository of the bridge node and relay code @@ -243,5 +257,5 @@ and import the [`./types.json`](./types.json) ## Scripts -The are some bash scripts in `scripts` folder that allow testing `Relay` +There are some bash scripts in `scripts` folder that allow testing `Relay` without running the entire network within docker. Use if needed for development. diff --git a/deployments/bridges/common/generate_messages.sh b/deployments/bridges/common/generate_messages.sh new file mode 100644 index 0000000000..26f0b2b4cb --- /dev/null +++ b/deployments/bridges/common/generate_messages.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Script for generating messages from a source chain to a target chain. +# Prerequisites: mounting the common folder in the docker container (Adding the following volume entry): +# - ./bridges/common:/common +# It can be used by executing `source /common/generate_messages.sh` in a different script, +# after setting the following variables: +# SOURCE_CHAIN +# TARGET_CHAIN +# MAX_SUBMIT_DELAY_S +# SEND_MESSAGE - the command that is executed to send a message +# MESSAGE_LANE +# SECONDARY_MESSAGE_LANE - optional +# SECONDARY_EXTRA_ARGS - optional, for example "--use-xcm-pallet" +# EXTRA_ARGS - for example "--use-xcm-pallet" +# REGULAR_PAYLOAD +# BATCH_PAYLOAD +# MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE + +SECONDARY_MESSAGE_LANE=${SECONDARY_MESSAGE_LANE:-""} +SECONDARY_EXTRA_ARGS=${SECONDARY_EXTRA_ARGS:-""} + +# Sleep a bit between messages +rand_sleep() { + SUBMIT_DELAY_S=`shuf -i 0-$MAX_SUBMIT_DELAY_S -n 1` + echo "Sleeping $SUBMIT_DELAY_S seconds..." + sleep $SUBMIT_DELAY_S + NOW=`date "+%Y-%m-%d %H:%M:%S"` + echo "Woke up at $NOW" +} + +# last time when we have been asking for conversion rate update +LAST_CONVERSION_RATE_UPDATE_TIME=0 +# conversion rate override argument +CONVERSION_RATE_OVERRIDE="--conversion-rate-override metric" + +# start sending large messages immediately +LARGE_MESSAGES_TIME=0 +# start sending message packs in a hour +BUNCH_OF_MESSAGES_TIME=3600 + +while true +do + rand_sleep + + # ask for latest conversion rate. We're doing that because otherwise we'll be facing + # bans from the conversion rate provider + if [ $SECONDS -ge $LAST_CONVERSION_RATE_UPDATE_TIME ]; then + CONVERSION_RATE_OVERRIDE="--conversion-rate-override metric" + CONVERSION_RATE_UPDATE_DELAY=`shuf -i 300-600 -n 1` + LAST_CONVERSION_RATE_UPDATE_TIME=$((SECONDS + $CONVERSION_RATE_UPDATE_DELAY)) + fi + + # send regular message + echo "Sending Message from $SOURCE_CHAIN to $TARGET_CHAIN" + SEND_MESSAGE_OUTPUT=`$SEND_MESSAGE --lane $MESSAGE_LANE $EXTRA_ARGS $CONVERSION_RATE_OVERRIDE raw $REGULAR_PAYLOAD 2>&1` + echo $SEND_MESSAGE_OUTPUT + if [ "$CONVERSION_RATE_OVERRIDE" = "--conversion-rate-override metric" ]; then + ACTUAL_CONVERSION_RATE_REGEX="conversion rate override: ([0-9\.]+)" + if [[ $SEND_MESSAGE_OUTPUT =~ $ACTUAL_CONVERSION_RATE_REGEX ]]; then + CONVERSION_RATE=${BASH_REMATCH[1]} + echo "Read updated conversion rate: $CONVERSION_RATE" + CONVERSION_RATE_OVERRIDE="--conversion-rate-override $CONVERSION_RATE" + else + echo "Error: unable to find conversion rate in send-message output. Will keep using on-chain rate" + CONVERSION_RATE_OVERRIDE="" + fi + fi + + if [ ! -z $SECONDARY_MESSAGE_LANE ]; then + echo "Sending Message from $SOURCE_CHAIN to $TARGET_CHAIN using secondary lane: $SECONDARY_MESSAGE_LANE" + $SEND_MESSAGE \ + --lane $SECONDARY_MESSAGE_LANE \ + $SECONDARY_EXTRA_ARGS \ + $CONVERSION_RATE_OVERRIDE \ + raw $REGULAR_PAYLOAD + fi + + # every other hour we're sending 3 large (size, weight, size+weight) messages + if [ $SECONDS -ge $LARGE_MESSAGES_TIME ]; then + LARGE_MESSAGES_TIME=$((SECONDS + 7200)) + + rand_sleep + echo "Sending Maximal Size Message from $SOURCE_CHAIN to $TARGET_CHAIN" + $SEND_MESSAGE \ + --lane $MESSAGE_LANE \ + $CONVERSION_RATE_OVERRIDE \ + sized max + fi + + # every other hour we're sending a bunch of small messages + if [ $SECONDS -ge $BUNCH_OF_MESSAGES_TIME ]; then + BUNCH_OF_MESSAGES_TIME=$((SECONDS + 7200)) + + for i in $(seq 0 $MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE); + do + $SEND_MESSAGE \ + --lane $MESSAGE_LANE \ + $EXTRA_ARGS \ + $CONVERSION_RATE_OVERRIDE \ + raw $BATCH_PAYLOAD + done + + fi +done diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json index abce8bbc29..1b48a47d47 100644 --- a/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json +++ b/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json @@ -15,7 +15,6 @@ "editable": true, "gnetId": null, "graphTooltip": 0, - "id": 3, "links": [], "panels": [ { @@ -247,10 +246,10 @@ } ], "executionErrorState": "alerting", - "for": "5m", + "for": "20m", "frequency": "1m", "handler": 1, - "name": "Messages generated at Millau are not detected by relay", + "name": "Millau -> Rialto messages are not detected by relay", "noDataState": "no_data", "notifications": [] }, @@ -299,16 +298,16 @@ "steppedLine": false, "targets": [ { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Rialto\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Millau\", \"type\", \"target_latest_received\")", + "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Rialto\", \"type\", \"source_latest_generated\"), \"type\", \"Latest Rialto message received by Millau\", \"type\", \"target_latest_received\")", "interval": "", "legendFormat": "{{type}}", "refId": "A" }, { - "expr": "max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[5m]) - min_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[5m])", + "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[10m]) OR on() vector(0)", "hide": true, "interval": "", - "legendFormat": "Messages generated in last 5 minutes", + "legendFormat": "Messages generated in last 5 minutes (Millau -> Rialto, 00000000)", "refId": "B" } ], @@ -408,7 +407,7 @@ "steppedLine": false, "targets": [ { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Rialto to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Millau\", \"type\", \"target_latest_received\")", + "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Rialto to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest Rialto message received by Millau\", \"type\", \"target_latest_received\")", "interval": "", "legendFormat": "{{type}}", "refId": "A" @@ -544,9 +543,9 @@ "refId": "A" }, { - "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[1m]) OR on() vector(0)", + "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[5m]) OR on() vector(0)", "interval": "", - "legendFormat": "Messages delivered to Rialto in last 1m", + "legendFormat": "Millau Messages delivered to Rialto in last 5m", "refId": "B" } ], @@ -607,7 +606,7 @@ { "evaluator": { "params": [ - 10 + 50 ], "type": "gt" }, @@ -629,10 +628,10 @@ } ], "executionErrorState": "alerting", - "for": "5m", + "for": "20m", "frequency": "1m", "handler": 1, - "name": "Too many unconfirmed messages", + "name": "Too many unconfirmed messages (Millau -> Rialto)", "noDataState": "no_data", "notifications": [] }, @@ -681,7 +680,7 @@ "steppedLine": false, "targets": [ { - "expr": "scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m])) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]))", + "expr": "scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", "interval": "", "legendFormat": "Unconfirmed messages at Millau", "refId": "A" @@ -766,10 +765,10 @@ } ], "executionErrorState": "alerting", - "for": "5m", + "for": "20m", "frequency": "1m", "handler": 1, - "name": "Rewards are not being confirmed", + "name": "Rewards are not being confirmed (Millau -> Rialto messages)", "noDataState": "no_data", "notifications": [] }, @@ -824,9 +823,9 @@ "refId": "A" }, { - "expr": "(scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]))) * (max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) > bool min_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "expr": "(scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) > bool min_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", "interval": "", - "legendFormat": "Unconfirmed rewards at Rialto (zero if messages are not being delivered to Rialto)", + "legendFormat": "Unconfirmed rewards at Millau->Rialto (zero if messages are not being delivered to Rialto)", "refId": "B" } ], @@ -961,16 +960,16 @@ "steppedLine": false, "targets": [ { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Rialto\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Millau\", \"type\", \"target_latest_received\")", + "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Rialto\", \"type\", \"source_latest_generated\"), \"type\", \"Latest Rialto message received by Millau\", \"type\", \"target_latest_received\")", "interval": "", "legendFormat": "{{type}}", "refId": "A" }, { - "expr": "increase(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=\"target_latest_received\"}[10m]) OR on() vector(0)", + "expr": "increase(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=\"source_latest_generated\"}[10m]) OR on() vector(0)", "hide": true, "interval": "", - "legendFormat": "Messages generated in last 5 minutes", + "legendFormat": "Messages generated in last 5 minutes (Millau -> Rialto, 00000001)", "refId": "B" } ], @@ -1104,7 +1103,7 @@ "steppedLine": false, "targets": [ { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Rialto to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Millau\", \"type\", \"target_latest_received\")", + "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Rialto to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest Rialto message received by Millau\", \"type\", \"target_latest_received\")", "interval": "", "legendFormat": "{{type}}", "refId": "A" @@ -1167,249 +1166,6 @@ "alignLevel": null } }, - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 - ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "1m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "max" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Token swap messages from Millau to Rialto are not being delivered", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {}, - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 11, - "w": 12, - "x": 0, - "y": 38 - }, - "hiddenSeries": false, - "id": 23, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_73776170_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Rialto\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Millau\", \"type\", \"target_latest_received\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - }, - { - "expr": "increase(Millau_to_Rialto_MessageLane_73776170_lane_state_nonces{type=\"target_latest_received\"}[20m]) OR on() vector(0)", - "hide": true, - "interval": "", - "legendFormat": "Messages generated in last 5 minutes", - "refId": "B" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "lt", - "value": 1 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Delivery race (73776170)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {}, - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 11, - "w": 12, - "x": 12, - "y": 38 - }, - "hiddenSeries": false, - "id": 24, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_73776170_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Rialto to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Millau\", \"type\", \"target_latest_received\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - }, - { - "expr": "increase(Millau_to_Rialto_MessageLane_73776170_lane_state_nonces{type=\"source_latest_confirmed\"}[10m]) OR on() vector(0)", - "hide": true, - "interval": "", - "legendFormat": "", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Confirmations race (73776170)", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, { "datasource": "Prometheus", "fieldConfig": { @@ -1436,7 +1192,7 @@ "h": 8, "w": 8, "x": 0, - "y": 49 + "y": 38 }, "id": 16, "options": { @@ -1485,7 +1241,7 @@ "h": 8, "w": 8, "x": 8, - "y": 49 + "y": 38 }, "hiddenSeries": false, "id": 18, @@ -1578,7 +1334,7 @@ "h": 8, "w": 8, "x": 16, - "y": 49 + "y": 38 }, "hiddenSeries": false, "id": 20, @@ -1680,5 +1436,5 @@ "timezone": "", "title": "Millau to Rialto Message Sync Dashboard", "uid": "relay-millau-to-rialto-messages", - "version": 2 + "version": 1 } diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json index 4e3d314a3f..7e7caedf91 100644 --- a/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json +++ b/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json @@ -247,10 +247,10 @@ } ], "executionErrorState": "alerting", - "for": "5m", + "for": "20m", "frequency": "1m", "handler": 1, - "name": "Messages generated at Rialto are not detected by relay", + "name": "Rialto -> Millau messages are not detected by relay", "noDataState": "no_data", "notifications": [] }, @@ -305,10 +305,10 @@ "refId": "A" }, { - "expr": "max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[5m]) - min_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[5m])", + "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[10m]) OR on() vector(0)", "hide": true, "interval": "", - "legendFormat": "Messages generated in last 5 minutes", + "legendFormat": "Messages generated in last 5 minutes (Rialto -> Millau, 00000000)", "refId": "B" } ], @@ -535,9 +535,9 @@ "refId": "A" }, { - "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[1m]) OR on() vector(0)", + "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[5m]) OR on() vector(0)", "interval": "", - "legendFormat": "Messages delivered to Millau in last 1m", + "legendFormat": "Rialto Messages delivered to Millau in last 5m", "refId": "B" } ], @@ -598,7 +598,7 @@ { "evaluator": { "params": [ - 10 + 50 ], "type": "gt" }, @@ -620,10 +620,10 @@ } ], "executionErrorState": "alerting", - "for": "5m", + "for": "20m", "frequency": "1m", "handler": 1, - "name": "Too many unconfirmed messages", + "name": "Too many unconfirmed messages (Rialto -> Millau)", "noDataState": "no_data", "notifications": [] }, @@ -672,7 +672,7 @@ "steppedLine": false, "targets": [ { - "expr": "scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m])) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]))", + "expr": "scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", "interval": "", "legendFormat": "Unconfirmed messages at Rialto", "refId": "A" @@ -757,10 +757,10 @@ } ], "executionErrorState": "alerting", - "for": "5m", + "for": "20m", "frequency": "1m", "handler": 1, - "name": "Rewards are not being confirmed", + "name": "Rewards are not being confirmed (Rialto -> Millau messages)", "noDataState": "no_data", "notifications": [] }, @@ -815,7 +815,7 @@ "refId": "A" }, { - "expr": "(scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]))) * (max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) > bool min_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "expr": "(scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) > bool min_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", "interval": "", "legendFormat": "Unconfirmed rewards at Millau (zero if messages are not being delivered to Millau)", "refId": "B" @@ -958,10 +958,10 @@ "refId": "A" }, { - "expr": "increase(Rialto_to_Millau_MessageLane_00000001_lane_state_nonces{type=\"target_latest_received\"}[10m]) OR on() vector(0)", + "expr": "increase(Rialto_to_Millau_MessageLane_00000001_lane_state_nonces{type=\"source_latest_generated\"}[10m]) OR on() vector(0)", "hide": true, "interval": "", - "legendFormat": "Messages generated in last 5 minutes", + "legendFormat": "Messages generated in last 5 minutes (Rialto -> Millau, 00000001)", "refId": "B" } ], diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json index 225e46fae3..c40ba241e0 100644 --- a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json +++ b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json @@ -490,6 +490,29 @@ "type": "last" }, "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" } ], "executionErrorState": "alerting", @@ -497,7 +520,7 @@ "frequency": "1m", "handler": 1, "name": "At-Rialto relay balances are too low", - "noDataState": "no_data", + "noDataState": "ok", "notifications": [] }, "aliasColors": {}, @@ -544,16 +567,22 @@ "steppedLine": false, "targets": [ { - "expr": "at_Rialto_relay_balance", + "expr": "at_Rialto_relay_MillauHeaders_balance", "interval": "", - "legendFormat": "Relay account balance", + "legendFormat": "With-Millau headers relay account balance", "refId": "A" }, { - "expr": "at_Rialto_messages_pallet_owner_balance", + "expr": "at_Rialto_relay_MillauMessages_balance", "interval": "", - "legendFormat": "Messages pallet owner balance", + "legendFormat": "With-Millau messages relay account balance", "refId": "B" + }, + { + "expr": "at_Rialto_relay_MillauMessagesPalletOwner_balance", + "interval": "", + "legendFormat": "With-Millau messages pallet owner account balance", + "refId": "C" } ], "thresholds": [ @@ -640,7 +669,7 @@ "type": "lt" }, "operator": { - "type": "and" + "type": "or" }, "query": { "params": [ @@ -654,6 +683,29 @@ "type": "last" }, "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" } ], "executionErrorState": "alerting", @@ -661,7 +713,7 @@ "frequency": "1m", "handler": 1, "name": "At-Millau relay balances are too low", - "noDataState": "no_data", + "noDataState": "ok", "notifications": [] }, "aliasColors": {}, @@ -708,16 +760,22 @@ "steppedLine": false, "targets": [ { - "expr": "at_Millau_relay_balance", + "expr": "at_Millau_relay_RialtoHeaders_balance{instance=\"relay-millau-rialto:9616\"}", "interval": "", - "legendFormat": "Relay account balance", + "legendFormat": "With-Rialto headers relay account balance", "refId": "A" }, { - "expr": "at_Millau_messages_pallet_owner_balance", + "expr": "at_Millau_relay_RialtoMessages_balance", "interval": "", - "legendFormat": "Messages pallet owner balance", + "legendFormat": "With-Rialto messages relay account balance", "refId": "B" + }, + { + "expr": "at_Millau_relay_RialtoMessagesPalletOwner_balance", + "interval": "", + "legendFormat": "With-Rialto messages pallet owner account balance", + "refId": "C" } ], "thresholds": [ @@ -849,7 +907,7 @@ "steppedLine": false, "targets": [ { - "expr": "Rialto_to_Millau_MessageLane_00000000_is_source_and_source_at_target_using_different_forks", + "expr": "Rialto_to_Millau_MessageLane_00000000_is_source_and_source_at_target_using_different_forks OR on() vector(0)", "interval": "", "legendFormat": "On different forks?", "refId": "A" @@ -984,7 +1042,7 @@ "steppedLine": false, "targets": [ { - "expr": "Millau_to_Rialto_MessageLane_00000000_is_source_and_source_at_target_using_different_forks", + "expr": "Millau_to_Rialto_MessageLane_00000000_is_source_and_source_at_target_using_different_forks OR on() vector(0)", "interval": "", "legendFormat": "On different forks?", "refId": "A" @@ -1038,6 +1096,104 @@ "align": false, "alignLevel": null } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_Rialto_MessageLane_00000000_unprofitable_delivery_transactions", + "interval": "", + "legendFormat": "Millau -> Rialto, lane 00000000", + "refId": "A" + }, + { + "expr": "Rialto_to_Millau_MessageLane_00000000_unprofitable_delivery_transactions", + "interval": "", + "legendFormat": "Rialto -> Millau, lane 00000000", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Count of unprofitable message delivery transactions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } } ], "refresh": "10s", diff --git a/deployments/bridges/rialto-millau/docker-compose.yml b/deployments/bridges/rialto-millau/docker-compose.yml index 5d774a5780..cd77dbbf12 100644 --- a/deployments/bridges/rialto-millau/docker-compose.yml +++ b/deployments/bridges/rialto-millau/docker-compose.yml @@ -19,9 +19,10 @@ services: LETSENCRYPT_EMAIL: admin@parity.io relay-millau-rialto: &sub-bridge-relay - image: paritytech/substrate-relay + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} entrypoint: /entrypoints/relay-millau-rialto-entrypoint.sh volumes: + - ./bridges/common:/common - ./bridges/rialto-millau/entrypoints:/entrypoints environment: RUST_LOG: rpc=trace,bridge=trace @@ -84,6 +85,7 @@ services: relay-messages-rialto-to-millau-generator: <<: *sub-bridge-relay environment: + RUST_LOG: bridge=trace MSG_EXCHANGE_GEN_SECONDARY_LANE: "00000001" entrypoint: /entrypoints/relay-messages-to-millau-generator-entrypoint.sh ports: @@ -91,14 +93,6 @@ services: depends_on: - relay-millau-rialto - relay-token-swap-generator: - <<: *sub-bridge-relay - entrypoint: /entrypoints/relay-token-swap-generator-entrypoint.sh - ports: - - "10716:9616" - depends_on: - - relay-millau-rialto - # Note: These are being overridden from the top level `monitoring` compose file. grafana-dashboard: environment: diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh index 743cc47f07..8eda149fde 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh @@ -7,10 +7,11 @@ MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} /home/user/substrate-relay relay-messages millau-to-rialto \ --lane $MESSAGE_LANE \ + --relayer-mode=altruistic \ --source-host millau-node-bob \ --source-port 9944 \ - --source-signer //Eve \ + --source-signer //Rialto.OutboundMessagesRelay.Lane00000001 \ --target-host rialto-node-bob \ --target-port 9944 \ - --target-signer //Eve \ + --target-signer //Millau.InboundMessagesRelay.Lane00000001 \ --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh index 2b536dbd81..4a3e5adbdc 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh @@ -7,10 +7,11 @@ MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} /home/user/substrate-relay relay-messages rialto-to-millau \ --lane $MESSAGE_LANE \ + --relayer-mode=altruistic \ --source-host rialto-node-bob \ --source-port 9944 \ - --source-signer //Ferdie \ + --source-signer //Millau.OutboundMessagesRelay.Lane00000001 \ --target-host millau-node-bob \ --target-port 9944 \ - --target-signer //Ferdie \ + --target-signer //Rialto.InboundMessagesRelay.Lane00000001 \ --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh index e20b3da7df..e3b566280a 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh @@ -12,132 +12,17 @@ MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} SECONDARY_MESSAGE_LANE=${MSG_EXCHANGE_GEN_SECONDARY_LANE} MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=1024 -FERDIE_ADDR=5oSLwptwgySxh5vz1HdvznQJjbQVgwYSvHEpYYeTXu1Ei8j7 SHARED_CMD="/home/user/substrate-relay send-message rialto-to-millau" SHARED_HOST="--source-host rialto-node-bob --source-port 9944" -DAVE_SIGNER="--source-signer //Dave --target-signer //Dave" +SOURCE_SIGNER="--source-signer //Millau.MessagesSender" -SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $DAVE_SIGNER" +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" -# Sleep a bit between messages -rand_sleep() { - SUBMIT_DELAY_S=`shuf -i 0-$MAX_SUBMIT_DELAY_S -n 1` - echo "Sleeping $SUBMIT_DELAY_S seconds..." - sleep $SUBMIT_DELAY_S - NOW=`date "+%Y-%m-%d %H:%M:%S"` - echo "Woke up at $NOW" -} +SOURCE_CHAIN="Rialto" +TARGET_CHAIN="Millau" +EXTRA_ARGS="--use-xcm-pallet" +REGULAR_PAYLOAD="020419ac" +BATCH_PAYLOAD="020419ac" -# start sending large messages immediately -LARGE_MESSAGES_TIME=0 -# start sending message packs in a hour -BUNCH_OF_MESSAGES_TIME=3600 - -while true -do - rand_sleep - echo "Sending Remark from Rialto to Millau using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - remark - - if [ ! -z $SECONDARY_MESSAGE_LANE ]; then - echo "Sending Remark from Rialto to Millau using Target Origin using secondary lane: $SECONDARY_MESSAGE_LANE" - $SEND_MESSAGE \ - --lane $SECONDARY_MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - --dispatch-fee-payment at-target-chain \ - remark - fi - - rand_sleep - echo "Sending Transfer from Rialto to Millau using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - transfer \ - --amount 1000000000 \ - --recipient $FERDIE_ADDR - - rand_sleep - echo "Sending Remark from Rialto to Millau using Source Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Source \ - remark - - rand_sleep - echo "Sending Transfer from Rialto to Millau using Source Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Source \ - transfer \ - --amount 1000000000 \ - --recipient $FERDIE_ADDR - - # every other hour we're sending 3 large (size, weight, size+weight) messages - if [ $SECONDS -ge $LARGE_MESSAGES_TIME ]; then - LARGE_MESSAGES_TIME=$((SECONDS + 7200)) - - rand_sleep - echo "Sending Maximal Size Remark from Rialto to Millau using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - remark \ - --remark-size=max - - rand_sleep - echo "Sending Maximal Dispatch Weight Remark from Rialto to Millau using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - --dispatch-weight=max \ - remark - - rand_sleep - echo "Sending Maximal Size and Dispatch Weight Remark from Rialto to Millau using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - --dispatch-weight=max \ - remark \ - --remark-size=max - - fi - - # every other hour we're sending a bunch of small messages - if [ $SECONDS -ge $BUNCH_OF_MESSAGES_TIME ]; then - BUNCH_OF_MESSAGES_TIME=$((SECONDS + 7200)) - - SEND_MESSAGE_OUTPUT=`$SEND_MESSAGE --lane $MESSAGE_LANE --conversion-rate-override metric --origin Target remark 2>&1` - echo $SEND_MESSAGE_OUTPUT - ACTUAL_CONVERSION_RATE_REGEX="conversion rate override: ([0-9\.]+)" - if [[ $SEND_MESSAGE_OUTPUT =~ $ACTUAL_CONVERSION_RATE_REGEX ]]; then - ACTUAL_CONVERSION_RATE=${BASH_REMATCH[1]} - else - echo "Unable to find conversion rate in send-message output" - exit 1 - fi - - for i in $(seq 1 $MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE); - do - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override $ACTUAL_CONVERSION_RATE \ - --origin Target \ - remark - done - - fi -done +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh index a8e032bbdf..685d82911e 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh @@ -12,132 +12,17 @@ MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} SECONDARY_MESSAGE_LANE=${MSG_EXCHANGE_GEN_SECONDARY_LANE} MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=128 -FERDIE_ADDR=6ztG3jPnJTwgZnnYsgCDXbbQVR82M96hBZtPvkN56A9668ZC SHARED_CMD=" /home/user/substrate-relay send-message millau-to-rialto" SHARED_HOST="--source-host millau-node-bob --source-port 9944" -DAVE_SIGNER="--target-signer //Dave --source-signer //Dave" +SOURCE_SIGNER="--source-signer //Rialto.MessagesSender" -SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $DAVE_SIGNER" +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" -# Sleep a bit between messages -rand_sleep() { - SUBMIT_DELAY_S=`shuf -i 0-$MAX_SUBMIT_DELAY_S -n 1` - echo "Sleeping $SUBMIT_DELAY_S seconds..." - sleep $SUBMIT_DELAY_S - NOW=`date "+%Y-%m-%d %H:%M:%S"` - echo "Woke up at $NOW" -} +SOURCE_CHAIN="Millau" +TARGET_CHAIN="Rialto" +EXTRA_ARGS="--use-xcm-pallet" +REGULAR_PAYLOAD="020419ac" +BATCH_PAYLOAD="020419ac" -# start sending large messages immediately -LARGE_MESSAGES_TIME=0 -# start sending message packs in a hour -BUNCH_OF_MESSAGES_TIME=3600 - -while true -do - rand_sleep - echo "Sending Remark from Millau to Rialto using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - remark - - if [ ! -z $SECONDARY_MESSAGE_LANE ]; then - echo "Sending Remark from Millau to Rialto using Target Origin using secondary lane: $SECONDARY_MESSAGE_LANE" - $SEND_MESSAGE \ - --lane $SECONDARY_MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - --dispatch-fee-payment at-target-chain \ - remark - fi - - rand_sleep - echo "Sending Transfer from Millau to Rialto using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - transfer \ - --amount 1000000000 \ - --recipient $FERDIE_ADDR - - rand_sleep - echo "Sending Remark from Millau to Rialto using Source Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Source \ - remark - - rand_sleep - echo "Sending Transfer from Millau to Rialto using Source Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Source \ - transfer \ - --amount 1000000000 \ - --recipient $FERDIE_ADDR - - # every other hour we're sending 3 large (size, weight, size+weight) messages - if [ $SECONDS -ge $LARGE_MESSAGES_TIME ]; then - LARGE_MESSAGES_TIME=$((SECONDS + 7200)) - - rand_sleep - echo "Sending Maximal Size Remark from Millau to Rialto using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - remark \ - --remark-size=max - - rand_sleep - echo "Sending Maximal Dispatch Weight Remark from Millau to Rialto using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - --dispatch-weight=max \ - remark - - rand_sleep - echo "Sending Maximal Size and Dispatch Weight Remark from Millau to Rialto using Target Origin" - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override metric \ - --origin Target \ - --dispatch-weight=max \ - remark \ - --remark-size=max - - fi - - # every other hour we're sending a bunch of small messages - if [ $SECONDS -ge $BUNCH_OF_MESSAGES_TIME ]; then - BUNCH_OF_MESSAGES_TIME=$((SECONDS + 7200)) - - SEND_MESSAGE_OUTPUT=`$SEND_MESSAGE --lane $MESSAGE_LANE --conversion-rate-override metric --origin Target remark 2>&1` - echo $SEND_MESSAGE_OUTPUT - ACTUAL_CONVERSION_RATE_REGEX="conversion rate override: ([0-9\.]+)" - if [[ $SEND_MESSAGE_OUTPUT =~ $ACTUAL_CONVERSION_RATE_REGEX ]]; then - ACTUAL_CONVERSION_RATE=${BASH_REMATCH[1]} - else - echo "Unable to find conversion rate in send-message output" - exit 1 - fi - - for i in $(seq 2 $MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE); - do - $SEND_MESSAGE \ - --lane $MESSAGE_LANE \ - --conversion-rate-override $ACTUAL_CONVERSION_RATE \ - --origin Target \ - remark - done - - fi -done +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh index 068560e150..bd9bf800ad 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh @@ -3,7 +3,7 @@ set -xeu sleep 15 -# //Dave is signing Millau -> Rialto message-send transactions, which are causing problems. +# //Rialto.MessagesSender is signing Millau -> Rialto message-send transactions, which are causing problems. # # When large message is being sent from Millau to Rialto AND other transactions are # blocking it from being mined, we'll see something like this in logs: @@ -18,7 +18,7 @@ sleep 15 /home/user/substrate-relay resubmit-transactions millau \ --target-host millau-node-alice \ --target-port 9944 \ - --target-signer //Dave \ + --target-signer //Rialto.MessagesSender \ --stalled-blocks 5 \ --tip-limit 1000000000000 \ --tip-step 1000000000 \ diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh index bab0e1c4af..208f3d9352 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh @@ -8,14 +8,14 @@ sleep 15 --source-port 9944 \ --target-host rialto-node-alice \ --target-port 9944 \ - --target-signer //Alice + --target-signer //Sudo /home/user/substrate-relay init-bridge rialto-to-millau \ --source-host rialto-node-alice \ --source-port 9944 \ --target-host millau-node-alice \ --target-port 9944 \ - --target-signer //Alice + --target-signer //Sudo # Give chain a little bit of time to process initialization transaction sleep 6 @@ -23,14 +23,15 @@ sleep 6 /home/user/substrate-relay relay-headers-and-messages millau-rialto \ --millau-host millau-node-alice \ --millau-port 9944 \ - --millau-signer //Charlie \ - --millau-messages-pallet-owner=//RialtoMessagesOwner \ + --millau-signer //Rialto.HeadersAndMessagesRelay \ + --millau-messages-pallet-owner=//Rialto.MessagesOwner \ --millau-transactions-mortality=64 \ --rialto-host rialto-node-alice \ --rialto-port 9944 \ - --rialto-signer //Charlie \ - --rialto-messages-pallet-owner=//MillauMessagesOwner \ + --rialto-signer //Millau.HeadersAndMessagesRelay \ + --rialto-messages-pallet-owner=//Millau.MessagesOwner \ --rialto-transactions-mortality=64 \ --lane=00000000 \ --lane=73776170 \ + --relayer-mode=altruistic \ --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh deleted file mode 100755 index 010c0572d5..0000000000 --- a/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT -# -# This scripts periodically calls the Substrate relay binary to generate messages. These messages -# are sent from the Millau network to the Rialto network. - -set -eu - -# Max delay before submitting transactions (s) -MAX_SUBMIT_DELAY_S=60 -SOURCE_HOST=millau-node-charlie -SOURCE_PORT=9944 -TARGET_HOST=rialto-node-charlie -TARGET_PORT=9944 - -# Sleep a bit between messages -rand_sleep() { - SUBMIT_DELAY_S=`shuf -i 0-$MAX_SUBMIT_DELAY_S -n 1` - echo "Sleeping $SUBMIT_DELAY_S seconds..." - sleep $SUBMIT_DELAY_S - NOW=`date "+%Y-%m-%d %H:%M:%S"` - echo "Woke up at $NOW" -} - -while true -do - rand_sleep - echo "Initiating token-swap between Rialto and Millau" - /home/user/substrate-relay \ - swap-tokens \ - millau-to-rialto \ - --source-host $SOURCE_HOST \ - --source-port $SOURCE_PORT \ - --source-signer //WithRialtoTokenSwap \ - --source-balance 100000 \ - --target-host $TARGET_HOST \ - --target-port $TARGET_PORT \ - --target-signer //WithMillauTokenSwap \ - --target-balance 200000 \ - --target-to-source-conversion-rate-override metric \ - --source-to-target-conversion-rate-override metric \ - lock-until-block \ - --blocks-before-expire 32 -done diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json new file mode 100644 index 0000000000..b20348cc51 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json @@ -0,0 +1,910 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "A" + }, + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_target_at_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized RialtoParachain headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At Millau", + "refId": "A" + }, + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_source_at_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Millau headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Millau -> RialtoParachain messages are not detected by relay", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from RialtoParachain\", \"type\", \"source_latest_generated\"), \"type\", \"Latest RialtoParachain message received by Millau\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + }, + { + "expr": "increase(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[10m]) OR on() vector(0)", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes (Millau -> RialtoParachain, 00000000)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by RialtoParachain to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest RialtoParachain message received by Millau\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "7m", + "frequency": "1m", + "handler": 1, + "name": "Messages from Millau to RialtoParachain are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 20 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at RialtoParachain", + "refId": "A" + }, + { + "expr": "increase(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[5m]) OR on() vector(0)", + "interval": "", + "legendFormat": "Millau Messages delivered to RialtoParachain in last 5m", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages (Millau -> RialtoParachain)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 20 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "legendFormat": "Unconfirmed messages at Millau", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed (Millau -> RialtoParachain messages)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 20 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at RialtoParachain", + "refId": "A" + }, + { + "expr": "(scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) > bool min_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau->RaltoParachain (zero if messages are not being delivered to RialtoParachain)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reward lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Millau to RialtoParachain Message Sync Dashboard", + "uid": "C61e-797z", + "version": 1 +} diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json new file mode 100644 index 0000000000..064436145d --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json @@ -0,0 +1,908 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At Millau", + "refId": "A" + }, + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_target_at_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Millau headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "A" + }, + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_source_at_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized RialtoParachain headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "RialtoParachain -> Millau messages are not detected by relay", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Millau\", \"type\", \"source_latest_generated\"), \"type\", \"Latest Millau message received by RialtoParachain\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + }, + { + "expr": "increase(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[10m]) OR on() vector(0)", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes (RialtoParachain -> Millau, 00000000)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Millau to RialtoParachain\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest Millau message received by RialtoParachain\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "7m", + "frequency": "1m", + "handler": 1, + "name": "Messages from RialtoParachain to Millau are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 20 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at Millau", + "refId": "A" + }, + { + "expr": "increase(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[5m]) OR on() vector(0)", + "interval": "", + "legendFormat": "RialtoParachain Messages delivered to Millau in last 5m", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages (RialtoParachain -> Millau)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 20 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "legendFormat": "Unconfirmed messages at RialtoParachain", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed (RialtoParachain -> Millau messages)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 20 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau", + "refId": "A" + }, + { + "expr": "(scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) > bool min_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau (zero if messages are not being delivered to Millau)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reward lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "RialtoParachain to Millau Message Sync Dashboard", + "uid": "-l61a7r7k", + "version": 1 +} diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json new file mode 100644 index 0000000000..a8305e84e4 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json @@ -0,0 +1,1129 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "rialtoparachain_storage_proof_overhead{instance='relay-millau-rialto-parachain-1:9616'}", + "interval": "", + "legendFormat": "Actual overhead", + "refId": "A" + }, + { + "exemplar": true, + "expr": "1024", + "hide": false, + "interval": "", + "legendFormat": "At runtime (hardcoded)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RialtoParachain: storage proof overhead", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "polkadot_to_base_conversion_rate{instance='relay-millau-rialto-parachain-1:9616'} / kusama_to_base_conversion_rate{instance='relay-millau-rialto-parachain-1:9616'}", + "interval": "", + "legendFormat": "Outside of runtime (actually Polkadot -> Kusama)", + "refId": "A" + }, + { + "exemplar": true, + "expr": "Millau_RialtoParachain_to_Millau_conversion_rate{instance='relay-millau-rialto-parachain-1:9616'}", + "hide": false, + "interval": "", + "legendFormat": "At runtime", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Millau: RialtoParachain -> Millau conversion rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "millau_storage_proof_overhead{instance='relay-millau-rialto-parachain-1:9616'}", + "interval": "", + "legendFormat": "Actual overhead", + "refId": "A" + }, + { + "exemplar": true, + "expr": "1024", + "hide": false, + "interval": "", + "legendFormat": "At runtime (hardcoded)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Millau: storage proof overhead", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "kusama_to_base_conversion_rate{instance='relay-millau-rialto-parachain-1:9616'} / polkadot_to_base_conversion_rate{instance='relay-millau-rialto-parachain-1:9616'}", + "interval": "", + "legendFormat": "Outside of runtime (actually Kusama -> Polkadot)", + "refId": "A" + }, + { + "exemplar": true, + "expr": "RialtoParachain_Millau_to_RialtoParachain_conversion_rate{instance='relay-millau-rialto-parachain-1:9616'}", + "hide": false, + "interval": "", + "legendFormat": "At runtime", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RialtoParachain: Millau -> RialtoParachain conversion rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "At-Rialto relay balances are too low", + "noDataState": "ok", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "at_RialtoParachain_relay_MillauHeaders_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-Millau headers relay account balance", + "refId": "A" + }, + { + "expr": "at_RialtoParachain_relay_MillauMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-Millau messages relay account balance", + "refId": "B" + }, + { + "expr": "at_RialtoParachain_relay_MillauMessagesPalletOwner_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-Millau messages pallet owner account balance", + "refId": "C" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1000 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RialtoParachain relay balances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "At-Millau relay balances are too low", + "noDataState": "ok", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "at_Millau_relay_RialtoHeaders_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-Rialto headers relay account balance", + "refId": "A" + }, + { + "expr": "at_Millau_relay_RialtoParachainMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-RialtoParachain messages relay account balance", + "refId": "B" + }, + { + "expr": "at_Millau_relay_RialtoParachains_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-Rialto parachains relay account balance", + "refId": "C" + }, + { + "expr": "at_Millau_relay_RialtoParachainMessagesPalletOwner_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-RialtoParachain messages pallet owner account balance", + "refId": "D" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1000 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Millau relay balances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-RialtoParachain-parachains-pallet and Rialto itself are on different forks alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_is_source_and_source_at_target_using_different_forks{instance=\"relay-millau-rialto-parachain-1:9616\"} OR on() vector(0)", + "instant": false, + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-RialtoParachain-parachains-pallet and RialtoParachain itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-Millau-grandpa-pallet and Millau itself are on different forks", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_is_source_and_source_at_target_using_different_forks{instance=\"relay-millau-rialto-parachain-1:9616\"} OR on() vector(0)", + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-Millau-grandpa-pallet and Millau itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "RialtoParachain+Millau maintenance dashboard", + "uid": "WALc3ajnk", + "version": 1 +} diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml b/deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml new file mode 100644 index 0000000000..ba683e3479 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml @@ -0,0 +1,3 @@ +- targets: + - relay-millau-rialto-parachain-1:9616 + - relay-millau-rialto-parachain-2:9616 diff --git a/deployments/bridges/rialto-parachain-millau/docker-compose.yml b/deployments/bridges/rialto-parachain-millau/docker-compose.yml new file mode 100644 index 0000000000..a62bda52eb --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/docker-compose.yml @@ -0,0 +1,90 @@ +# Exposed ports: 10816, 10916, 11016, 11017, 11018 + +version: '3.5' +services: + # We provide overrides for these particular nodes since they are public facing + # nodes which we use to connect from things like Polkadot JS Apps. + rialto-parachain-collator-charlie: + environment: + VIRTUAL_HOST: wss.rialto-parachain.brucke.link + VIRTUAL_PORT: 9944 + LETSENCRYPT_HOST: wss.rialto-parachain.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + + millau-node-charlie: + environment: + VIRTUAL_HOST: wss.millau.brucke.link + VIRTUAL_PORT: 9944 + LETSENCRYPT_HOST: wss.millau.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + + relay-millau-rialto-parachain-1: &sub-bridge-relay + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-millau-rialto-parachain-entrypoint.sh + volumes: + - ./bridges/common:/common + - ./bridges/rialto-parachain-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + ports: + - "10816:9616" + depends_on: &all-nodes + - millau-node-alice + - millau-node-bob + - millau-node-charlie + - millau-node-dave + - millau-node-eve + - rialto-parachain-collator-alice + - rialto-parachain-collator-bob + - rialto-parachain-collator-charlie + + relay-millau-rialto-parachain-2: + <<: *sub-bridge-relay + environment: + RUST_LOG: rpc=trace,bridge=trace + EXT_MILLAU_RELAY_ACCOUNT: //RialtoParachain.HeadersAndMessagesRelay2 + EXT_MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE: //RialtoParachain.RialtoHeadersRelay2 + EXT_RIALTO_PARACHAIN_RELAY_ACCOUNT: //Millau.HeadersAndMessagesRelay2 + ports: + - "10916:9616" + relay-messages-millau-to-rialto-parachain-generator: + <<: *sub-bridge-relay + ports: + - "11016:9616" + entrypoint: /entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh + depends_on: + - relay-millau-rialto-parachain-1 + + relay-messages-rialto-parachain-to-millau-generator: + <<: *sub-bridge-relay + entrypoint: /entrypoints/relay-messages-to-millau-generator-entrypoint.sh + ports: + - "11017:9616" + depends_on: + - relay-millau-rialto-parachain-1 + + relay-messages-millau-to-rialto-parachain-resubmitter: + <<: *sub-bridge-relay + environment: + RUST_LOG: bridge=trace + entrypoint: /entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh + ports: + - "11018:9616" + depends_on: + - relay-messages-millau-to-rialto-parachain-generator + + # Note: These are being overridden from the top level `monitoring` compose file. + grafana-dashboard: + environment: + VIRTUAL_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + VIRTUAL_PORT: 3000 + LETSENCRYPT_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + volumes: + - ./bridges/rialto-parachain-millau/dashboard/grafana:/etc/grafana/dashboards/rialto-parachain-millau:ro + - ./networks/dashboard/grafana/beefy-dashboard.json:/etc/grafana/dashboards/beefy.json + + prometheus-metrics: + volumes: + - ./bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml:/etc/prometheus/targets-rialto-parachain-millau.yml + depends_on: *all-nodes diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh new file mode 100755 index 0000000000..92aafdfbed --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT +# +# This scripts periodically calls the Substrate relay binary to generate messages. These messages +# are sent from the Rialto network to the Millau network. + +set -eu + +# Max delay before submitting transactions (s) +MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} +MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} +MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=1024 + +SHARED_CMD="/home/user/substrate-relay send-message rialto-parachain-to-millau" +SHARED_HOST="--source-host rialto-parachain-collator-bob --source-port 9944" +SOURCE_SIGNER="--source-signer //Millau.MessagesSender" + +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" + +SOURCE_CHAIN="RialtoParachain" +TARGET_CHAIN="Millau" +EXTRA_ARGS="--use-xcm-pallet" +REGULAR_PAYLOAD="020419ac" +BATCH_PAYLOAD="010109020419A8" + +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh new file mode 100755 index 0000000000..791519daff --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT +# +# This scripts periodically calls the Substrate relay binary to generate messages. These messages +# are sent from the Millau network to the Rialto network. + +set -eu + +# Max delay before submitting transactions (s) +MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} +MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} +MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=1024 + +SHARED_CMD=" /home/user/substrate-relay send-message millau-to-rialto-parachain" +SHARED_HOST="--source-host millau-node-bob --source-port 9944" +SOURCE_SIGNER="--source-signer //RialtoParachain.MessagesSender" + +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" + +SOURCE_CHAIN="Millau" +TARGET_CHAIN="RialtoParachain" +EXTRA_ARGS="--use-xcm-pallet" +REGULAR_PAYLOAD="020419ac" +BATCH_PAYLOAD="010109020419A8" + +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh new file mode 100755 index 0000000000..cf4c4612d6 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -xeu + +sleep 15 + +# //RialtoParachain.MessagesSender is signing Millau -> RialtoParachain message-send transactions, which are causing problems. +# +# When large message is being sent from Millau to RialtoParachain AND other transactions are +# blocking it from being mined, we'll see something like this in logs: +# +# Millau transaction priority with tip=0: 17800827994. Target priority: +# 526186677695 +# +# So since fee multiplier in Millau is `1` and `WeightToFee` is `IdentityFee`, then +# we need tip around `526186677695 - 17800827994 = 508_385_849_701`. Let's round it +# up to `1_000_000_000_000`. + +/home/user/substrate-relay resubmit-transactions millau \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //RialtoParachain.MessagesSender \ + --stalled-blocks 7 \ + --tip-limit 1000000000000 \ + --tip-step 1000000000 \ + make-it-best-transaction diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh new file mode 100755 index 0000000000..f2732e82f4 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -xeu + +sleep 15 + +MILLAU_RELAY_ACCOUNT=${EXT_MILLAU_RELAY_ACCOUNT:-//RialtoParachain.HeadersAndMessagesRelay1} +MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE=${EXT_MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE:-//RialtoParachain.RialtoHeadersRelay1} +RIALTO_PARACHAIN_RELAY_ACCOUNT=${EXT_RIALTO_PARACHAIN_RELAY_ACCOUNT:-//Millau.HeadersAndMessagesRelay1} + +/home/user/substrate-relay init-bridge millau-to-rialto-parachain \ + --source-host millau-node-alice \ + --source-port 9944 \ + --target-host rialto-parachain-collator-alice \ + --target-port 9944 \ + --target-signer //Sudo + +/home/user/substrate-relay init-bridge rialto-to-millau \ + --source-host rialto-node-alice \ + --source-port 9944 \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //Sudo + +# Give chain a little bit of time to process initialization transaction +sleep 6 + +/home/user/substrate-relay relay-headers-and-messages millau-rialto-parachain \ + --millau-host millau-node-alice \ + --millau-port 9944 \ + --millau-signer $MILLAU_RELAY_ACCOUNT \ + --rialto-headers-to-millau-signer $MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE \ + --millau-messages-pallet-owner=//RialtoParachain.MessagesOwner \ + --millau-transactions-mortality=64 \ + --rialto-parachain-host rialto-parachain-collator-charlie \ + --rialto-parachain-port 9944 \ + --rialto-parachain-signer $RIALTO_PARACHAIN_RELAY_ACCOUNT \ + --rialto-parachain-messages-pallet-owner=//Millau.MessagesOwner \ + --rialto-parachain-transactions-mortality=64 \ + --rialto-host rialto-node-alice \ + --rialto-port 9944 \ + --lane=00000000 \ + --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json index 682ac2c778..8f740d2ba5 100644 --- a/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json +++ b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json @@ -410,7 +410,7 @@ "steppedLine": false, "targets": [ { - "expr": "system_average_load{instance='relay-headers-westend-to-millau:9616'}", + "expr": "system_average_load{instance='relay-headers-westend-to-millau-1:9616'}", "interval": "", "legendFormat": "Average system load in last {{over}}", "refId": "A" @@ -509,7 +509,7 @@ "pluginVersion": "7.1.3", "targets": [ { - "expr": "avg_over_time(process_cpu_usage_percentage{instance='relay-headers-westend-to-millau:9616'}[1m])", + "expr": "avg_over_time(process_cpu_usage_percentage{instance='relay-headers-westend-to-millau-1:9616'}[1m])", "instant": true, "interval": "", "legendFormat": "1 CPU = 100", @@ -702,7 +702,7 @@ "steppedLine": false, "targets": [ { - "expr": "process_memory_usage_bytes{instance='relay-headers-westend-to-millau:9616'} / 1024 / 1024", + "expr": "process_memory_usage_bytes{instance='relay-headers-westend-to-millau-1:9616'} / 1024 / 1024", "interval": "", "legendFormat": "Process memory, MB", "refId": "A" diff --git a/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json new file mode 100644 index 0000000000..007b6ef932 --- /dev/null +++ b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json @@ -0,0 +1,200 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 32 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Too many Westmint headers are missing at Millau", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Westend_to_Millau_Parachains_best_parachain_block_number_at_source{parachain='para_2000'}", + "interval": "", + "legendFormat": "At Westend", + "refId": "A" + }, + { + "expr": "Westend_to_Millau_Parachains_best_parachain_block_number_at_target{parachain='para_2000'}", + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + }, + { + "expr": "Westend_to_Millau_Parachains_best_parachain_block_number_at_source{parachain='para_2000'} - Westend_to_Millau_Parachains_best_parachain_block_number_at_target{parachain='para_2000'}", + "hide": true, + "interval": "", + "legendFormat": "Missing Westmint headers at Millau", + "refId": "C" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 32 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Westmint headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Westend parachains at Millau", + "uid": "vUMhOlq7k", + "version": 1 + } + \ No newline at end of file diff --git a/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml b/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml index 5d49e11274..aed2d49458 100644 --- a/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml +++ b/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml @@ -1,2 +1,3 @@ - targets: - - relay-headers-westend-to-millau:9616 + - relay-headers-westend-to-millau-1:9616 + - relay-parachains-westend-to-millau-1:9616 \ No newline at end of file diff --git a/deployments/bridges/westend-millau/docker-compose.yml b/deployments/bridges/westend-millau/docker-compose.yml index 8caa17ffb8..dfb6ebb0c6 100644 --- a/deployments/bridges/westend-millau/docker-compose.yml +++ b/deployments/bridges/westend-millau/docker-compose.yml @@ -1,9 +1,9 @@ -# Exposed ports: 10616 +# Exposed ports: 10616, 10617, 10618, 10619 version: '3.5' services: - relay-headers-westend-to-millau: - image: paritytech/substrate-relay + relay-headers-westend-to-millau-1: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} entrypoint: /entrypoints/relay-headers-westend-to-millau-entrypoint.sh volumes: - ./bridges/westend-millau/entrypoints:/entrypoints @@ -14,6 +14,44 @@ services: depends_on: - millau-node-alice + relay-headers-westend-to-millau-2: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-headers-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + EXT_RELAY_ACCOUNT: //Westend.HeadersRelay2 + ports: + - "10617:9616" + depends_on: + - millau-node-alice + + relay-parachains-westend-to-millau-1: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-parachains-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + ports: + - "10618:9616" + depends_on: + - millau-node-alice + + relay-parachains-westend-to-millau-2: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-parachains-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + EXT_RELAY_ACCOUNT: //Westend.WestmintHeaders2 + ports: + - "10619:9616" + depends_on: + - millau-node-alice + # Note: These are being overridden from the top level `monitoring` compose file. grafana-dashboard: environment: @@ -28,4 +66,7 @@ services: volumes: - ./bridges/westend-millau/dashboard/prometheus/targets.yml:/etc/prometheus/targets-westend-millau.yml depends_on: - - relay-headers-westend-to-millau + - relay-headers-westend-to-millau-1 + - relay-headers-westend-to-millau-2 + - relay-parachains-westend-to-millau-1 + - relay-parachains-westend-to-millau-2 diff --git a/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh b/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh index f37ee69915..8548e9f5a4 100755 --- a/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh +++ b/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh @@ -3,13 +3,15 @@ set -xeu sleep 15 +RELAY_ACCOUNT=${EXT_RELAY_ACCOUNT:-//Westend.HeadersRelay1} + /home/user/substrate-relay init-bridge westend-to-millau \ --source-host westend-rpc.polkadot.io \ --source-port 443 \ --source-secure \ --target-host millau-node-alice \ --target-port 9944 \ - --target-signer //George + --target-signer //Westend.GrandpaOwner # Give chain a little bit of time to process initialization transaction sleep 6 @@ -19,6 +21,6 @@ sleep 6 --source-secure \ --target-host millau-node-alice \ --target-port 9944 \ - --target-signer //George \ + --target-signer $RELAY_ACCOUNT \ --target-transactions-mortality=4\ --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh b/deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh new file mode 100755 index 0000000000..fc7ccb3584 --- /dev/null +++ b/deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xeu + +sleep 15 + +RELAY_ACCOUNT=${EXT_RELAY_ACCOUNT:-//Westend.WestmintHeaders1} + +/home/user/substrate-relay relay-parachains westend-to-millau \ + --source-host westend-rpc.polkadot.io \ + --source-port 443 \ + --source-secure \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer $RELAY_ACCOUNT \ + --target-transactions-mortality=4\ + --prometheus-host=0.0.0.0 diff --git a/deployments/local-scripts/relay-headers-rococo-to-wococo.sh b/deployments/local-scripts/relay-headers-rococo-to-wococo.sh deleted file mode 100755 index 61028e1756..0000000000 --- a/deployments/local-scripts/relay-headers-rococo-to-wococo.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# -# Run an instance of the Rococo -> Wococo header sync. -# -# Right now this relies on local Wococo and Rococo networks -# running (which include `pallet-bridge-grandpa` in their -# runtimes), but in the future it could use use public RPC nodes. - -set -xeu - -RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay init-bridge rococo-to-wococo \ - --source-host 127.0.0.1 \ - --source-port 9955 \ - --target-host 127.0.0.1 \ - --target-port 9944 \ - --target-signer //Alice - -RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay relay-headers rococo-to-wococo \ - --source-host 127.0.0.1 \ - --source-port 9955 \ - --target-host 127.0.0.1 \ - --target-port 9944 \ - --target-signer //Bob \ - --prometheus-host=0.0.0.0 \ diff --git a/deployments/local-scripts/relay-headers-wococo-to-rococo.sh b/deployments/local-scripts/relay-headers-wococo-to-rococo.sh deleted file mode 100755 index c57db2086f..0000000000 --- a/deployments/local-scripts/relay-headers-wococo-to-rococo.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# -# Run an instance of the Wococo -> Rococo header sync. -# -# Right now this relies on local Wococo and Rococo networks -# running (which include `pallet-bridge-grandpa` in their -# runtimes), but in the future it could use use public RPC nodes. - -set -xeu - -RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay init-bridge wococo-to-rococo \ - --source-host 127.0.0.1 \ - --source-port 9944 \ - --target-host 127.0.0.1 \ - --target-port 9955 \ - --target-signer //Alice - -RUST_LOG=rpc=trace,bridge=trace ./target/debug/substrate-relay relay-headers wococo-to-rococo \ - --source-host 127.0.0.1 \ - --source-port 9944 \ - --target-host 127.0.0.1 \ - --target-port 9955 \ - --target-signer //Charlie \ - --prometheus-host=0.0.0.0 \ diff --git a/deployments/local-scripts/run-rococo-node.sh b/deployments/local-scripts/run-rococo-node.sh deleted file mode 100755 index 4d43321eba..0000000000 --- a/deployments/local-scripts/run-rococo-node.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Run a development instance of the Rococo Substrate bridge node. -# To override the default port just export ROCOCO_PORT=9955 -# -# Note: This script will not work out of the box with the bridges -# repo since it relies on a Polkadot binary. - -ROCOCO_PORT="${ROCOCO_PORT:-9955}" - -RUST_LOG=runtime=trace,runtime::bridge=trace \ -./target/debug/polkadot --chain=rococo-dev --alice --tmp \ - --rpc-cors=all --unsafe-rpc-external --unsafe-ws-external \ - --port 33044 --rpc-port 9934 --ws-port $ROCOCO_PORT \ diff --git a/deployments/local-scripts/run-wococo-node.sh b/deployments/local-scripts/run-wococo-node.sh deleted file mode 100755 index f314c0c7fa..0000000000 --- a/deployments/local-scripts/run-wococo-node.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Run a development instance of the Wococo Substrate bridge node. -# To override the default port just export WOCOCO_PORT=9955 -# -# Note: This script will not work out of the box with the bridges -# repo since it relies on a Polkadot binary. - -WOCOCO_PORT="${WOCOCO_PORT:-9944}" - -RUST_LOG=runtime=trace,runtime::bridge=trace \ -./target/debug/polkadot --chain=wococo-dev --alice --tmp \ - --rpc-cors=all --unsafe-rpc-external --unsafe-ws-external \ - --port 33033 --rpc-port 9933 --ws-port $WOCOCO_PORT \ diff --git a/deployments/monitoring/GrafanaMatrix.Dockerfile b/deployments/monitoring/GrafanaMatrix.Dockerfile index df80f70021..be1c80d405 100644 --- a/deployments/monitoring/GrafanaMatrix.Dockerfile +++ b/deployments/monitoring/GrafanaMatrix.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/ruby:alpine +FROM ruby:alpine3.13 RUN apk add --no-cache git @@ -7,12 +7,9 @@ ENV RACK_ENV production RUN mkdir $APP_HOME WORKDIR $APP_HOME -# The latest master has some changes in how the application is run. We don't -# want to update just yet so we're pinning to an old commit. RUN git clone https://github.com/ananace/ruby-grafana-matrix.git $APP_HOME -RUN git checkout 0d662b29633d16176291d11a2d85ba5107cf7de3 RUN bundle install --without development RUN mkdir /config && touch /config/config.yml && ln -s /config/config.yml ./config.yml -CMD ["bundle", "exec", "bin/server"] +CMD ["bundle", "exec", "rackup", "-p4567"] diff --git a/deployments/monitoring/docker-compose.yml b/deployments/monitoring/docker-compose.yml index 5456cb76dc..1fa50c68d0 100644 --- a/deployments/monitoring/docker-compose.yml +++ b/deployments/monitoring/docker-compose.yml @@ -1,24 +1,26 @@ version: '3.5' services: prometheus-metrics: - image: prom/prometheus:v2.20.1 + image: prom/prometheus:v2.38.0 volumes: - ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090" grafana-dashboard: - image: grafana/grafana:7.1.3 + image: grafana/grafana:8.2.6 environment: GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASS:-admin} GF_SERVER_ROOT_URL: ${GRAFANA_SERVER_ROOT_URL} GF_SERVER_DOMAIN: ${GRAFANA_SERVER_DOMAIN} volumes: - ./monitoring/grafana/provisioning/:/etc/grafana/provisioning/:ro + - ./monitoring/grafana/dashboards/:/etc/grafana/dashboards/common:ro ports: - "3000:3000" depends_on: - prometheus-metrics + entrypoint: sh -c "echo 'sleeping for 10m' && sleep 600 && /run.sh" grafana-matrix-notifier: build: diff --git a/deployments/monitoring/grafana-matrix/config.yml b/deployments/monitoring/grafana-matrix/config.yml index 645ee708fe..123cf76a80 100644 --- a/deployments/monitoring/grafana-matrix/config.yml +++ b/deployments/monitoring/grafana-matrix/config.yml @@ -1,8 +1,6 @@ --- # Webhook server configuration # Or use the launch options `-o '::' -p 4567` -#bind: '::' -#port: 4567 # Set up your HS connections matrix: @@ -24,7 +22,7 @@ msgtype: m.text # Set up notification ingress rules rules: - name: bridge # Name of the rule - room: "#bridges-workers:matrix.parity.io" # Room or ID + room: "#bridges-rialto-millau-alerts:matrix.parity.io" # Room or ID matrix: matrix-parity-io # The Matrix HS to use - defaults to first one msgtype: m.notice # The following values are optional: diff --git a/deployments/monitoring/grafana/dashboards/nodes.json b/deployments/monitoring/grafana/dashboards/nodes.json new file mode 100644 index 0000000000..db14c3cf1f --- /dev/null +++ b/deployments/monitoring/grafana/dashboards/nodes.json @@ -0,0 +1,200 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "Running nodes", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "15m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "3m", + "frequency": "1m", + "handler": 1, + "name": "Nodes are not running", + "noDataState": "alerting", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "interval": null, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "maxDataPoints": null, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "up", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Running nodes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:111", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:112", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "", + "schemaVersion": 32, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Running nodes", + "uid": "DHl-xSW4z", + "version": 1 +} diff --git a/deployments/networks/dashboard/grafana/beefy-dashboard.json b/deployments/networks/dashboard/grafana/beefy-dashboard.json index 0216e14554..a5df3449e6 100644 --- a/deployments/networks/dashboard/grafana/beefy-dashboard.json +++ b/deployments/networks/dashboard/grafana/beefy-dashboard.json @@ -23,24 +23,47 @@ "conditions": [ { "evaluator": { - "params": [ - 1 - ], - "type": "lt" + "params": [ + 1 + ], + "type": "lt" }, "operator": { - "type": "and" + "type": "and" }, "query": { - "params": [ - "C", - "5m", - "now" - ] + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "D", + "5m", + "now" + ] }, "reducer": { - "params": [], - "type": "max" + "params": [], + "type": "max" }, "type": "query" } @@ -113,23 +136,23 @@ "steppedLine": false, "targets": [ { - "expr": "polkadot_beefy_best_block", + "expr": "substrate_beefy_best_block{chain=\"rialto_local\"}", "legendFormat": "Rialto(Charlie)", "refId": "A" }, { - "expr": "substrate_beefy_best_block", + "expr": "substrate_beefy_best_block{chain=\"millau_local\"}", "legendFormat": "Millau(Charlie)", "refId": "B" }, { - "expr": "max_over_time(substrate_beefy_best_block[5m]) - min_over_time(substrate_beefy_best_block[5m])", + "expr": "max_over_time(substrate_beefy_best_block{chain=\"millau_local\"}[5m]) - min_over_time(substrate_beefy_best_block{chain=\"millau_local\"}[5m])", "hide": true, "legendFormat": "Millau Best Beefy blocks count in last 5 minutes", "refId": "C" }, { - "expr": "max_over_time(polkadot_beefy_best_block[5m]) - min_over_time(polkadot_beefy_best_block[5m])", + "expr": "max_over_time(substrate_beefy_best_block{chain=\"rialto_local\"}[5m]) - min_over_time(substrate_beefy_best_block{chain=\"rialto_local\"}[5m])", "hide": true, "legendFormat": "Rialto Best Beefy blocks count in last 5 minutes", "refId": "D" @@ -230,22 +253,22 @@ "pluginVersion": "7.1.3", "targets": [ { - "expr": "polkadot_beefy_should_vote_on", + "expr": "substrate_beefy_should_vote_on{chain=\"rialto_local\"}", "legendFormat": "Rialto(Charlie) Should-Vote-On", "refId": "C" }, { - "expr": "polkadot_beefy_round_concluded", + "expr": "substrate_beefy_round_concluded{chain=\"rialto_local\"}", "legendFormat": "Rialto(Charlie) Round-Concluded", "refId": "A" }, { - "expr": "substrate_beefy_should_vote_on", + "expr": "substrate_beefy_should_vote_on{chain=\"millau_local\"}", "legendFormat": "Millau(Charlie) Should-Vote-On", "refId": "D" }, { - "expr": "substrate_beefy_round_concluded", + "expr": "substrate_beefy_round_concluded{chain=\"millau_local\"}", "legendFormat": "Millau(Charlie) Round-Concluded", "refId": "B" } @@ -300,12 +323,12 @@ "steppedLine": false, "targets": [ { - "expr": "polkadot_beefy_votes_sent", + "expr": "substrate_beefy_votes_sent{chain=\"rialto_local\"}", "legendFormat": "Rialto (node Charlie)", "refId": "A" }, { - "expr": "substrate_beefy_votes_sent", + "expr": "substrate_beefy_votes_sent{chain=\"millau_local\"}", "legendFormat": "Millau (node Charlie)", "refId": "B" } @@ -355,6 +378,29 @@ "alert": { "alertRuleTags": {}, "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, { "evaluator": { "params": [ @@ -383,7 +429,7 @@ "for": "5m", "frequency": "1m", "handler": 1, - "name": "Beefy Skipped Sessions alert", + "name": "Beefy Lagging Sessions alert", "noDataState": "no_data", "notifications": [] }, @@ -447,12 +493,12 @@ "steppedLine": false, "targets": [ { - "expr": "polkadot_beefy_skipped_sessions", + "expr": "substrate_beefy_lagging_sessions{chain=\"rialto_local\"}", "legendFormat": "Rialto(Charlie)", "refId": "A" }, { - "expr": "substrate_beefy_skipped_sessions", + "expr": "substrate_beefy_lagging_sessions{chain=\"millau_local\"}", "legendFormat": "Millau(Charlie)", "refId": "B" } @@ -469,7 +515,7 @@ "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Beefy Skipped Sessions", + "title": "Beefy Lagging Sessions", "tooltip": { "shared": true, "sort": 0, diff --git a/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh b/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh index 519ab228e9..bb201ac5da 100755 --- a/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh +++ b/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh @@ -8,4 +8,4 @@ sleep 15 --parachain-port 9944 \ --relaychain-host rialto-node-alice \ --relaychain-port 9944 \ - --relaychain-signer //Alice + --relaychain-signer //Sudo diff --git a/deployments/networks/millau.yml b/deployments/networks/millau.yml index 13ac8d4877..6c57a3863e 100644 --- a/deployments/networks/millau.yml +++ b/deployments/networks/millau.yml @@ -8,7 +8,7 @@ version: '3.5' services: millau-node-alice: &millau-bridge-node - image: paritytech/millau-bridge-node + image: ${MILLAU_BRIDGE_NODE_IMAGE:-paritytech/millau-bridge-node} entrypoint: - /home/user/millau-bridge-node - --execution=Native diff --git a/deployments/networks/rialto-parachain.yml b/deployments/networks/rialto-parachain.yml index b2d2188f1b..c6dab73ff7 100644 --- a/deployments/networks/rialto-parachain.yml +++ b/deployments/networks/rialto-parachain.yml @@ -5,7 +5,7 @@ version: '3.5' services: rialto-parachain-collator-alice: &rialto-parachain-collator - image: paritytech/rialto-parachain-collator + image: ${RIALTO_PARACHAIN_COLLATOR_IMAGE:-paritytech/rialto-parachain-collator} entrypoint: > /home/user/rialto-parachain-collator --alice @@ -25,7 +25,7 @@ services: volumes: - rialto-share:/rialto-share:z environment: - RUST_LOG: runtime=trace,rpc=trace,txpool=trace,parachain=trace,parity_ws=trace + RUST_LOG: runtime=trace,rpc=trace,txpool=trace,parachain=trace,parity_ws=trace,sc_basic_authorship=trace depends_on: - rialto-chainspec-exporter ports: @@ -77,7 +77,7 @@ services: - "20644:9944" rialto-parachain-registrar: - image: paritytech/substrate-relay + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} entrypoint: /entrypoints/rialto-parachain-registrar-entrypoint.sh volumes: - ./networks/entrypoints:/entrypoints diff --git a/deployments/networks/rialto.yml b/deployments/networks/rialto.yml index 40e881a37c..1e2bdd3e41 100644 --- a/deployments/networks/rialto.yml +++ b/deployments/networks/rialto.yml @@ -8,7 +8,7 @@ version: '3.5' services: rialto-node-alice: &rialto-bridge-node - image: paritytech/rialto-bridge-node + image: ${RIALTO_BRIDGE_NODE_IMAGE:-paritytech/rialto-bridge-node} entrypoint: - /home/user/rialto-bridge-node - --execution=Native @@ -94,7 +94,7 @@ services: - "10344:9944" rialto-chainspec-exporter: - image: paritytech/rialto-bridge-node + image: ${RIALTO_BRIDGE_NODE_IMAGE:-paritytech/rialto-bridge-node} entrypoint: /entrypoints/rialto-chainspec-exporter-entrypoint.sh volumes: - ./networks/entrypoints:/entrypoints diff --git a/deployments/reverse-proxy/docker-compose.yml b/deployments/reverse-proxy/docker-compose.yml index 61c9505ae5..ee49e96afd 100644 --- a/deployments/reverse-proxy/docker-compose.yml +++ b/deployments/reverse-proxy/docker-compose.yml @@ -16,6 +16,7 @@ services: - dhparam:/etc/nginx/dhparam - certs:/etc/nginx/certs:ro - /var/run/docker.sock:/tmp/docker.sock:ro + - acme:/etc/acme.sh letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion @@ -27,6 +28,7 @@ services: volumes: - certs:/etc/nginx/certs:rw - /var/run/docker.sock:/var/run/docker.sock:ro + - acme:/etc/acme.sh volumes: conf: @@ -34,6 +36,7 @@ volumes: html: dhparam: certs: + acme: networks: nginx-proxy: diff --git a/deployments/run.sh b/deployments/run.sh index 5c1cded1e8..bbae473317 100755 --- a/deployments/run.sh +++ b/deployments/run.sh @@ -30,20 +30,33 @@ function show_help () { echo Error: $1 echo " " echo "Usage:" - echo " ./run.sh rialto-millau [stop|update] Run Rialto <> Millau Networks & Bridge" - echo " ./run.sh westend-millau [stop|update] Run Westend -> Millau Networks & Bridge" + echo " ./run.sh rialto-millau [stop|update] Run Rialto <> Millau Networks & Bridge" + echo " ./run.sh rialto-parachain-millau [stop|update] Run RialtoParachain <> Millau Networks & Bridge" + echo " ./run.sh westend-millau [stop|update] Run Westend -> Millau Networks & Bridge" + echo " ./run.sh everything|all [stop|update] Run all available Networks & Bridges" echo " " echo "Options:" echo " --no-monitoring Disable monitoring" echo " --no-ui Disable UI" + echo " --local Use prebuilt local images when starting relay and nodes" + echo " --local-substrate-relay Use prebuilt local/substrate-realy image when starting relay" + echo " --local-rialto Use prebuilt local/rialto-bridge-node image when starting nodes" + echo " --local-rialto-parachain Use prebuilt local/rialto-parachain-collator image when starting nodes" + echo " --local-millau Use prebuilt local/millau-bridge-node image when starting nodes" echo " " echo "You can start multiple bridges at once by passing several bridge names:" - echo " ./run.sh rialto-millau westend-millau [stop|update]" + echo " ./run.sh rialto-millau rialto-parachain-millau westend-millau [stop|update]" exit 1 } -RIALTO=' -f ./networks/rialto.yml -f ./networks/rialto-parachain.yml' +RIALTO=' -f ./networks/rialto.yml' +RIALTO_PARACHAIN=' -f ./networks/rialto-parachain.yml' MILLAU=' -f ./networks/millau.yml' + +RIALTO_MILLAU='rialto-millau' +RIALTO_PARACHAIN_MILLAU='rialto-parachain-millau' +WESTEND_MILLAU='westend-millau' + MONITORING=' -f ./monitoring/docker-compose.yml' UI=' -f ./ui/docker-compose.yml' @@ -63,18 +76,56 @@ do shift continue ;; + --local) + export SUBSTRATE_RELAY_IMAGE=local/substrate-relay + export RIALTO_BRIDGE_NODE_IMAGE=local/rialto-bridge-node + export RIALTO_PARACHAIN_COLLATOR_IMAGE=local/rialto-parachain-collator + export MILLAU_BRIDGE_NODE_IMAGE=local/millau-bridge-node + shift + continue + ;; + --local-substrate-relay) + export SUBSTRATE_RELAY_IMAGE=local/substrate-relay + shift + continue + ;; + --local-rialto) + export RIALTO_BRIDGE_NODE_IMAGE=local/rialto-bridge-node + shift + continue + ;; + --local-rialto-parachain) + export RIALTO_PARACHAIN_COLLATOR_IMAGE=local/rialto-parachain-collator + shift + continue + ;; + --local-millau) + export MILLAU_BRIDGE_NODE_IMAGE=local/millau-bridge-node + shift + continue + ;; + everything|all) + BRIDGES=(${RIALTO_MILLAU:-} ${RIALTO_PARACHAIN_MILLAU:-} ${WESTEND_MILLAU:-}) + NETWORKS="${RIALTO:-} ${RIALTO_PARACHAIN:-} ${MILLAU:-}" + unset RIALTO RIALTO_PARACHAIN MILLAU RIALTO_MILLAU RIALTO_PARACHAIN_MILLAU WESTEND_MILLAU + shift + ;; rialto-millau) - BRIDGES+=($i) - NETWORKS+=${RIALTO} - RIALTO='' - NETWORKS+=${MILLAU} - MILLAU='' + BRIDGES+=(${RIALTO_MILLAU:-}) + NETWORKS+="${RIALTO:-} ${MILLAU:-}" + unset RIALTO MILLAU RIALTO_MILLAU + shift + ;; + rialto-parachain-millau) + BRIDGES+=(${RIALTO_PARACHAIN_MILLAU:-}) + NETWORKS+="${RIALTO:-} ${RIALTO_PARACHAIN:-} ${MILLAU:-}" + unset RIALTO RIALTO_PARACHAIN MILLAU RIALTO_PARACHAIN_MILLAU shift ;; westend-millau) - BRIDGES+=($i) - NETWORKS+=${MILLAU} - MILLAU='' + BRIDGES+=(${WESTEND_MILLAU:-}) + NETWORKS+=${MILLAU:-} + unset MILLAU WESTEND_MILLAU shift ;; start|stop|update) diff --git a/deployments/types-rococo.json b/deployments/types-rococo.json deleted file mode 100644 index 6f4592a8d5..0000000000 --- a/deployments/types-rococo.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "--1": "Rococo Types", - "RococoAddress": "AccountId", - "RococoLookupSource": "AccountId", - "RococoBalance": "u128", - "RococoBlockHash": "H256", - "RococoBlockNumber": "u32", - "RococoHeader": "Header", - "--2": "Wococo Types", - "WococoAddress": "AccountId", - "WococoLookupSource": "AccountId", - "WococoBalance": "RococoBalance", - "WococoBlockHash": "RococoBlockHash", - "WococoBlockNumber": "RococoBlockNumber", - "WococoHeader": "RococoHeader", - "--3": "Common types", - "AccountSigner": "MultiSigner", - "SpecVersion": "u32", - "RelayerId": "AccountId", - "SourceAccountId": "AccountId", - "ImportedHeader": { - "header": "BridgedHeader", - "requires_justification": "bool", - "is_finalized": "bool", - "signal_hash": "Option" - }, - "AuthoritySet": { - "authorities": "AuthorityList", - "set_id": "SetId" - }, - "Id": "[u8; 4]", - "ChainId": "Id", - "LaneId": "Id", - "MessageNonce": "u64", - "BridgeMessageId": "(Id, u64)", - "MessageKey": { - "lane_id": "LaneId", - "nonce:": "MessageNonce" - }, - "InboundRelayer": "AccountId", - "InboundLaneData": { - "relayers": "Vec", - "last_confirmed_nonce": "MessageNonce" - }, - "UnrewardedRelayer": { - "relayer": "RelayerId", - "messages": "DeliveredMessages" - }, - "DeliveredMessages": { - "begin": "MessageNonce", - "end": "MessageNonce", - "dispatch_results": "BitVec" - }, - "OutboundLaneData": { - "oldest_unpruned_nonce": "MessageNonce", - "latest_received_nonce": "MessageNonce", - "latest_generated_nonce": "MessageNonce" - }, - "MessageData": { - "payload": "MessagePayload", - "fee": "Fee" - }, - "MessagePayload": "Vec", - "BridgedOpaqueCall": "Vec", - "OutboundMessageFee": "Fee", - "OutboundPayload": { - "spec_version": "SpecVersion", - "weight": "Weight", - "origin": "CallOrigin", - "dispatch_fee_payment": "DispatchFeePayment", - "call": "BridgedOpaqueCall" - }, - "CallOrigin": { - "_enum": { - "SourceRoot": "()", - "TargetAccount": "(SourceAccountId, MultiSigner, MultiSignature)", - "SourceAccount": "SourceAccountId" - } - }, - "DispatchFeePayment": { - "_enum": { - "AtSourceChain": "()", - "AtTargetChain": "()" - } - }, - "MultiSigner": { - "_enum": { - "Ed25519": "H256", - "Sr25519": "H256", - "Ecdsa": "[u8;33]" - } - }, - "MessagesProofOf": { - "bridged_header_hash": "BridgedBlockHash", - "storage_proof": "Vec", - "lane": "LaneId", - "nonces_start": "MessageNonce", - "nonces_end": "MessageNonce" - }, - "StorageProofItem": "Vec", - "MessagesDeliveryProofOf": { - "bridged_header_hash": "BridgedBlockHash", - "storage_proof": "Vec", - "lane": "LaneId" - }, - "UnrewardedRelayersState": { - "unrewarded_relayer_entries": "MessageNonce", - "messages_in_oldest_entry": "MessageNonce", - "total_messages": "MessageNonce" - }, - "AncestryProof": "()", - "MessageFeeData": { - "lane_id": "LaneId", - "payload": "OutboundPayload" - }, - "Precommit": { - "target_hash": "BridgedBlockHash", - "target_number": "BridgedBlockNumber" - }, - "AuthoritySignature": "[u8;64]", - "AuthorityId": "[u8;32]", - "SignedPrecommit": { - "precommit": "Precommit", - "signature": "AuthoritySignature", - "id": "AuthorityId" - }, - "Commit": { - "target_hash": "BridgedBlockHash", - "target_number": "BridgedBlockNumber", - "precommits": "Vec" - }, - "GrandpaJustification": { - "round": "u64", - "commit": "Commit", - "votes_ancestries": "Vec" - }, - "Address": "RococoAddress", - "LookupSource": "RococoLookupSource", - "Fee": "RococoBalance", - "Balance": "RococoBalance", - "BlockHash": "RococoBlockHash", - "BlockNumber": "RococoBlockNumber", - "BridgedBlockHash": "WococoBlockHash", - "BridgedBlockNumber": "WococoBlockNumber", - "BridgedHeader": "WococoHeader", - "Parameter": { - "_enum": { - "RococoToWococoConversionRate": "u128" - } - } -} diff --git a/deployments/types-wococo.json b/deployments/types-wococo.json deleted file mode 100644 index 562f08afa9..0000000000 --- a/deployments/types-wococo.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "--1": "Rococo Types", - "RococoAddress": "AccountId", - "RococoLookupSource": "AccountId", - "RococoBalance": "u128", - "RococoBlockHash": "H256", - "RococoBlockNumber": "u32", - "RococoHeader": "Header", - "--2": "Wococo Types", - "WococoAddress": "AccountId", - "WococoLookupSource": "AccountId", - "WococoBalance": "RococoBalance", - "WococoBlockHash": "RococoBlockHash", - "WococoBlockNumber": "RococoBlockNumber", - "WococoHeader": "RococoHeader", - "--3": "Common types", - "AccountSigner": "MultiSigner", - "SpecVersion": "u32", - "RelayerId": "AccountId", - "SourceAccountId": "AccountId", - "ImportedHeader": { - "header": "BridgedHeader", - "requires_justification": "bool", - "is_finalized": "bool", - "signal_hash": "Option" - }, - "AuthoritySet": { - "authorities": "AuthorityList", - "set_id": "SetId" - }, - "Id": "[u8; 4]", - "ChainId": "Id", - "LaneId": "Id", - "MessageNonce": "u64", - "BridgeMessageId": "(Id, u64)", - "MessageKey": { - "lane_id": "LaneId", - "nonce:": "MessageNonce" - }, - "InboundRelayer": "AccountId", - "InboundLaneData": { - "relayers": "Vec", - "last_confirmed_nonce": "MessageNonce" - }, - "UnrewardedRelayer": { - "relayer": "RelayerId", - "messages": "DeliveredMessages" - }, - "DeliveredMessages": { - "begin": "MessageNonce", - "end": "MessageNonce", - "dispatch_results": "BitVec" - }, - "OutboundLaneData": { - "oldest_unpruned_nonce": "MessageNonce", - "latest_received_nonce": "MessageNonce", - "latest_generated_nonce": "MessageNonce" - }, - "MessageData": { - "payload": "MessagePayload", - "fee": "Fee" - }, - "MessagePayload": "Vec", - "BridgedOpaqueCall": "Vec", - "OutboundMessageFee": "Fee", - "OutboundPayload": { - "spec_version": "SpecVersion", - "weight": "Weight", - "origin": "CallOrigin", - "dispatch_fee_payment": "DispatchFeePayment", - "call": "BridgedOpaqueCall" - }, - "CallOrigin": { - "_enum": { - "SourceRoot": "()", - "TargetAccount": "(SourceAccountId, MultiSigner, MultiSignature)", - "SourceAccount": "SourceAccountId" - } - }, - "DispatchFeePayment": { - "_enum": { - "AtSourceChain": "()", - "AtTargetChain": "()" - } - }, - "MultiSigner": { - "_enum": { - "Ed25519": "H256", - "Sr25519": "H256", - "Ecdsa": "[u8;33]" - } - }, - "MessagesProofOf": { - "bridged_header_hash": "BridgedBlockHash", - "storage_proof": "Vec", - "lane": "LaneId", - "nonces_start": "MessageNonce", - "nonces_end": "MessageNonce" - }, - "StorageProofItem": "Vec", - "MessagesDeliveryProofOf": { - "bridged_header_hash": "BridgedBlockHash", - "storage_proof": "Vec", - "lane": "LaneId" - }, - "UnrewardedRelayersState": { - "unrewarded_relayer_entries": "MessageNonce", - "messages_in_oldest_entry": "MessageNonce", - "total_messages": "MessageNonce" - }, - "AncestryProof": "()", - "MessageFeeData": { - "lane_id": "LaneId", - "payload": "OutboundPayload" - }, - "Precommit": { - "target_hash": "BridgedBlockHash", - "target_number": "BridgedBlockNumber" - }, - "AuthoritySignature": "[u8;64]", - "AuthorityId": "[u8;32]", - "SignedPrecommit": { - "precommit": "Precommit", - "signature": "AuthoritySignature", - "id": "AuthorityId" - }, - "Commit": { - "target_hash": "BridgedBlockHash", - "target_number": "BridgedBlockNumber", - "precommits": "Vec" - }, - "GrandpaJustification": { - "round": "u64", - "commit": "Commit", - "votes_ancestries": "Vec" - }, - "Address": "WococoAddress", - "LookupSource": "WococoLookupSource", - "Fee": "WococoBalance", - "Balance": "WococoBalance", - "Hash": "WococoBlockHash", - "BlockHash": "WococoBlockHash", - "BlockNumber": "WococoBlockNumber", - "BridgedBlockHash": "RococoBlockHash", - "BridgedBlockNumber": "RococoBlockNumber", - "BridgedHeader": "RococoHeader", - "Parameter": { - "_enum": { - "WococoToRococoConversionRate": "u128" - } - } -} diff --git a/deployments/types/build.sh b/deployments/types/build.sh index 1bcfd23ee0..be96459a6d 100755 --- a/deployments/types/build.sh +++ b/deployments/types/build.sh @@ -4,7 +4,7 @@ # JS clients. # # It works by creating definitions for each side of the different bridge pairs we support -# (Rialto<>Millau and Rococo<>Wococo at the moment). +# (Rialto<>Millau at the moment). # # To avoid duplication each bridge pair has a JSON file with common definitions, as well as a # general JSON file with common definitions regardless of the bridge pair. These files are then @@ -15,8 +15,6 @@ set -eux # Make sure we are in the right dir. cd $(dirname $(realpath $0)) -# Create types for our supported bridge pairs (Rialto<>Millau, Rococo<>Wococo) +# Create types for our supported bridge pairs (Rialto<>Millau) jq -s '.[0] * .[1] * .[2]' rialto-millau.json common.json rialto.json > ../types-rialto.json jq -s '.[0] * .[1] * .[2]' rialto-millau.json common.json millau.json > ../types-millau.json -jq -s '.[0] * .[1] * .[2]' rococo-wococo.json common.json rococo.json > ../types-rococo.json -jq -s '.[0] * .[1] * .[2]' rococo-wococo.json common.json wococo.json > ../types-wococo.json diff --git a/deployments/types/rococo-wococo.json b/deployments/types/rococo-wococo.json deleted file mode 100644 index e0864c2ffb..0000000000 --- a/deployments/types/rococo-wococo.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "--1": "Rococo Types", - "RococoAddress": "AccountId", - "RococoLookupSource": "AccountId", - "RococoBalance": "u128", - "RococoBlockHash": "H256", - "RococoBlockNumber": "u32", - "RococoHeader": "Header", - "--2": "Wococo Types", - "WococoAddress": "AccountId", - "WococoLookupSource": "AccountId", - "WococoBalance": "RococoBalance", - "WococoBlockHash": "RococoBlockHash", - "WococoBlockNumber": "RococoBlockNumber", - "WococoHeader": "RococoHeader" -} diff --git a/deployments/types/rococo.json b/deployments/types/rococo.json deleted file mode 100644 index fa1bf27500..0000000000 --- a/deployments/types/rococo.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "Address": "RococoAddress", - "LookupSource": "RococoLookupSource", - "Fee": "RococoBalance", - "Balance": "RococoBalance", - "BlockHash": "RococoBlockHash", - "BlockNumber": "RococoBlockNumber", - "BridgedBlockHash": "WococoBlockHash", - "BridgedBlockNumber": "WococoBlockNumber", - "BridgedHeader": "WococoHeader", - "Parameter": { - "_enum": { - "RococoToWococoConversionRate": "u128" - } - } -} diff --git a/deployments/types/wococo.json b/deployments/types/wococo.json deleted file mode 100644 index 7c7b4ff276..0000000000 --- a/deployments/types/wococo.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "Address": "WococoAddress", - "LookupSource": "WococoLookupSource", - "Fee": "WococoBalance", - "Balance": "WococoBalance", - "Hash": "WococoBlockHash", - "BlockHash": "WococoBlockHash", - "BlockNumber": "WococoBlockNumber", - "BridgedBlockHash": "RococoBlockHash", - "BridgedBlockNumber": "RococoBlockNumber", - "BridgedHeader": "RococoHeader", - "Parameter": { - "_enum": { - "WococoToRococoConversionRate": "u128" - } - } -} diff --git a/fuzz/storage-proof/Cargo.lock b/fuzz/storage-proof/Cargo.lock index e303f3a887..1c40a1a0d3 100644 --- a/fuzz/storage-proof/Cargo.lock +++ b/fuzz/storage-proof/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -12,30 +14,35 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.14.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ "gimli", ] [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.4.7" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.7", + "once_cell", + "version_check", +] [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -57,9 +64,9 @@ checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "arbitrary" -version = "0.4.7" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" +checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490" [[package]] name = "arrayref" @@ -82,57 +89,98 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "async-trait" -version = "0.1.42" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.56" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", - "cfg-if 1.0.0", + "cc", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base58" -version = "0.1.0" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "0.17.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" dependencies = [ - "either", + "funty", "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +dependencies = [ + "digest 0.10.3", ] [[package]] @@ -154,7 +202,7 @@ dependencies = [ "block-padding", "byte-tools", "byteorder", - "generic-array 0.12.3", + "generic-array 0.12.4", ] [[package]] @@ -167,26 +215,21 @@ dependencies = [ ] [[package]] -name = "block-padding" -version = "0.1.5" +name = "block-buffer" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "byte-tools", + "generic-array 0.14.4", ] [[package]] -name = "bp-header-chain" -version = "0.1.0" +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "finality-grandpa", - "frame-support", - "parity-scale-codec", - "serde", - "sp-core", - "sp-finality-grandpa", - "sp-runtime", - "sp-std", + "byte-tools", ] [[package]] @@ -194,30 +237,31 @@ name = "bp-runtime" version = "0.1.0" dependencies = [ "frame-support", + "frame-system", + "hash-db", "num-traits", "parity-scale-codec", + "scale-info", + "serde", "sp-core", "sp-io", "sp-runtime", + "sp-state-machine", "sp-std", + "sp-trie", ] [[package]] -name = "bp-test-utils" -version = "0.1.0" -dependencies = [ - "bp-header-chain", - "finality-grandpa", - "sp-finality-grandpa", - "sp-keyring", - "sp-runtime", -] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byte-slice-cast" -version = "0.3.5" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" +checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" [[package]] name = "byte-tools" @@ -232,10 +276,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] -name = "cfg-if" -version = "0.1.10" +name = "cc" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" @@ -252,18 +296,14 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time", "winapi", ] [[package]] -name = "cloudabi" -version = "0.0.3" +name = "const-oid" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" [[package]] name = "constant_time_eq" @@ -272,10 +312,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] -name = "cpuid-bool" -version = "0.1.2" +name = "cpufeatures" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] [[package]] name = "crunchy" @@ -284,13 +327,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] -name = "crypto-mac" -version = "0.7.0" +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.4", + "rand_core 0.6.1", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" dependencies = [ - "generic-array 0.12.3", - "subtle 1.0.0", + "generic-array 0.14.4", + "typenum", ] [[package]] @@ -300,7 +355,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.4", - "subtle 2.4.0", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.4", + "subtle", ] [[package]] @@ -312,7 +377,7 @@ dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle 2.4.0", + "subtle", "zeroize", ] @@ -325,10 +390,19 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.4.0", + "subtle", "zeroize", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derive_more" version = "0.99.11" @@ -346,7 +420,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3", + "generic-array 0.12.4", ] [[package]] @@ -358,6 +432,23 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -385,6 +476,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "ed25519" version = "1.0.3" @@ -404,7 +507,7 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2 0.9.2", + "sha2 0.9.9", "zeroize", ] @@ -414,11 +517,42 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array 0.14.4", + "group", + "rand_core 0.6.1", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "environmental" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6576a1755ddffd988788025e75bce9e74b018f7cc226198fe931d077911c6d7e" +checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" [[package]] name = "fake-simd" @@ -427,18 +561,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] -name = "finality-grandpa" -version = "0.12.3" +name = "ff" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" dependencies = [ - "either", - "futures", - "futures-timer", - "log", - "num-traits", - "parity-scale-codec", - "parking_lot 0.9.0", + "rand_core 0.6.1", + "subtle", ] [[package]] @@ -455,44 +584,50 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "12.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" dependencies = [ + "cfg-if", "parity-scale-codec", + "scale-info", "serde", - "sp-core", - "sp-std", ] [[package]] name = "frame-support" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "bitflags", "frame-metadata", "frame-support-procedural", "impl-trait-for-tuples", + "k256", "log", "once_cell", "parity-scale-codec", "paste", + "scale-info", "serde", - "smallvec 1.6.1", + "smallvec", "sp-arithmetic", "sp-core", + "sp-core-hashing-proc-macro", "sp-inherents", "sp-io", "sp-runtime", + "sp-staking", "sp-state-machine", "sp-std", "sp-tracing", + "tt-call", ] [[package]] name = "frame-support-procedural" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -503,8 +638,8 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -515,8 +650,8 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "3.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "proc-macro2", "quote", @@ -525,12 +660,13 @@ dependencies = [ [[package]] name = "frame-system" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "frame-support", - "impl-trait-for-tuples", + "log", "parity-scale-codec", + "scale-info", "serde", "sp-core", "sp-io", @@ -539,11 +675,17 @@ dependencies = [ "sp-version", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -556,9 +698,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -566,15 +708,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -584,17 +726,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -602,30 +743,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" -dependencies = [ - "once_cell", -] - -[[package]] -name = "futures-timer" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.12" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-channel", "futures-core", @@ -636,16 +768,14 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] [[package]] name = "generic-array" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ "typenum", ] @@ -666,27 +796,40 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.10.1+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "gimli" -version = "0.23.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.1", + "subtle", +] [[package]] name = "hash-db" @@ -705,22 +848,13 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" dependencies = [ "ahash", ] -[[package]] -name = "heck" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "hermit-abi" version = "0.1.18" @@ -738,51 +872,57 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "hmac" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac 0.7.0", - "digest 0.8.1", + "crypto-mac 0.8.0", + "digest 0.9.0", ] [[package]] name = "hmac" -version = "0.8.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.8.0", + "crypto-mac 0.11.1", "digest 0.9.0", ] [[package]] name = "hmac-drbg" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ - "digest 0.8.1", - "generic-array 0.12.3", - "hmac 0.7.1", + "digest 0.9.0", + "generic-array 0.14.4", + "hmac 0.8.1", ] [[package]] name = "honggfuzz" -version = "0.5.52" +version = "0.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ead88897bcad1c396806d6ccba260a0363e11da997472e9e19ab9889969083a2" +checksum = "bea09577d948a98a5f59b7c891e274c4fb35ad52f67782b3d0cb53b9c05301f1" dependencies = [ "arbitrary", "lazy_static", "memmap", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "impl-codec" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ "parity-scale-codec", ] @@ -798,24 +938,15 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f65a8ecf74feeacdab8d38cb129e550ca871cccaa7d1921d8636ecd75534903" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "instant" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "integer-sqrt" version = "0.1.5" @@ -831,6 +962,33 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sec1", +] + [[package]] name = "keccak" version = "0.1.0" @@ -845,51 +1003,75 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libsecp256k1" -version = "0.3.5" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" +checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" dependencies = [ "arrayref", - "crunchy", - "digest 0.8.1", + "base64", + "digest 0.9.0", "hmac-drbg", - "rand 0.7.3", - "sha2 0.8.2", - "subtle 2.4.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.2", + "serde", + "sha2 0.9.9", "typenum", ] [[package]] -name = "lock_api" -version = "0.3.4" +name = "libsecp256k1-core" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ - "scopeguard", + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", ] [[package]] name = "lock_api" -version = "0.4.2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.13" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -901,17 +1083,11 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "memchr" -version = "2.3.4" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap" @@ -925,9 +1101,9 @@ dependencies = [ [[package]] name = "memory-db" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbd2a22f201c03cc1706a727842490abfea17b7b53260358239828208daba3c" +checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" dependencies = [ "hash-db", "hashbrown", @@ -954,12 +1130,11 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", - "autocfg", ] [[package]] @@ -979,6 +1154,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-format" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" +dependencies = [ + "arrayvec 0.4.12", + "itoa 0.4.7", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -1022,18 +1207,18 @@ dependencies = [ [[package]] name = "object" -version = "0.23.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] [[package]] name = "once_cell" -version = "1.5.2" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" -dependencies = [ - "parking_lot 0.11.1", -] +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "opaque-debug" @@ -1047,42 +1232,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "pallet-substrate-bridge" -version = "0.1.0" -dependencies = [ - "bp-header-chain", - "bp-runtime", - "finality-grandpa", - "frame-support", - "frame-system", - "hash-db", - "parity-scale-codec", - "serde", - "sp-finality-grandpa", - "sp-runtime", - "sp-std", - "sp-trie", -] - [[package]] name = "parity-scale-codec" -version = "1.3.6" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79602888a81ace83e3d1d4b2873286c1f5f906c84db667594e8db8da3506c383" +checksum = "e8b44461635bbb1a0300f100a841e571e7d919c81c73075ef5d152ffdb521066" dependencies = [ - "arrayvec 0.5.2", + "arrayvec 0.7.2", "bitvec", "byte-slice-cast", + "impl-trait-for-tuples", "parity-scale-codec-derive", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "1.2.2" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db82bb1c18fc00176004462dd809b2a6d851669550aa17af6dacd21ae0c14" +checksum = "c45ed1f39709f5a89338fab50e59816b2e8815f5bb58276e7ddf9afd495f73f8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1092,15 +1260,15 @@ dependencies = [ [[package]] name = "parity-util-mem" -version = "0.8.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f17f15cb05897127bf36a240085a1f0bbef7bce3024849eccf7f93f6171bc27" +checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "hashbrown", "impl-trait-for-tuples", "parity-util-mem-derive", - "parking_lot 0.11.1", + "parking_lot", "primitive-types", "winapi", ] @@ -1118,97 +1286,55 @@ dependencies = [ [[package]] name = "parity-wasm" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" - -[[package]] -name = "parking_lot" -version = "0.9.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.6.2", - "rustc_version", -] +checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" [[package]] name = "parking_lot" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" -dependencies = [ - "instant", - "lock_api 0.4.2", - "parking_lot_core 0.8.2", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall", - "rustc_version", - "smallvec 0.6.14", - "winapi", + "lock_api", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ - "cfg-if 1.0.0", - "instant", + "cfg-if", "libc", "redox_syscall", - "smallvec 1.6.1", - "winapi", + "smallvec", + "windows-sys", ] [[package]] name = "paste" -version = "0.1.18" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - -[[package]] -name = "paste-impl" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" -dependencies = [ - "proc-macro-hack", -] +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" [[package]] name = "pbkdf2" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" dependencies = [ - "byteorder", - "crypto-mac 0.7.0", + "crypto-mac 0.8.0", ] [[package]] name = "pbkdf2" -version = "0.4.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" dependencies = [ - "crypto-mac 0.8.0", + "crypto-mac 0.11.1", ] [[package]] @@ -1231,60 +1357,50 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "primitive-types" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3824ae2c5e27160113b9e029a10ec9e3f0237bad8029f69c7724393c9fdefd8" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ "fixed-hash", "impl-codec", "impl-serde", + "scale-info", "uint", ] [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ + "thiserror", "toml", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "radium" -version = "0.3.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -1296,7 +1412,7 @@ dependencies = [ "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc", + "rand_hc 0.2.0", "rand_pcg", ] @@ -1309,6 +1425,7 @@ dependencies = [ "libc", "rand_chacha 0.3.0", "rand_core 0.6.1", + "rand_hc 0.3.1", ] [[package]] @@ -1346,7 +1463,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" dependencies = [ - "getrandom 0.2.2", + "getrandom 0.2.7", ] [[package]] @@ -1358,6 +1475,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core 0.6.1", +] + [[package]] name = "rand_pcg" version = "0.2.1" @@ -1369,9 +1495,12 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] [[package]] name = "ref-cast" @@ -1395,14 +1524,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] @@ -1417,9 +1545,20 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] [[package]] name = "rustc-demangle" @@ -1440,19 +1579,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] -name = "rustc_version" -version = "0.2.3" +name = "ryu" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scale-info" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c46be926081c9f4dd5dd9b6f1d3e3229f2360bc6502dd8836f84a93b7c75e99a" dependencies = [ - "semver", + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", ] [[package]] -name = "ryu" -version = "1.0.5" +name = "scale-info-derive" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "50e334bb10a245e28e5fd755cabcafd96cfcd167c99ae63a46924ca8d8703a3c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] [[package]] name = "schnorrkel" @@ -1467,9 +1623,8 @@ dependencies = [ "merlin", "rand 0.7.3", "rand_core 0.5.1", - "serde", "sha2 0.8.2", - "subtle 2.4.0", + "subtle", "zeroize", ] @@ -1480,43 +1635,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "secrecy" -version = "0.7.0" +name = "sec1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0673d6a6449f5e7d12a1caf424fd9363e2af3a4953023ed455e3c4beef4597c0" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" dependencies = [ + "der", + "generic-array 0.14.4", + "subtle", "zeroize", ] [[package]] -name = "semver" -version = "0.9.0" +name = "secp256k1" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260" dependencies = [ - "semver-parser", + "secp256k1-sys", ] [[package]] -name = "semver-parser" -version = "0.7.0" +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] [[package]] name = "serde" -version = "1.0.120" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.120" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" dependencies = [ "proc-macro2", "quote", @@ -1525,11 +1695,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ - "itoa", + "itoa 1.0.2", "ryu", "serde", ] @@ -1548,17 +1718,38 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpuid-bool", + "cfg-if", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sha3" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +dependencies = [ + "digest 0.10.3", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.1" @@ -1570,9 +1761,13 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.1", +] [[package]] name = "slab" @@ -1582,53 +1777,17 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.6.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" - -[[package]] -name = "sp-api" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" -dependencies = [ - "hash-db", - "parity-scale-codec", - "sp-api-proc-macro", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-version", - "thiserror", -] - -[[package]] -name = "sp-api-proc-macro" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" -dependencies = [ - "blake2-rfc", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "sp-application-crypto" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "parity-scale-codec", + "scale-info", "serde", "sp-core", "sp-io", @@ -1637,23 +1796,26 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "integer-sqrt", "num-traits", "parity-scale-codec", + "scale-info", "serde", "sp-debug-derive", "sp-std", + "static_assertions", ] [[package]] name = "sp-core" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "base58", + "bitflags", "blake2-rfc", "byteorder", "dyn-clonable", @@ -1670,89 +1832,101 @@ dependencies = [ "num-traits", "parity-scale-codec", "parity-util-mem", - "parking_lot 0.11.1", + "parking_lot", "primitive-types", "rand 0.7.3", "regex", + "scale-info", "schnorrkel", + "secp256k1", "secrecy", "serde", - "sha2 0.9.2", + "sp-core-hashing", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", "sp-std", "sp-storage", + "ss58-registry", "substrate-bip39", "thiserror", "tiny-bip39", - "tiny-keccak", - "twox-hash", "wasmi", "zeroize", ] [[package]] -name = "sp-debug-derive" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +name = "sp-core-hashing" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "blake2", + "byteorder", + "digest 0.10.3", + "sha2 0.10.2", + "sha3", + "sp-std", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "proc-macro2", "quote", + "sp-core-hashing", "syn", ] [[package]] -name = "sp-externalities" -version = "0.8.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +name = "sp-debug-derive" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ - "environmental", - "parity-scale-codec", - "sp-std", - "sp-storage", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "sp-finality-grandpa" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +name = "sp-externalities" +version = "0.12.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ - "finality-grandpa", - "log", + "environmental", "parity-scale-codec", - "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-keystore", - "sp-runtime", "sp-std", + "sp-storage", ] [[package]] name = "sp-inherents" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ + "async-trait", + "impl-trait-for-tuples", "parity-scale-codec", - "parking_lot 0.11.1", "sp-core", + "sp-runtime", "sp-std", "thiserror", ] [[package]] name = "sp-io" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "futures", "hash-db", "libsecp256k1", "log", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot", + "secp256k1", "sp-core", "sp-externalities", "sp-keystore", @@ -1766,45 +1940,36 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "sp-keyring" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" -dependencies = [ - "lazy_static", - "sp-core", - "sp-runtime", - "strum", -] - [[package]] name = "sp-keystore" -version = "0.8.0" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "0.12.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "async-trait", - "derive_more", "futures", "merlin", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot", "schnorrkel", "sp-core", "sp-externalities", + "thiserror", ] [[package]] name = "sp-panic-handler" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "backtrace", + "lazy_static", + "regex", ] [[package]] name = "sp-runtime" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "either", "hash256-std-hasher", @@ -1814,6 +1979,7 @@ dependencies = [ "parity-util-mem", "paste", "rand 0.7.3", + "scale-info", "serde", "sp-application-crypto", "sp-arithmetic", @@ -1824,8 +1990,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -1841,8 +2007,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "Inflector", "proc-macro-crate", @@ -1851,37 +2017,48 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-staking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-state-machine" -version = "0.8.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "0.12.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "hash-db", "log", "num-traits", "parity-scale-codec", - "parking_lot 0.11.1", + "parking_lot", "rand 0.7.3", - "smallvec 1.6.1", + "smallvec", "sp-core", "sp-externalities", "sp-panic-handler", "sp-std", "sp-trie", "thiserror", - "trie-db", + "tracing", "trie-root", ] [[package]] name = "sp-std" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" [[package]] name = "sp-storage" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "impl-serde", "parity-scale-codec", @@ -1893,10 +2070,9 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ - "log", "parity-scale-codec", "sp-std", "tracing", @@ -1906,99 +2082,90 @@ dependencies = [ [[package]] name = "sp-trie" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "hash-db", "memory-db", "parity-scale-codec", + "scale-info", "sp-core", "sp-std", + "thiserror", "trie-db", "trie-root", ] [[package]] name = "sp-version" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ "impl-serde", "parity-scale-codec", + "parity-wasm", + "scale-info", "serde", + "sp-core-hashing-proc-macro", "sp-runtime", "sp-std", + "sp-version-proc-macro", + "thiserror", ] [[package]] -name = "sp-wasm-interface" -version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#4b687dfb4def2b5eee9f5a20629e3fc3563587ee" +name = "sp-version-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ - "impl-trait-for-tuples", "parity-scale-codec", - "sp-std", - "wasmi", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strum" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22" +name = "sp-wasm-interface" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" dependencies = [ - "strum_macros", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std", + "wasmi", ] [[package]] -name = "strum_macros" -version = "0.16.0" +name = "ss58-registry" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81" +checksum = "77ef98aedad3dc52e10995e7ed15f1279e11d4da35795f5dac7305742d0feb66" dependencies = [ - "heck", + "Inflector", + "num-format", "proc-macro2", "quote", - "syn", + "serde", + "serde_json", + "unicode-xid", ] [[package]] -name = "substrate-bip39" -version = "0.4.2" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed6646a0159b9935b5d045611560eeef842b78d7adc3ba36f5ca325a13a0236" -dependencies = [ - "hmac 0.7.1", - "pbkdf2 0.3.0", - "schnorrkel", - "sha2 0.8.2", - "zeroize", -] +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "substrate-bridge-fuzzer" +name = "storage-proof-fuzzer" version = "0.1.0" dependencies = [ - "bp-header-chain", "bp-runtime", - "bp-test-utils", - "finality-grandpa", - "frame-support", - "frame-system", - "hash-db", + "env_logger", "honggfuzz", - "pallet-substrate-bridge", - "parity-scale-codec", - "serde", + "log", "sp-core", - "sp-finality-grandpa", - "sp-io", "sp-runtime", "sp-state-machine", "sp-std", @@ -2006,10 +2173,17 @@ dependencies = [ ] [[package]] -name = "subtle" -version = "1.0.0" +name = "substrate-bip39" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", + "schnorrkel", + "sha2 0.9.9", + "zeroize", +] [[package]] name = "subtle" @@ -2019,13 +2193,13 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.58" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2040,20 +2214,35 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -2062,28 +2251,18 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "time" -version = "0.1.43" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "libc", - "winapi", + "once_cell", ] [[package]] name = "tiny-bip39" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e44c4759bae7f1032e286a7ef990bd9ed23fe831b7eeba0beb97484c2e59b8" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" dependencies = [ "anyhow", "hmac 0.8.1", @@ -2091,21 +2270,13 @@ dependencies = [ "pbkdf2 0.4.0", "rand 0.7.3", "rustc-hash", - "sha2 0.9.2", + "sha2 0.9.9", "thiserror", "unicode-normalization", + "wasm-bindgen", "zeroize", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinyvec" version = "1.1.0" @@ -2132,11 +2303,11 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.22" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2144,9 +2315,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.11" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -2155,18 +2326,19 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] name = "tracing-log" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ "lazy_static", "log", @@ -2185,9 +2357,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.15" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fa8f0c8f4c594e4fc9debc1990deab13238077271ba84dd853d54902ee3401" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ "ansi_term", "chrono", @@ -2197,7 +2369,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.6.1", + "smallvec", "thread_local", "tracing", "tracing-core", @@ -2207,42 +2379,49 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.22.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc176c377eb24d652c9c69c832c832019011b6106182bf84276c66b66d5c9a6" +checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" dependencies = [ "hash-db", "hashbrown", "log", "rustc-hex", - "smallvec 1.6.1", + "smallvec", ] [[package]] name = "trie-root" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" +checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" dependencies = [ "hash-db", ] +[[package]] +name = "tt-call" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" + [[package]] name = "twox-hash" -version = "1.6.0" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", - "rand 0.7.3", + "cfg-if", + "digest 0.10.3", + "rand 0.8.2", "static_assertions", ] [[package]] name = "typenum" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "uint" @@ -2256,6 +2435,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + [[package]] name = "unicode-normalization" version = "0.1.16" @@ -2266,16 +2451,16 @@ dependencies = [ ] [[package]] -name = "unicode-segmentation" -version = "1.7.1" +name = "unicode-xid" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] -name = "unicode-xid" -version = "0.2.1" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" @@ -2291,16 +2476,71 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.1+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" [[package]] name = "wasmi" -version = "0.6.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff" +checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" dependencies = [ + "downcast-rs", "libc", "memory_units", "num-rational", @@ -2311,9 +2551,9 @@ dependencies = [ [[package]] name = "wasmi-validation" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" +checksum = "165343ecd6c018fc09ebcae280752702c9a2ef3e6f8d02f1cfcbdb53ef6d7937" dependencies = [ "parity-wasm", ] @@ -2334,26 +2574,87 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "wyz" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +dependencies = [ + "tap", +] + [[package]] name = "zeroize" -version = "1.2.0" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" +checksum = "20b578acffd8516a6c3f2a1bdefc1ec37e547bb4e0fb8b6b01a4cafc886b4442" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.0.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", "quote", diff --git a/modules/dispatch/README.md b/modules/dispatch/README.md deleted file mode 100644 index 068ff1167f..0000000000 --- a/modules/dispatch/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Call Dispatch Module - -The call dispatch module has a single internal (only callable by other runtime modules) entry point -for dispatching encoded calls (`pallet_bridge_dispatch::Module::dispatch`). Every dispatch -(successful or not) emits a corresponding module event. The module doesn't have any call-related -requirements - they may come from the bridged chain over some message lane, or they may be crafted -locally. But in this document we'll mostly talk about this module in the context of bridges. - -Every message that is being dispatched has three main characteristics: -- `bridge` is the 4-bytes identifier of the bridge where this message comes from. This may be the - identifier of the bridged chain (like `b"rlto"` for messages coming from `Rialto`), or the - identifier of the bridge itself (`b"rimi"` for `Rialto` <-> `Millau` bridge); -- `id` is the unique id of the message within the given bridge. For messages coming from the - [messages module](../messages/README.md), it may worth to use a tuple - `(LaneId, MessageNonce)` to identify a message; -- `message` is the `bp_message_dispatch::MessagePayload` structure. The `call` field is set - to the (potentially) encoded `Call` of this chain. - -The easiest way to understand what is happening when a `Call` is being dispatched, is to look at the -module events set: - -- `MessageRejected` event is emitted if a message has been rejected even before it has reached the - module. Dispatch then is called just to reflect the fact that message has been received, but we - have failed to pre-process it (e.g. because we have failed to decode `MessagePayload` structure - from the proof); -- `MessageVersionSpecMismatch` event is emitted if current runtime specification version differs - from the version that has been used to encode the `Call`. The message payload has the - `spec_version`, that is filled by the message submitter. If this value differs from the current - runtime version, dispatch mechanism rejects to dispatch the message. Without this check, we may - decode the wrong `Call` for example if method arguments were changed; -- `MessageCallDecodeFailed` event is emitted if we have failed to decode `Call` from the payload. - This may happen if the submitter has provided incorrect value in the `call` field, or if source - chain storage has been corrupted. The `Call` is decoded after `spec_version` check, so we'll never - try to decode `Call` from other runtime version; -- `MessageSignatureMismatch` event is emitted if submitter has chose to dispatch message using - specified this chain account (`bp_message_dispatch::CallOrigin::TargetAccount` origin), - but he has failed to prove that he owns the private key for this account; -- `MessageCallRejected` event is emitted if the module has been deployed with some call filter and - this filter has rejected the `Call`. In your bridge you may choose to reject all messages except - e.g. balance transfer calls; -- `MessageWeightMismatch` event is emitted if the message submitter has specified invalid `Call` - dispatch weight in the `weight` field of the message payload. The value of this field is compared - to the pre-dispatch weight of the decoded `Call`. If it is less than the actual pre-dispatch - weight, the dispatch is rejected. Keep in mind, that even if post-dispatch weight will be less - than specified, the submitter still have to declare (and pay for) the maximal possible weight - (that is the pre-dispatch weight); -- `MessageDispatchPaymentFailed` event is emitted if the message submitter has selected to pay - dispatch fee at the target chain, but has failed to do that; -- `MessageDispatched` event is emitted if the message has passed all checks and we have actually - dispatched it. The dispatch may still fail, though - that's why we are including the dispatch - result in the event payload. - -When we talk about module in context of bridges, these events are helping in following cases: - -1. when the message submitter has access to the state of both chains and wants to monitor what has - happened with his message. Then he could use the message id (that he gets from the - [messages module events](../messages/README.md#General-Information)) to filter events of - call dispatch module at the target chain and actually see what has happened with his message; - -1. when the message submitter only has access to the source chain state (for example, when sender is - the runtime module at the source chain). In this case, your bridge may have additional mechanism - to deliver dispatch proofs (which are storage proof of module events) back to the source chain, - thus allowing the submitter to see what has happened with his messages. diff --git a/modules/dispatch/src/lib.rs b/modules/dispatch/src/lib.rs deleted file mode 100644 index 1e030b7332..0000000000 --- a/modules/dispatch/src/lib.rs +++ /dev/null @@ -1,1084 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Runtime module which takes care of dispatching messages received over the bridge. -//! -//! The messages are interpreted directly as runtime `Call`. We attempt to decode -//! them and then dispatch as usual. To prevent compatibility issues, the Calls have -//! to include a `spec_version`. This will be checked before dispatch. In the case of -//! a successful dispatch an event is emitted. - -#![cfg_attr(not(feature = "std"), no_std)] -// Generated by `decl_event!` -#![allow(clippy::unused_unit)] - -use bp_message_dispatch::{CallOrigin, MessageDispatch, MessagePayload, SpecVersion}; -use bp_runtime::{ - derive_account_id, - messages::{DispatchFeePayment, MessageDispatchResult}, - ChainId, SourceAccount, -}; -use codec::Encode; -use frame_support::{ - dispatch::Dispatchable, - ensure, - traits::{Contains, Get}, - weights::{extract_actual_weight, GetDispatchInfo}, -}; -use frame_system::RawOrigin; -use sp_runtime::traits::{BadOrigin, Convert, IdentifyAccount, MaybeDisplay, Verify}; -use sp_std::{fmt::Debug, prelude::*}; - -pub use pallet::*; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From> + IsType<::Event>; - /// Id of the message. Whenever message is passed to the dispatch module, it emits - /// event with this id + dispatch result. Could be e.g. (LaneId, MessageNonce) if - /// it comes from the messages module. - type BridgeMessageId: Parameter; - /// Type of account ID on source chain. - type SourceChainAccountId: Parameter - + Member - + MaybeSerializeDeserialize - + Debug - + MaybeDisplay - + Ord; - /// Type of account public key on target chain. - type TargetChainAccountPublic: Parameter + IdentifyAccount; - /// Type of signature that may prove that the message has been signed by - /// owner of `TargetChainAccountPublic`. - type TargetChainSignature: Parameter + Verify; - /// The overarching dispatch call type. - type Call: Parameter - + GetDispatchInfo - + Dispatchable< - Origin = ::Origin, - PostInfo = frame_support::dispatch::PostDispatchInfo, - >; - /// Pre-dispatch filter for incoming calls. - /// - /// The pallet will filter all incoming calls right before they're dispatched. If this - /// filter rejects the call, special event (`Event::MessageCallRejected`) is emitted. - type CallFilter: Contains<>::Call>; - /// The type that is used to wrap the `Self::Call` when it is moved over bridge. - /// - /// The idea behind this is to avoid `Call` conversion/decoding until we'll be sure - /// that all other stuff (like `spec_version`) is ok. If we would try to decode - /// `Call` which has been encoded using previous `spec_version`, then we might end - /// up with decoding error, instead of `MessageVersionSpecMismatch`. - type EncodedCall: Decode + Encode + Into>::Call, ()>>; - /// A type which can be turned into an AccountId from a 256-bit hash. - /// - /// Used when deriving target chain AccountIds from source chain AccountIds. - type AccountIdConverter: sp_runtime::traits::Convert; - } - - type BridgeMessageIdOf = >::BridgeMessageId; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(PhantomData<(T, I)>); - - #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet {} - - #[pallet::call] - impl, I: 'static> Pallet {} - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event, I: 'static = ()> { - /// Message has been rejected before reaching dispatch. - MessageRejected(ChainId, BridgeMessageIdOf), - /// Message has been rejected by dispatcher because of spec version mismatch. - /// Last two arguments are: expected and passed spec version. - MessageVersionSpecMismatch(ChainId, BridgeMessageIdOf, SpecVersion, SpecVersion), - /// Message has been rejected by dispatcher because of weight mismatch. - /// Last two arguments are: expected and passed call weight. - MessageWeightMismatch(ChainId, BridgeMessageIdOf, Weight, Weight), - /// Message signature mismatch. - MessageSignatureMismatch(ChainId, BridgeMessageIdOf), - /// We have failed to decode Call from the message. - MessageCallDecodeFailed(ChainId, BridgeMessageIdOf), - /// The call from the message has been rejected by the call filter. - MessageCallRejected(ChainId, BridgeMessageIdOf), - /// The origin account has failed to pay fee for dispatching the message. - MessageDispatchPaymentFailed( - ChainId, - BridgeMessageIdOf, - ::AccountId, - Weight, - ), - /// Message has been dispatched with given result. - MessageDispatched(ChainId, BridgeMessageIdOf, DispatchResult), - /// Phantom member, never used. Needed to handle multiple pallet instances. - _Dummy(PhantomData), - } -} - -impl, I: 'static> MessageDispatch for Pallet { - type Message = MessagePayload< - T::SourceChainAccountId, - T::TargetChainAccountPublic, - T::TargetChainSignature, - T::EncodedCall, - >; - - fn dispatch_weight(message: &Self::Message) -> bp_message_dispatch::Weight { - message.weight - } - - fn dispatch Result<(), ()>>( - source_chain: ChainId, - target_chain: ChainId, - id: T::BridgeMessageId, - message: Result, - pay_dispatch_fee: P, - ) -> MessageDispatchResult { - // emit special even if message has been rejected by external component - let message = match message { - Ok(message) => message, - Err(_) => { - log::trace!( - target: "runtime::bridge-dispatch", - "Message {:?}/{:?}: rejected before actual dispatch", - source_chain, - id, - ); - Self::deposit_event(Event::MessageRejected(source_chain, id)); - return MessageDispatchResult { - dispatch_result: false, - unspent_weight: 0, - dispatch_fee_paid_during_dispatch: false, - } - }, - }; - - // verify spec version - // (we want it to be the same, because otherwise we may decode Call improperly) - let mut dispatch_result = MessageDispatchResult { - dispatch_result: false, - unspent_weight: message.weight, - dispatch_fee_paid_during_dispatch: false, - }; - let expected_version = ::Version::get().spec_version; - if message.spec_version != expected_version { - log::trace!( - "Message {:?}/{:?}: spec_version mismatch. Expected {:?}, got {:?}", - source_chain, - id, - expected_version, - message.spec_version, - ); - Self::deposit_event(Event::MessageVersionSpecMismatch( - source_chain, - id, - expected_version, - message.spec_version, - )); - return dispatch_result - } - - // now that we have spec version checked, let's decode the call - let call = match message.call.into() { - Ok(call) => call, - Err(_) => { - log::trace!( - target: "runtime::bridge-dispatch", - "Failed to decode Call from message {:?}/{:?}", - source_chain, - id, - ); - Self::deposit_event(Event::MessageCallDecodeFailed(source_chain, id)); - return dispatch_result - }, - }; - - // prepare dispatch origin - let origin_account = match message.origin { - CallOrigin::SourceRoot => { - let hex_id = - derive_account_id::(source_chain, SourceAccount::Root); - let target_id = T::AccountIdConverter::convert(hex_id); - log::trace!(target: "runtime::bridge-dispatch", "Root Account: {:?}", &target_id); - target_id - }, - CallOrigin::TargetAccount(source_account_id, target_public, target_signature) => { - let digest = account_ownership_digest( - &call, - source_account_id, - message.spec_version, - source_chain, - target_chain, - ); - - let target_account = target_public.into_account(); - if !target_signature.verify(&digest[..], &target_account) { - log::trace!( - target: "runtime::bridge-dispatch", - "Message {:?}/{:?}: origin proof is invalid. Expected account: {:?} from signature: {:?}", - source_chain, - id, - target_account, - target_signature, - ); - Self::deposit_event(Event::MessageSignatureMismatch(source_chain, id)); - return dispatch_result - } - - log::trace!(target: "runtime::bridge-dispatch", "Target Account: {:?}", &target_account); - target_account - }, - CallOrigin::SourceAccount(source_account_id) => { - let hex_id = - derive_account_id(source_chain, SourceAccount::Account(source_account_id)); - let target_id = T::AccountIdConverter::convert(hex_id); - log::trace!(target: "runtime::bridge-dispatch", "Source Account: {:?}", &target_id); - target_id - }, - }; - - // filter the call - if !T::CallFilter::contains(&call) { - log::trace!( - target: "runtime::bridge-dispatch", - "Message {:?}/{:?}: the call ({:?}) is rejected by filter", - source_chain, - id, - call, - ); - Self::deposit_event(Event::MessageCallRejected(source_chain, id)); - return dispatch_result - } - - // verify weight - // (we want passed weight to be at least equal to pre-dispatch weight of the call - // because otherwise Calls may be dispatched at lower price) - let dispatch_info = call.get_dispatch_info(); - let expected_weight = dispatch_info.weight; - if message.weight < expected_weight { - log::trace!( - target: "runtime::bridge-dispatch", - "Message {:?}/{:?}: passed weight is too low. Expected at least {:?}, got {:?}", - source_chain, - id, - expected_weight, - message.weight, - ); - Self::deposit_event(Event::MessageWeightMismatch( - source_chain, - id, - expected_weight, - message.weight, - )); - return dispatch_result - } - - // pay dispatch fee right before dispatch - let pay_dispatch_fee_at_target_chain = - message.dispatch_fee_payment == DispatchFeePayment::AtTargetChain; - if pay_dispatch_fee_at_target_chain && - pay_dispatch_fee(&origin_account, message.weight).is_err() - { - log::trace!( - target: "runtime::bridge-dispatch", - "Failed to pay dispatch fee for dispatching message {:?}/{:?} with weight {}", - source_chain, - id, - message.weight, - ); - Self::deposit_event(Event::MessageDispatchPaymentFailed( - source_chain, - id, - origin_account, - message.weight, - )); - return dispatch_result - } - dispatch_result.dispatch_fee_paid_during_dispatch = pay_dispatch_fee_at_target_chain; - - // finally dispatch message - let origin = RawOrigin::Signed(origin_account).into(); - - log::trace!(target: "runtime::bridge-dispatch", "Message being dispatched is: {:.4096?}", &call); - let result = call.dispatch(origin); - let actual_call_weight = extract_actual_weight(&result, &dispatch_info); - dispatch_result.dispatch_result = result.is_ok(); - dispatch_result.unspent_weight = message.weight.saturating_sub(actual_call_weight); - - log::trace!( - target: "runtime::bridge-dispatch", - "Message {:?}/{:?} has been dispatched. Weight: {} of {}. Result: {:?}. Call dispatch result: {:?}", - source_chain, - id, - actual_call_weight, - message.weight, - dispatch_result, - result, - ); - - Self::deposit_event(Event::MessageDispatched( - source_chain, - id, - result.map(drop).map_err(|e| e.error), - )); - - dispatch_result - } -} - -/// Check if the message is allowed to be dispatched on the target chain given the sender's origin -/// on the source chain. -/// -/// For example, if a message is sent from a "regular" account on the source chain it will not be -/// allowed to be dispatched as Root on the target chain. This is a useful check to do on the source -/// chain _before_ sending a message whose dispatch will be rejected on the target chain. -pub fn verify_message_origin< - SourceChainAccountId, - TargetChainAccountPublic, - TargetChainSignature, - Call, ->( - sender_origin: &RawOrigin, - message: &MessagePayload< - SourceChainAccountId, - TargetChainAccountPublic, - TargetChainSignature, - Call, - >, -) -> Result, BadOrigin> -where - SourceChainAccountId: PartialEq + Clone, -{ - match message.origin { - CallOrigin::SourceRoot => { - ensure!(sender_origin == &RawOrigin::Root, BadOrigin); - Ok(None) - }, - CallOrigin::TargetAccount(ref source_account_id, _, _) => { - ensure!(sender_origin == &RawOrigin::Signed(source_account_id.clone()), BadOrigin); - Ok(Some(source_account_id.clone())) - }, - CallOrigin::SourceAccount(ref source_account_id) => { - ensure!( - sender_origin == &RawOrigin::Signed(source_account_id.clone()) || - sender_origin == &RawOrigin::Root, - BadOrigin - ); - Ok(Some(source_account_id.clone())) - }, - } -} - -/// Target account ownership digest from the source chain. -/// -/// The byte vector returned by this function will be signed with a target chain account -/// private key. This way, the owner of `source_account_id` on the source chain proves that -/// the target chain account private key is also under his control. -pub fn account_ownership_digest( - call: &Call, - source_account_id: AccountId, - target_spec_version: SpecVersion, - source_chain_id: ChainId, - target_chain_id: ChainId, -) -> Vec -where - Call: Encode, - AccountId: Encode, - SpecVersion: Encode, -{ - let mut proof = Vec::new(); - call.encode_to(&mut proof); - source_account_id.encode_to(&mut proof); - target_spec_version.encode_to(&mut proof); - source_chain_id.encode_to(&mut proof); - target_chain_id.encode_to(&mut proof); - - proof -} - -#[cfg(test)] -mod tests { - // From construct_runtime macro - #![allow(clippy::from_over_into)] - - use super::*; - use codec::Decode; - use frame_support::{parameter_types, weights::Weight}; - use frame_system::{EventRecord, Phase}; - use scale_info::TypeInfo; - use sp_core::H256; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, - }; - - type AccountId = u64; - type BridgeMessageId = [u8; 4]; - - const SOURCE_CHAIN_ID: ChainId = *b"srce"; - const TARGET_CHAIN_ID: ChainId = *b"trgt"; - - #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] - pub struct TestAccountPublic(AccountId); - - impl IdentifyAccount for TestAccountPublic { - type AccountId = AccountId; - - fn into_account(self) -> AccountId { - self.0 - } - } - - #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] - pub struct TestSignature(AccountId); - - impl Verify for TestSignature { - type Signer = TestAccountPublic; - - fn verify>(&self, _msg: L, signer: &AccountId) -> bool { - self.0 == *signer - } - } - - pub struct AccountIdConverter; - - impl sp_runtime::traits::Convert for AccountIdConverter { - fn convert(hash: H256) -> AccountId { - hash.to_low_u64_ne() - } - } - - type Block = frame_system::mocking::MockBlock; - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - - use crate as call_dispatch; - - frame_support::construct_runtime! { - pub enum TestRuntime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Dispatch: call_dispatch::{Pallet, Call, Event}, - } - } - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); - } - - impl frame_system::Config for TestRuntime { - type Origin = Origin; - type Index = u64; - type Call = Call; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - impl Config for TestRuntime { - type Event = Event; - type BridgeMessageId = BridgeMessageId; - type SourceChainAccountId = AccountId; - type TargetChainAccountPublic = TestAccountPublic; - type TargetChainSignature = TestSignature; - type Call = Call; - type CallFilter = TestCallFilter; - type EncodedCall = EncodedCall; - type AccountIdConverter = AccountIdConverter; - } - - #[derive(Decode, Encode)] - pub struct EncodedCall(Vec); - - impl From for Result { - fn from(call: EncodedCall) -> Result { - Call::decode(&mut &call.0[..]).map_err(drop) - } - } - - pub struct TestCallFilter; - - impl Contains for TestCallFilter { - fn contains(call: &Call) -> bool { - !matches!(*call, Call::System(frame_system::Call::fill_block { .. })) - } - } - - const TEST_SPEC_VERSION: SpecVersion = 0; - const TEST_WEIGHT: Weight = 1_000_000_000; - - fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - sp_io::TestExternalities::new(t) - } - - fn prepare_message( - origin: CallOrigin, - call: Call, - ) -> as MessageDispatch< - AccountId, - ::BridgeMessageId, - >>::Message { - MessagePayload { - spec_version: TEST_SPEC_VERSION, - weight: TEST_WEIGHT, - origin, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - call: EncodedCall(call.encode()), - } - } - - fn prepare_root_message( - call: Call, - ) -> as MessageDispatch< - AccountId, - ::BridgeMessageId, - >>::Message { - prepare_message(CallOrigin::SourceRoot, call) - } - - fn prepare_target_message( - call: Call, - ) -> as MessageDispatch< - AccountId, - ::BridgeMessageId, - >>::Message { - let origin = CallOrigin::TargetAccount(1, TestAccountPublic(1), TestSignature(1)); - prepare_message(origin, call) - } - - fn prepare_source_message( - call: Call, - ) -> as MessageDispatch< - AccountId, - ::BridgeMessageId, - >>::Message { - let origin = CallOrigin::SourceAccount(1); - prepare_message(origin, call) - } - - #[test] - fn should_fail_on_spec_version_mismatch() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - const BAD_SPEC_VERSION: SpecVersion = 99; - let mut message = prepare_root_message(Call::System(frame_system::Call::remark { - remark: vec![1, 2, 3], - })); - let weight = message.weight; - message.spec_version = BAD_SPEC_VERSION; - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert_eq!(result.unspent_weight, weight); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch( - call_dispatch::Event::::MessageVersionSpecMismatch( - SOURCE_CHAIN_ID, - id, - TEST_SPEC_VERSION, - BAD_SPEC_VERSION - ) - ), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_fail_on_weight_mismatch() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - let call = Call::System(frame_system::Call::set_heap_pages { pages: 42 }); - let call_weight = call.get_dispatch_info().weight; - let mut message = prepare_root_message(call); - message.weight = 7; - assert!(call_weight > 7, "needed for test to actually trigger a weight mismatch"); - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert_eq!(result.unspent_weight, 7); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch( - call_dispatch::Event::::MessageWeightMismatch( - SOURCE_CHAIN_ID, - id, - call_weight, - 7, - ) - ), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_fail_on_signature_mismatch() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let call_origin = CallOrigin::TargetAccount(1, TestAccountPublic(1), TestSignature(99)); - let message = prepare_message( - call_origin, - Call::System(frame_system::Call::remark { remark: vec![1, 2, 3] }), - ); - let weight = message.weight; - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert_eq!(result.unspent_weight, weight); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch( - call_dispatch::Event::::MessageSignatureMismatch( - SOURCE_CHAIN_ID, - id - ) - ), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_emit_event_for_rejected_messages() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - System::set_block_number(1); - Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Err(()), - |_, _| unreachable!(), - ); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch(call_dispatch::Event::::MessageRejected( - SOURCE_CHAIN_ID, - id - )), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_fail_on_call_decode() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let mut message = prepare_root_message(Call::System(frame_system::Call::remark { - remark: vec![1, 2, 3], - })); - let weight = message.weight; - message.call.0 = vec![]; - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert_eq!(result.unspent_weight, weight); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch( - call_dispatch::Event::::MessageCallDecodeFailed( - SOURCE_CHAIN_ID, - id - ) - ), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_emit_event_for_rejected_calls() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let call = - Call::System(frame_system::Call::fill_block { ratio: Perbill::from_percent(75) }); - let weight = call.get_dispatch_info().weight; - let mut message = prepare_root_message(call); - message.weight = weight; - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert_eq!(result.unspent_weight, weight); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch( - call_dispatch::Event::::MessageCallRejected( - SOURCE_CHAIN_ID, - id - ) - ), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_emit_event_for_unpaid_calls() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let mut message = prepare_root_message(Call::System(frame_system::Call::remark { - remark: vec![1, 2, 3], - })); - let weight = message.weight; - message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain; - - System::set_block_number(1); - let result = - Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| { - Err(()) - }); - assert_eq!(result.unspent_weight, weight); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch( - call_dispatch::Event::::MessageDispatchPaymentFailed( - SOURCE_CHAIN_ID, - id, - AccountIdConverter::convert(derive_account_id::( - SOURCE_CHAIN_ID, - SourceAccount::Root - )), - TEST_WEIGHT, - ) - ), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_dispatch_calls_paid_at_target_chain() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let mut message = prepare_root_message(Call::System(frame_system::Call::remark { - remark: vec![1, 2, 3], - })); - message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain; - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| Ok(()), - ); - assert!(result.dispatch_fee_paid_during_dispatch); - assert!(result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch(call_dispatch::Event::::MessageDispatched( - SOURCE_CHAIN_ID, - id, - Ok(()) - )), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_return_dispatch_failed_flag_if_dispatch_happened_but_failed() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let call = Call::System(frame_system::Call::set_heap_pages { pages: 1 }); - let message = prepare_target_message(call); - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert!(!result.dispatch_fee_paid_during_dispatch); - assert!(!result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch(call_dispatch::Event::::MessageDispatched( - SOURCE_CHAIN_ID, - id, - Err(sp_runtime::DispatchError::BadOrigin) - )), - topics: vec![], - }], - ); - }) - } - - #[test] - fn should_dispatch_bridge_message_from_root_origin() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - let message = prepare_root_message(Call::System(frame_system::Call::remark { - remark: vec![1, 2, 3], - })); - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert!(!result.dispatch_fee_paid_during_dispatch); - assert!(result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch(call_dispatch::Event::::MessageDispatched( - SOURCE_CHAIN_ID, - id, - Ok(()) - )), - topics: vec![], - }], - ); - }); - } - - #[test] - fn should_dispatch_bridge_message_from_target_origin() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let call = Call::System(frame_system::Call::remark { remark: vec![] }); - let message = prepare_target_message(call); - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert!(!result.dispatch_fee_paid_during_dispatch); - assert!(result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch(call_dispatch::Event::::MessageDispatched( - SOURCE_CHAIN_ID, - id, - Ok(()) - )), - topics: vec![], - }], - ); - }) - } - - #[test] - fn should_dispatch_bridge_message_from_source_origin() { - new_test_ext().execute_with(|| { - let id = [0; 4]; - - let call = Call::System(frame_system::Call::remark { remark: vec![] }); - let message = prepare_source_message(call); - - System::set_block_number(1); - let result = Dispatch::dispatch( - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - id, - Ok(message), - |_, _| unreachable!(), - ); - assert!(!result.dispatch_fee_paid_during_dispatch); - assert!(result.dispatch_result); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: Event::Dispatch(call_dispatch::Event::::MessageDispatched( - SOURCE_CHAIN_ID, - id, - Ok(()) - )), - topics: vec![], - }], - ); - }) - } - - #[test] - fn origin_is_checked_when_verifying_sending_message_using_source_root_account() { - let call = Call::System(frame_system::Call::remark { remark: vec![] }); - let message = prepare_root_message(call); - - // When message is sent by Root, CallOrigin::SourceRoot is allowed - assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(None))); - - // when message is sent by some real account, CallOrigin::SourceRoot is not allowed - assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Err(BadOrigin))); - } - - #[test] - fn origin_is_checked_when_verifying_sending_message_using_target_account() { - let call = Call::System(frame_system::Call::remark { remark: vec![] }); - let message = prepare_target_message(call); - - // When message is sent by Root, CallOrigin::TargetAccount is not allowed - assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Err(BadOrigin))); - - // When message is sent by some other account, it is rejected - assert!(matches!(verify_message_origin(&RawOrigin::Signed(2), &message), Err(BadOrigin))); - - // When message is sent by a real account, it is allowed to have origin - // CallOrigin::TargetAccount - assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Ok(Some(1)))); - } - - #[test] - fn origin_is_checked_when_verifying_sending_message_using_source_account() { - let call = Call::System(frame_system::Call::remark { remark: vec![] }); - let message = prepare_source_message(call); - - // Sending a message from the expected origin account works - assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Ok(Some(1)))); - - // If we send a message from a different account, it is rejected - assert!(matches!(verify_message_origin(&RawOrigin::Signed(2), &message), Err(BadOrigin))); - - // The Root account is allowed to assume any expected origin account - assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(Some(1)))); - } -} diff --git a/modules/grandpa/Cargo.toml b/modules/grandpa/Cargo.toml index eac80375da..55022d7e5c 100644 --- a/modules/grandpa/Cargo.toml +++ b/modules/grandpa/Cargo.toml @@ -8,11 +8,11 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -finality-grandpa = { version = "0.15.0", default-features = false } -log = { version = "0.4.14", default-features = false } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +finality-grandpa = { version = "0.16.0", default-features = false } +log = { version = "0.4.17", default-features = false } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true } # Bridge Dependencies diff --git a/modules/grandpa/src/benchmarking.rs b/modules/grandpa/src/benchmarking.rs index 46e1e41a87..f93798536a 100644 --- a/modules/grandpa/src/benchmarking.rs +++ b/modules/grandpa/src/benchmarking.rs @@ -41,6 +41,7 @@ use crate::*; +use bp_runtime::BasicOperatingMode; use bp_test_utils::{ accounts, make_justification_for_header, JustificationGeneratorParams, TEST_GRANDPA_ROUND, TEST_GRANDPA_SET_ID, @@ -62,6 +63,16 @@ const MAX_VOTE_ANCESTRIES: u32 = 1000; // number of validators. const MAX_VALIDATOR_SET_SIZE: u32 = 1024; +// `1..MAX_VALIDATOR_SET_SIZE` and `1..MAX_VOTE_ANCESTRIES` are too large && benchmarks are +// running for almost 40m (steps=50, repeat=20) on a decent laptop, which is too much. Since +// we're building linear function here, let's just select some limited subrange for benchmarking. +const VALIDATOR_SET_SIZE_RANGE_BEGIN: u32 = MAX_VALIDATOR_SET_SIZE / 20; +const VALIDATOR_SET_SIZE_RANGE_END: u32 = + VALIDATOR_SET_SIZE_RANGE_BEGIN + VALIDATOR_SET_SIZE_RANGE_BEGIN; +const MAX_VOTE_ANCESTRIES_RANGE_BEGIN: u32 = MAX_VOTE_ANCESTRIES / 20; +const MAX_VOTE_ANCESTRIES_RANGE_END: u32 = + MAX_VOTE_ANCESTRIES_RANGE_BEGIN + MAX_VOTE_ANCESTRIES_RANGE_BEGIN; + /// Returns number of first header to be imported. /// /// Since we bootstrap the pallet with `HeadersToKeep` already imported headers, @@ -84,7 +95,7 @@ fn prepare_benchmark_data, I: 'static>( header: Box::new(bp_test_utils::test_header(Zero::zero())), authority_list, set_id: TEST_GRANDPA_SET_ID, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }; bootstrap_bridge::(init_data); @@ -106,8 +117,8 @@ benchmarks_instance_pallet! { // This is the "gold standard" benchmark for this extrinsic, and it's what should be used to // annotate the weight in the pallet. submit_finality_proof { - let p in 1..MAX_VALIDATOR_SET_SIZE; - let v in 1..MAX_VOTE_ANCESTRIES; + let p in VALIDATOR_SET_SIZE_RANGE_BEGIN..VALIDATOR_SET_SIZE_RANGE_END; + let v in MAX_VOTE_ANCESTRIES_RANGE_BEGIN..MAX_VOTE_ANCESTRIES_RANGE_END; let caller: T::AccountId = whitelisted_caller(); let (header, justification) = prepare_benchmark_data::(p, v); }: submit_finality_proof(RawOrigin::Signed(caller), Box::new(header), justification) @@ -115,7 +126,7 @@ benchmarks_instance_pallet! { let header: BridgedHeader = bp_test_utils::test_header(header_number::()); let expected_hash = header.hash(); - assert_eq!(>::get(), expected_hash); + assert_eq!(>::get().unwrap().1, expected_hash); assert!(>::contains_key(expected_hash)); } } diff --git a/modules/grandpa/src/extension.rs b/modules/grandpa/src/extension.rs new file mode 100644 index 0000000000..a724b6518d --- /dev/null +++ b/modules/grandpa/src/extension.rs @@ -0,0 +1,115 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use crate::{Config, Pallet}; +use bp_runtime::FilterCall; +use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; +use sp_runtime::{ + traits::Header, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, +}; + +/// Validate Grandpa headers in order to avoid "mining" transactions that provide outdated +/// bridged chain headers. Without this validation, even honest relayers may lose their funds +/// if there are multiple relays running and submitting the same information. +impl< + Call: IsSubType, T>>, + T: frame_system::Config + Config, + I: 'static, + > FilterCall for Pallet +{ + fn validate(call: &::Call) -> TransactionValidity { + let bundled_block_number = match call.is_sub_type() { + Some(crate::Call::::submit_finality_proof { ref finality_target, .. }) => + *finality_target.number(), + _ => return Ok(ValidTransaction::default()), + }; + + let best_finalized = crate::BestFinalized::::get(); + let best_finalized_number = match best_finalized { + Some((best_finalized_number, _)) => best_finalized_number, + None => return InvalidTransaction::Call.into(), + }; + + if best_finalized_number >= bundled_block_number { + log::trace!( + target: crate::LOG_TARGET, + "Rejecting obsolete bridged header: bundled {:?}, best {:?}", + bundled_block_number, + best_finalized_number, + ); + + return InvalidTransaction::Stale.into() + } + + Ok(ValidTransaction::default()) + } +} + +#[cfg(test)] +mod tests { + use super::FilterCall; + use crate::{ + mock::{run_test, test_header, Call, TestNumber, TestRuntime}, + BestFinalized, + }; + use bp_test_utils::make_default_justification; + + fn validate_block_submit(num: TestNumber) -> bool { + crate::Pallet::::validate(&Call::Grandpa( + crate::Call::::submit_finality_proof { + finality_target: Box::new(test_header(num)), + justification: make_default_justification(&test_header(num)), + }, + )) + .is_ok() + } + + fn sync_to_header_10() { + let header10_hash = sp_core::H256::default(); + BestFinalized::::put((10, header10_hash)); + } + + #[test] + fn extension_rejects_obsolete_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#5 => tx is + // rejected + sync_to_header_10(); + assert!(!validate_block_submit(5)); + }); + } + + #[test] + fn extension_rejects_same_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#10 => tx is + // rejected + sync_to_header_10(); + assert!(!validate_block_submit(10)); + }); + } + + #[test] + fn extension_accepts_new_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#15 => tx is + // accepted + sync_to_header_10(); + assert!(validate_block_submit(15)); + }); + } +} diff --git a/modules/grandpa/src/lib.rs b/modules/grandpa/src/lib.rs index 947bfdc7f6..4074421fc5 100644 --- a/modules/grandpa/src/lib.rs +++ b/modules/grandpa/src/lib.rs @@ -36,21 +36,20 @@ // Runtime-generated enums #![allow(clippy::large_enum_variant)] -use crate::weights::WeightInfo; - use bp_header_chain::{justification::GrandpaJustification, InitializationData}; -use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf}; +use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, OwnedBridgeModule}; use finality_grandpa::voter_set::VoterSet; use frame_support::{ensure, fail}; -use frame_system::{ensure_signed, RawOrigin}; +use frame_system::ensure_signed; use sp_finality_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID}; -use sp_runtime::traits::{BadOrigin, Header as HeaderT, Zero}; +use sp_runtime::traits::{Header as HeaderT, Zero}; use sp_std::{boxed::Box, convert::TryInto}; +mod extension; #[cfg(test)] mod mock; -/// Pallet containing weights for this pallet. +/// Module, containing weights for this pallet. pub mod weights; #[cfg(feature = "runtime-benchmarks")] @@ -58,6 +57,10 @@ pub mod benchmarking; // Re-export in crate namespace for `construct_runtime!` pub use pallet::*; +pub use weights::WeightInfo; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-grandpa"; /// Block number of the bridged chain. pub type BridgedBlockNumber = BlockNumberOf<>::BridgedChain>; @@ -71,6 +74,7 @@ pub type BridgedHeader = HeaderOf<>::BridgedChain>; #[frame_support::pallet] pub mod pallet { use super::*; + use bp_runtime::BasicOperatingMode; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -93,6 +97,8 @@ pub mod pallet { /// The setting is there to prevent growing the on-chain state indefinitely. Note /// the setting does not relate to block numbers - we will simply keep as much items /// in the storage, so it doesn't guarantee any fixed timeframe for finality headers. + /// + /// Incautious change of this constant may lead to orphan entries in the runtime storage. #[pallet::constant] type HeadersToKeep: Get; @@ -115,6 +121,13 @@ pub mod pallet { } } + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = BasicOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + #[pallet::call] impl, I: 'static> Pallet { /// Verify a target header is finalized according to the given finality proof. @@ -133,19 +146,26 @@ pub mod pallet { finality_target: Box>, justification: GrandpaJustification>, ) -> DispatchResultWithPostInfo { - ensure_operational::()?; + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; let _ = ensure_signed(origin)?; ensure!(Self::request_count() < T::MaxRequests::get(), >::TooManyRequests); let (hash, number) = (finality_target.hash(), finality_target.number()); - log::trace!(target: "runtime::bridge-grandpa", "Going to try and finalize header {:?}", finality_target); + log::trace!( + target: LOG_TARGET, + "Going to try and finalize header {:?}", + finality_target + ); - let best_finalized = match >::get(>::get()) { + let best_finalized = BestFinalized::::get(); + let best_finalized = + best_finalized.and_then(|(_, hash)| ImportedHeaders::::get(hash)); + let best_finalized = match best_finalized { Some(best_finalized) => best_finalized, None => { log::error!( - target: "runtime::bridge-grandpa", + target: LOG_TARGET, "Cannot finalize header {:?} because pallet is not yet initialized", finality_target, ); @@ -166,7 +186,11 @@ pub mod pallet { try_enact_authority_change::(&finality_target, set_id)?; >::mutate(|count| *count += 1); insert_header::(*finality_target, hash); - log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash); + log::info!( + target: LOG_TARGET, + "Successfully imported finalized header with hash {:?}!", + hash + ); // mandatory header is a header that changes authorities set. The pallet can't go // further without importing this header. So every bridge MUST import mandatory headers. @@ -193,14 +217,14 @@ pub mod pallet { origin: OriginFor, init_data: super::InitializationData>, ) -> DispatchResultWithPostInfo { - ensure_owner_or_root::(origin)?; + Self::ensure_owner_or_root(origin)?; let init_allowed = !>::exists(); ensure!(init_allowed, >::AlreadyInitialized); initialize_bridge::(init_data.clone()); log::info!( - target: "runtime::bridge-grandpa", + target: LOG_TARGET, "Pallet has been initialized with the following parameters: {:?}", init_data ); @@ -212,43 +236,19 @@ pub mod pallet { /// /// May only be called either by root, or by `PalletOwner`. #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] - pub fn set_owner( - origin: OriginFor, - new_owner: Option, - ) -> DispatchResultWithPostInfo { - ensure_owner_or_root::(origin)?; - match new_owner { - Some(new_owner) => { - PalletOwner::::put(&new_owner); - log::info!(target: "runtime::bridge-grandpa", "Setting pallet Owner to: {:?}", new_owner); - }, - None => { - PalletOwner::::kill(); - log::info!(target: "runtime::bridge-grandpa", "Removed Owner of pallet."); - }, - } - - Ok(().into()) + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) } /// Halt or resume all pallet operations. /// /// May only be called either by root, or by `PalletOwner`. #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] - pub fn set_operational( + pub fn set_operating_mode( origin: OriginFor, - operational: bool, - ) -> DispatchResultWithPostInfo { - ensure_owner_or_root::(origin)?; - >::put(!operational); - - if operational { - log::info!(target: "runtime::bridge-grandpa", "Resuming pallet operations."); - } else { - log::warn!(target: "runtime::bridge-grandpa", "Stopping pallet operations."); - } - - Ok(().into()) + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) } } @@ -270,8 +270,8 @@ pub mod pallet { /// Hash of the best finalized header. #[pallet::storage] - pub(super) type BestFinalized, I: 'static = ()> = - StorageValue<_, BridgedBlockHash, ValueQuery>; + pub type BestFinalized, I: 'static = ()> = + StorageValue<_, (BridgedBlockNumber, BridgedBlockHash), OptionQuery>; /// A ring buffer of imported hashes. Ordered by the insertion time. #[pallet::storage] @@ -285,7 +285,7 @@ pub mod pallet { /// Headers which have been imported into the pallet. #[pallet::storage] - pub(super) type ImportedHeaders, I: 'static = ()> = + pub type ImportedHeaders, I: 'static = ()> = StorageMap<_, Identity, BridgedBlockHash, BridgedHeader>; /// The current GRANDPA Authority set. @@ -303,9 +303,12 @@ pub mod pallet { pub type PalletOwner, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; - /// If true, all pallet transactions are failed immediately. + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, or no transactions will be allowed. #[pallet::storage] - pub(super) type IsHalted, I: 'static = ()> = StorageValue<_, bool, ValueQuery>; + pub type PalletOperatingMode, I: 'static = ()> = + StorageValue<_, BasicOperatingMode, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { @@ -334,7 +337,7 @@ pub mod pallet { } else { // Since the bridge hasn't been initialized we shouldn't allow anyone to perform // transactions. - >::put(true); + >::put(BasicOperatingMode::Halted); } } } @@ -359,10 +362,10 @@ pub mod pallet { NotInitialized, /// The pallet has already been initialized. AlreadyInitialized, - /// All pallet operations are halted. - Halted, /// The storage proof doesn't contains storage root. So it is invalid for given header. StorageRootMismatch, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), } /// Check the given header for a GRANDPA scheduled authority set change. If a change @@ -400,7 +403,7 @@ pub mod pallet { change_enacted = true; log::info!( - target: "runtime::bridge-grandpa", + target: LOG_TARGET, "Transitioned from authority set {} to {}! New authorities are: {:?}", current_set_id, current_set_id + 1, @@ -437,7 +440,7 @@ pub mod pallet { ) .map_err(|e| { log::error!( - target: "runtime::bridge-grandpa", + target: LOG_TARGET, "Received invalid justification for {:?}: {:?}", hash, e, @@ -456,14 +459,14 @@ pub mod pallet { ) { let index = >::get(); let pruning = >::try_get(index); - >::put(hash); + >::put((*header.number(), hash)); >::insert(hash, header); >::insert(index, hash); // Update ring buffer pointer and remove old header. >::put((index + 1) % T::HeadersToKeep::get()); if let Ok(hash) = pruning { - log::debug!(target: "runtime::bridge-grandpa", "Pruning old header: {:?}.", hash); + log::debug!(target: LOG_TARGET, "Pruning old header: {:?}.", hash); >::remove(hash); } } @@ -473,7 +476,8 @@ pub mod pallet { pub(crate) fn initialize_bridge, I: 'static>( init_params: super::InitializationData>, ) { - let super::InitializationData { header, authority_list, set_id, is_halted } = init_params; + let super::InitializationData { header, authority_list, set_id, operating_mode } = + init_params; let initial_hash = header.hash(); >::put(initial_hash); @@ -483,7 +487,7 @@ pub mod pallet { let authority_set = bp_header_chain::AuthoritySet::new(authority_list, set_id); >::put(authority_set); - >::put(is_halted); + >::put(operating_mode); } #[cfg(feature = "runtime-benchmarks")] @@ -508,26 +512,6 @@ pub mod pallet { insert_header::(header, hash); } } - - /// Ensure that the origin is either root, or `PalletOwner`. - fn ensure_owner_or_root, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> { - match origin.into() { - Ok(RawOrigin::Root) => Ok(()), - Ok(RawOrigin::Signed(ref signer)) - if Some(signer) == >::get().as_ref() => - Ok(()), - _ => Err(BadOrigin), - } - } - - /// Ensure that the pallet is in operational mode (not halted). - fn ensure_operational, I: 'static>() -> Result<(), Error> { - if >::get() { - Err(>::Halted) - } else { - Ok(()) - } - } } impl, I: 'static> Pallet { @@ -535,17 +519,9 @@ impl, I: 'static> Pallet { /// /// Returns a dummy header if there is no best header. This can only happen /// if the pallet has not been initialized yet. - pub fn best_finalized() -> BridgedHeader { - let hash = >::get(); - >::get(hash).unwrap_or_else(|| { - >::new( - Default::default(), - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ) - }) + pub fn best_finalized() -> Option> { + let (_, hash) = >::get()?; + >::get(hash) } /// Check if a particular header is known to the bridge pallet. @@ -614,7 +590,7 @@ pub fn initialize_for_benchmarks, I: 'static>(header: BridgedHeader authority_list: sp_std::vec::Vec::new(), /* we don't verify any proofs in external * benchmarks */ set_id: 0, - is_halted: false, + operating_mode: bp_runtime::BasicOperatingMode::Normal, }); } @@ -622,9 +598,10 @@ pub fn initialize_for_benchmarks, I: 'static>(header: BridgedHeader mod tests { use super::*; use crate::mock::{run_test, test_header, Origin, TestHeader, TestNumber, TestRuntime}; + use bp_runtime::BasicOperatingMode; use bp_test_utils::{ - authority_list, make_default_justification, make_justification_for_header, - JustificationGeneratorParams, ALICE, BOB, + authority_list, generate_owned_bridge_module_tests, make_default_justification, + make_justification_for_header, JustificationGeneratorParams, ALICE, BOB, }; use codec::Encode; use frame_support::{ @@ -649,7 +626,7 @@ mod tests { header: Box::new(genesis), authority_list: authority_list(), set_id: 1, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }; Pallet::::initialize(origin, init_data.clone()).map(|_| init_data) @@ -712,21 +689,18 @@ mod tests { #[test] fn init_storage_entries_are_correctly_initialized() { run_test(|| { - assert_eq!( - BestFinalized::::get(), - BridgedBlockHash::::default() - ); - assert_eq!(Pallet::::best_finalized(), test_header(0)); + assert_eq!(BestFinalized::::get(), None,); + assert_eq!(Pallet::::best_finalized(), None); let init_data = init_with_origin(Origin::root()).unwrap(); assert!(>::contains_key(init_data.header.hash())); - assert_eq!(BestFinalized::::get(), init_data.header.hash()); + assert_eq!(BestFinalized::::get().unwrap().1, init_data.header.hash()); assert_eq!( CurrentAuthoritySet::::get().authorities, init_data.authority_list ); - assert!(!IsHalted::::get()); + assert_eq!(PalletOperatingMode::::get(), BasicOperatingMode::Normal); }) } @@ -741,73 +715,24 @@ mod tests { }) } - #[test] - fn pallet_owner_may_change_owner() { - run_test(|| { - PalletOwner::::put(2); - - assert_ok!(Pallet::::set_owner(Origin::root(), Some(1))); - assert_noop!( - Pallet::::set_operational(Origin::signed(2), false), - DispatchError::BadOrigin, - ); - assert_ok!(Pallet::::set_operational(Origin::root(), false)); - - assert_ok!(Pallet::::set_owner(Origin::signed(1), None)); - assert_noop!( - Pallet::::set_operational(Origin::signed(1), true), - DispatchError::BadOrigin, - ); - assert_noop!( - Pallet::::set_operational(Origin::signed(2), true), - DispatchError::BadOrigin, - ); - assert_ok!(Pallet::::set_operational(Origin::root(), true)); - }); - } - - #[test] - fn pallet_may_be_halted_by_root() { - run_test(|| { - assert_ok!(Pallet::::set_operational(Origin::root(), false)); - assert_ok!(Pallet::::set_operational(Origin::root(), true)); - }); - } - - #[test] - fn pallet_may_be_halted_by_owner() { - run_test(|| { - PalletOwner::::put(2); - - assert_ok!(Pallet::::set_operational(Origin::signed(2), false)); - assert_ok!(Pallet::::set_operational(Origin::signed(2), true)); - - assert_noop!( - Pallet::::set_operational(Origin::signed(1), false), - DispatchError::BadOrigin, - ); - assert_noop!( - Pallet::::set_operational(Origin::signed(1), true), - DispatchError::BadOrigin, - ); - - assert_ok!(Pallet::::set_operational(Origin::signed(2), false)); - assert_noop!( - Pallet::::set_operational(Origin::signed(1), true), - DispatchError::BadOrigin, - ); - }); - } - #[test] fn pallet_rejects_transactions_if_halted() { run_test(|| { initialize_substrate_bridge(); - assert_ok!(Pallet::::set_operational(Origin::root(), false)); - assert_noop!(submit_finality_proof(1), Error::::Halted); + assert_ok!(Pallet::::set_operating_mode( + Origin::root(), + BasicOperatingMode::Halted + )); + assert_noop!( + submit_finality_proof(1), + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted) + ); - assert_ok!(Pallet::::set_operational(Origin::root(), true)); + assert_ok!(Pallet::::set_operating_mode( + Origin::root(), + BasicOperatingMode::Normal + )); assert_ok!(submit_finality_proof(1)); }) } @@ -832,7 +757,7 @@ mod tests { ); let header = test_header(1); - assert_eq!(>::get(), header.hash()); + assert_eq!(>::get().unwrap().1, header.hash()); assert!(>::contains_key(header.hash())); }) } @@ -889,7 +814,7 @@ mod tests { header: Box::new(genesis), authority_list: invalid_authority_list, set_id: 1, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }; assert_ok!(Pallet::::initialize(Origin::root(), init_data)); @@ -949,7 +874,7 @@ mod tests { ); // Make sure that our header is the best finalized - assert_eq!(>::get(), header.hash()); + assert_eq!(>::get().unwrap().1, header.hash()); assert!(>::contains_key(header.hash())); // Make sure that the authority set actually changed upon importing our header @@ -1033,7 +958,7 @@ mod tests { header.set_state_root(state_root); let hash = header.hash(); - >::put(hash); + >::put((2, hash)); >::insert(hash, header); assert_ok!( @@ -1129,7 +1054,7 @@ mod tests { run_test(|| { initialize_substrate_bridge(); assert_ok!(submit_finality_proof(1)); - let first_header = Pallet::::best_finalized(); + let first_header = Pallet::::best_finalized().unwrap(); next_block(); assert_ok!(submit_finality_proof(2)); @@ -1153,13 +1078,15 @@ mod tests { #[test] fn storage_keys_computed_properly() { assert_eq!( - IsHalted::::storage_value_final_key().to_vec(), - bp_header_chain::storage_keys::is_halted_key("Grandpa").0, + PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_header_chain::storage_keys::pallet_operating_mode_key("Grandpa").0, ); assert_eq!( BestFinalized::::storage_value_final_key().to_vec(), - bp_header_chain::storage_keys::best_finalized_hash_key("Grandpa").0, + bp_header_chain::storage_keys::best_finalized_key("Grandpa").0, ); } + + generate_owned_bridge_module_tests!(BasicOperatingMode::Normal, BasicOperatingMode::Halted); } diff --git a/modules/grandpa/src/mock.rs b/modules/grandpa/src/mock.rs index bfc749d523..a0327761fc 100644 --- a/modules/grandpa/src/mock.rs +++ b/modules/grandpa/src/mock.rs @@ -42,7 +42,7 @@ construct_runtime! { UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Grandpa: grandpa::{Pallet}, + Grandpa: grandpa::{Pallet, Call}, } } diff --git a/modules/grandpa/src/weights.rs b/modules/grandpa/src/weights.rs index 2c4660160a..f23a2ac190 100644 --- a/modules/grandpa/src/weights.rs +++ b/modules/grandpa/src/weights.rs @@ -17,14 +17,15 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-28, STEPS: 50, REPEAT: 20 +//! DATE: 2022-07-06, STEPS: 50, REPEAT: 20 //! LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled -//! CHAIN: Some("dev"), DB CACHE: 128 +//! CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/release/millau-bridge-node // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -39,6 +40,7 @@ #![allow(clippy::all)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{ traits::Get, @@ -55,9 +57,9 @@ pub trait WeightInfo { pub struct MillauWeight(PhantomData); impl WeightInfo for MillauWeight { fn submit_finality_proof(p: u32, v: u32) -> Weight { - (115_651_000 as Weight) - .saturating_add((61_465_000 as Weight).saturating_mul(p as Weight)) - .saturating_add((3_438_000 as Weight).saturating_mul(v as Weight)) + (55_070_000 as Weight) + .saturating_add((39_678_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_540_000 as Weight).saturating_mul(v as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(6 as Weight)) } @@ -66,9 +68,9 @@ impl WeightInfo for MillauWeight { // For backwards compatibility and tests impl WeightInfo for () { fn submit_finality_proof(p: u32, v: u32) -> Weight { - (115_651_000 as Weight) - .saturating_add((61_465_000 as Weight).saturating_mul(p as Weight)) - .saturating_add((3_438_000 as Weight).saturating_mul(v as Weight)) + (55_070_000 as Weight) + .saturating_add((39_678_000 as Weight).saturating_mul(p as Weight)) + .saturating_add((1_540_000 as Weight).saturating_mul(v as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(6 as Weight)) } diff --git a/modules/messages/Cargo.toml b/modules/messages/Cargo.toml index 804f323f10..78a70b9bd5 100644 --- a/modules/messages/Cargo.toml +++ b/modules/messages/Cargo.toml @@ -8,15 +8,14 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] bitvec = { version = "1", default-features = false, features = ["alloc"] } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.14", default-features = false } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +log = { version = "0.4.17", default-features = false } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.101", optional = true, features = ["derive"] } # Bridge dependencies -bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false } bp-messages = { path = "../../primitives/messages", default-features = false } bp-runtime = { path = "../../primitives/runtime", default-features = false } @@ -32,11 +31,11 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d [dev-dependencies] sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +bp-test-utils = { path = "../../primitives/test-utils" } [features] default = ["std"] std = [ - "bp-message-dispatch/std", "bp-messages/std", "bp-runtime/std", "codec/std", diff --git a/modules/messages/src/benchmarking.rs b/modules/messages/src/benchmarking.rs index 46a8150d03..e7650f1721 100644 --- a/modules/messages/src/benchmarking.rs +++ b/modules/messages/src/benchmarking.rs @@ -19,14 +19,15 @@ use crate::{ inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane, outbound_lane::ReceivalConfirmationResult, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call, + OutboundLanes, OutboundMessages, }; use bp_messages::{ source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages, - InboundLaneData, LaneId, MessageData, MessageNonce, OutboundLaneData, UnrewardedRelayer, - UnrewardedRelayersState, + InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, OutboundLaneData, + UnrewardedRelayer, UnrewardedRelayersState, }; -use bp_runtime::messages::DispatchFeePayment; +use bp_runtime::{messages::DispatchFeePayment, StorageProofSize}; use frame_benchmarking::{account, benchmarks_instance_pallet}; use frame_support::{traits::Get, weights::Weight}; use frame_system::RawOrigin; @@ -37,20 +38,6 @@ const SEED: u32 = 0; /// Pallet we're benchmarking here. pub struct Pallet, I: 'static>(crate::Pallet); -/// Proof size requirements. -#[derive(Clone, Copy, Debug)] -pub enum ProofSize { - /// The proof is expected to be minimal. If value size may be changed, then it is expected to - /// have given size. - Minimal(u32), - /// The proof is expected to have at least given size and grow by increasing number of trie - /// nodes included in the proof. - HasExtraNodes(u32), - /// The proof is expected to have at least given size and grow by increasing value that is - /// stored in the trie. - HasLargeLeaf(u32), -} - /// Benchmark-specific message parameters. #[derive(Debug)] pub struct MessageParams { @@ -70,7 +57,7 @@ pub struct MessageProofParams { /// If `Some`, the proof needs to include this outbound lane data. pub outbound_lane_data: Option, /// Proof size requirements. - pub size: ProofSize, + pub size: StorageProofSize, /// Where the fee for dispatching message is paid? pub dispatch_fee_payment: DispatchFeePayment, } @@ -83,7 +70,7 @@ pub struct MessageDeliveryProofParams { /// The proof needs to include this inbound lane data. pub inbound_lane_data: InboundLaneData, /// Proof size requirements. - pub size: ProofSize, + pub size: StorageProofSize, } /// Trait that must be implemented by runtime. @@ -139,10 +126,8 @@ benchmarks_instance_pallet! { // added. send_minimal_message_worst_case { let lane_id = T::bench_lane_id(); - let relayers_fund_id = crate::relayer_fund_account_id::(); let sender = account("sender", 0, SEED); T::endow_account(&sender); - T::endow_account(&relayers_fund_id); // 'send' messages that are to be pruned when our message is sent for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() { @@ -172,10 +157,8 @@ benchmarks_instance_pallet! { // `(send_16_kb_message_worst_case - send_1_kb_message_worst_case) / 15`. send_1_kb_message_worst_case { let lane_id = T::bench_lane_id(); - let relayers_fund_id = crate::relayer_fund_account_id::(); let sender = account("sender", 0, SEED); T::endow_account(&sender); - T::endow_account(&relayers_fund_id); // 'send' messages that are to be pruned when our message is sent for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() { @@ -211,10 +194,8 @@ benchmarks_instance_pallet! { // `(send_16_kb_message_worst_case - send_1_kb_message_worst_case) / 15`. send_16_kb_message_worst_case { let lane_id = T::bench_lane_id(); - let relayers_fund_id = crate::relayer_fund_account_id::(); let sender = account("sender", 0, SEED); T::endow_account(&sender); - T::endow_account(&relayers_fund_id); // 'send' messages that are to be pruned when our message is sent for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() { @@ -246,10 +227,8 @@ benchmarks_instance_pallet! { // // Result of this benchmark is directly used by weight formula of the call. maximal_increase_message_fee { - let relayers_fund_id = crate::relayer_fund_account_id::(); let sender = account("sender", 42, SEED); T::endow_account(&sender); - T::endow_account(&relayers_fund_id); let additional_fee = T::account_balance(&sender); let lane_id = T::bench_lane_id(); @@ -258,7 +237,10 @@ benchmarks_instance_pallet! { send_regular_message_with_payload::(vec![42u8; T::maximal_message_size() as _]); }: increase_message_fee(RawOrigin::Signed(sender.clone()), lane_id, nonce, additional_fee) verify { - assert_eq!(T::account_balance(&sender), 0.into()); + assert_eq!( + OutboundMessages::::get(MessageKey { lane_id, nonce }).unwrap().fee, + T::message_fee() + additional_fee, + ); } // Benchmark `increase_message_fee` with following conditions: @@ -267,10 +249,8 @@ benchmarks_instance_pallet! { increase_message_fee { let i in 0..T::maximal_message_size().try_into().unwrap_or_default(); - let relayers_fund_id = crate::relayer_fund_account_id::(); let sender = account("sender", 42, SEED); T::endow_account(&sender); - T::endow_account(&relayers_fund_id); let additional_fee = T::account_balance(&sender); let lane_id = T::bench_lane_id(); @@ -279,7 +259,10 @@ benchmarks_instance_pallet! { send_regular_message_with_payload::(vec![42u8; i as _]); }: increase_message_fee(RawOrigin::Signed(sender.clone()), lane_id, nonce, additional_fee) verify { - assert_eq!(T::account_balance(&sender), 0.into()); + assert_eq!( + OutboundMessages::::get(MessageKey { lane_id, nonce }).unwrap().fee, + T::message_fee() + additional_fee, + ); } // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: @@ -302,7 +285,7 @@ benchmarks_instance_pallet! { lane: T::bench_lane_id(), message_nonces: 21..=21, outbound_lane_data: None, - size: ProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), dispatch_fee_payment: DispatchFeePayment::AtTargetChain, }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) @@ -337,7 +320,7 @@ benchmarks_instance_pallet! { lane: T::bench_lane_id(), message_nonces: 21..=22, outbound_lane_data: None, - size: ProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), dispatch_fee_payment: DispatchFeePayment::AtTargetChain, }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 2, dispatch_weight) @@ -376,7 +359,7 @@ benchmarks_instance_pallet! { latest_received_nonce: 20, latest_generated_nonce: 21, }), - size: ProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), dispatch_fee_payment: DispatchFeePayment::AtTargetChain, }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) @@ -408,7 +391,7 @@ benchmarks_instance_pallet! { lane: T::bench_lane_id(), message_nonces: 21..=21, outbound_lane_data: None, - size: ProofSize::HasExtraNodes(1024), + size: StorageProofSize::HasExtraNodes(1024), dispatch_fee_payment: DispatchFeePayment::AtTargetChain, }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) @@ -443,7 +426,7 @@ benchmarks_instance_pallet! { lane: T::bench_lane_id(), message_nonces: 21..=21, outbound_lane_data: None, - size: ProofSize::HasExtraNodes(16 * 1024), + size: StorageProofSize::HasExtraNodes(16 * 1024), dispatch_fee_payment: DispatchFeePayment::AtTargetChain, }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) @@ -477,7 +460,7 @@ benchmarks_instance_pallet! { lane: T::bench_lane_id(), message_nonces: 21..=21, outbound_lane_data: None, - size: ProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), dispatch_fee_payment: DispatchFeePayment::AtSourceChain, }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) @@ -495,10 +478,8 @@ benchmarks_instance_pallet! { // // This is base benchmark for all other confirmations delivery benchmarks. receive_delivery_proof_for_single_message { - let relayers_fund_id = crate::relayer_fund_account_id::(); let relayer_id: T::AccountId = account("relayer", 0, SEED); let relayer_balance = T::account_balance(&relayer_id); - T::endow_account(&relayers_fund_id); // send message that we're going to confirm send_regular_message::(); @@ -507,6 +488,7 @@ benchmarks_instance_pallet! { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 1, total_messages: 1, + last_delivered_nonce: 1, }; let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), @@ -517,14 +499,11 @@ benchmarks_instance_pallet! { }].into_iter().collect(), last_confirmed_nonce: 0, }, - size: ProofSize::Minimal(0), + size: StorageProofSize::Minimal(0), }); }: receive_messages_delivery_proof(RawOrigin::Signed(relayer_id.clone()), proof, relayers_state) verify { - assert_eq!( - T::account_balance(&relayer_id), - relayer_balance + T::message_fee(), - ); + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 1); } // Benchmark `receive_messages_delivery_proof` extrinsic with following conditions: @@ -535,10 +514,8 @@ benchmarks_instance_pallet! { // as `weight(receive_delivery_proof_for_two_messages_by_single_relayer) // - weight(receive_delivery_proof_for_single_message)`. receive_delivery_proof_for_two_messages_by_single_relayer { - let relayers_fund_id = crate::relayer_fund_account_id::(); let relayer_id: T::AccountId = account("relayer", 0, SEED); let relayer_balance = T::account_balance(&relayer_id); - T::endow_account(&relayers_fund_id); // send message that we're going to confirm send_regular_message::(); @@ -548,6 +525,7 @@ benchmarks_instance_pallet! { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 2, total_messages: 2, + last_delivered_nonce: 2, }; let mut delivered_messages = DeliveredMessages::new(1, true); delivered_messages.note_dispatched_message(true); @@ -560,11 +538,11 @@ benchmarks_instance_pallet! { }].into_iter().collect(), last_confirmed_nonce: 0, }, - size: ProofSize::Minimal(0), + size: StorageProofSize::Minimal(0), }); }: receive_messages_delivery_proof(RawOrigin::Signed(relayer_id.clone()), proof, relayers_state) verify { - ensure_relayer_rewarded::(&relayer_id, &relayer_balance); + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); } // Benchmark `receive_messages_delivery_proof` extrinsic with following conditions: @@ -575,12 +553,10 @@ benchmarks_instance_pallet! { // as `weight(receive_delivery_proof_for_two_messages_by_two_relayers) // - weight(receive_delivery_proof_for_two_messages_by_single_relayer)`. receive_delivery_proof_for_two_messages_by_two_relayers { - let relayers_fund_id = crate::relayer_fund_account_id::(); let relayer1_id: T::AccountId = account("relayer1", 1, SEED); let relayer1_balance = T::account_balance(&relayer1_id); let relayer2_id: T::AccountId = account("relayer2", 2, SEED); let relayer2_balance = T::account_balance(&relayer2_id); - T::endow_account(&relayers_fund_id); // send message that we're going to confirm send_regular_message::(); @@ -590,6 +566,7 @@ benchmarks_instance_pallet! { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, total_messages: 2, + last_delivered_nonce: 2, }; let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), @@ -606,12 +583,11 @@ benchmarks_instance_pallet! { ].into_iter().collect(), last_confirmed_nonce: 0, }, - size: ProofSize::Minimal(0), + size: StorageProofSize::Minimal(0), }); }: receive_messages_delivery_proof(RawOrigin::Signed(relayer1_id.clone()), proof, relayers_state) verify { - ensure_relayer_rewarded::(&relayer1_id, &relayer1_balance); - ensure_relayer_rewarded::(&relayer2_id, &relayer2_balance); + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); } } @@ -653,16 +629,3 @@ fn receive_messages, I: 'static>(nonce: MessageNonce) { last_confirmed_nonce: 0, }); } - -fn ensure_relayer_rewarded, I: 'static>( - relayer_id: &T::AccountId, - old_balance: &T::OutboundMessageFee, -) { - let new_balance = T::account_balance(relayer_id); - assert!( - new_balance > *old_balance, - "Relayer haven't received reward for relaying message: old balance = {:?}, new balance = {:?}", - old_balance, - new_balance, - ); -} diff --git a/modules/messages/src/inbound_lane.rs b/modules/messages/src/inbound_lane.rs index 00875bb878..cae7692704 100644 --- a/modules/messages/src/inbound_lane.rs +++ b/modules/messages/src/inbound_lane.rs @@ -16,13 +16,17 @@ //! Everything about incoming messages receival. +use crate::Config; + use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; use bp_runtime::messages::MessageDispatchResult; -use frame_support::RuntimeDebug; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{traits::Get, RuntimeDebug}; +use scale_info::{Type, TypeInfo}; use sp_std::prelude::PartialEq; /// Inbound lane storage. @@ -44,6 +48,68 @@ pub trait InboundLaneStorage { fn set_data(&mut self, data: InboundLaneData); } +/// Inbound lane data wrapper that implements `MaxEncodedLen`. +/// +/// We have already had `MaxEncodedLen`-like functionality before, but its usage has +/// been localized and we haven't been passing bounds (maximal count of unrewarded relayer entries, +/// maximal count of unconfirmed messages) everywhere. This wrapper allows us to avoid passing +/// these generic bounds all over the code. +/// +/// The encoding of this type matches encoding of the corresponding `MessageData`. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] +pub struct StoredInboundLaneData, I: 'static>(pub InboundLaneData); + +impl, I: 'static> sp_std::ops::Deref for StoredInboundLaneData { + type Target = InboundLaneData; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl, I: 'static> sp_std::ops::DerefMut for StoredInboundLaneData { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl, I: 'static> Default for StoredInboundLaneData { + fn default() -> Self { + StoredInboundLaneData(Default::default()) + } +} + +impl, I: 'static> From> + for InboundLaneData +{ + fn from(data: StoredInboundLaneData) -> Self { + data.0 + } +} + +impl, I: 'static> EncodeLike> + for InboundLaneData +{ +} + +impl, I: 'static> TypeInfo for StoredInboundLaneData { + type Identity = Self; + + fn type_info() -> Type { + InboundLaneData::::type_info() + } +} + +impl, I: 'static> MaxEncodedLen for StoredInboundLaneData { + fn max_encoded_len() -> usize { + InboundLaneData::::encoded_size_hint( + T::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize, + T::MaxUnconfirmedMessagesAtInboundLane::get() as usize, + ) + .unwrap_or(usize::MAX) + } +} + /// Result of single message receival. #[derive(RuntimeDebug, PartialEq, Eq)] pub enum ReceivalResult { @@ -333,7 +399,7 @@ mod tests { run_test(|| { let mut lane = inbound_lane::(TEST_LANE_ID); let max_nonce = - ::MaxUnrewardedRelayerEntriesAtInboundLane::get(); + ::MaxUnrewardedRelayerEntriesAtInboundLane::get(); for current_nonce in 1..max_nonce + 1 { assert_eq!( lane.receive_message::( @@ -372,8 +438,7 @@ mod tests { fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { let mut lane = inbound_lane::(TEST_LANE_ID); - let max_nonce = - ::MaxUnconfirmedMessagesAtInboundLane::get(); + let max_nonce = ::MaxUnconfirmedMessagesAtInboundLane::get(); for current_nonce in 1..=max_nonce { assert_eq!( lane.receive_message::( diff --git a/modules/messages/src/instant_payments.rs b/modules/messages/src/instant_payments.rs deleted file mode 100644 index 2a620a9522..0000000000 --- a/modules/messages/src/instant_payments.rs +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Implementation of `MessageDeliveryAndDispatchPayment` trait on top of `Currency` trait. -//! -//! The payment is first transferred to a special `relayers-fund` account and only transferred -//! to the actual relayer in case confirmation is received. - -use crate::OutboundMessages; - -use bp_messages::{ - source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards, SenderOrigin}, - LaneId, MessageKey, MessageNonce, UnrewardedRelayer, -}; -use codec::Encode; -use frame_support::traits::{Currency as CurrencyT, ExistenceRequirement, Get}; -use num_traits::{SaturatingAdd, Zero}; -use sp_runtime::traits::Saturating; -use sp_std::{collections::vec_deque::VecDeque, fmt::Debug, ops::RangeInclusive}; - -/// Error that occurs when message fee is non-zero, but payer is not defined. -const NON_ZERO_MESSAGE_FEE_CANT_BE_PAID_BY_NONE: &str = - "Non-zero message fee can't be paid by "; - -/// Instant message payments made in given currency. -/// -/// The balance is initially reserved in a special `relayers-fund` account, and transferred -/// to the relayer when message delivery is confirmed. -/// -/// Additionally, confirmation transaction submitter (`confirmation_relayer`) is reimbursed -/// with the confirmation rewards (part of message fee, reserved to pay for delivery confirmation). -/// -/// NOTE The `relayers-fund` account must always exist i.e. be over Existential Deposit (ED; the -/// pallet enforces that) to make sure that even if the message cost is below ED it is still paid -/// to the relayer account. -/// NOTE It's within relayer's interest to keep their balance above ED as well, to make sure they -/// can receive the payment. -pub struct InstantCurrencyPayments { - _phantom: sp_std::marker::PhantomData<(T, I, Currency, GetConfirmationFee)>, -} - -impl - MessageDeliveryAndDispatchPayment - for InstantCurrencyPayments -where - T: frame_system::Config + crate::Config, - I: 'static, - T::Origin: SenderOrigin, - Currency: CurrencyT, - Currency::Balance: From, - GetConfirmationFee: Get, -{ - type Error = &'static str; - - fn pay_delivery_and_dispatch_fee( - submitter: &T::Origin, - fee: &Currency::Balance, - relayer_fund_account: &T::AccountId, - ) -> Result<(), Self::Error> { - let submitter_account = match submitter.linked_account() { - Some(submitter_account) => submitter_account, - None if !fee.is_zero() => { - // if we'll accept some message that has declared that the `fee` has been paid but - // it isn't actually paid, then it'll lead to problems with delivery confirmation - // payments (see `pay_relayer_rewards` && `confirmation_relayer` in particular) - return Err(NON_ZERO_MESSAGE_FEE_CANT_BE_PAID_BY_NONE) - }, - None => { - // message lane verifier has accepted the message before, so this message - // is unpaid **by design** - // => let's just do nothing - return Ok(()) - }, - }; - - if !frame_system::Pallet::::account_exists(relayer_fund_account) { - return Err("The relayer fund account must exist for the message lanes pallet to work correctly."); - } - - Currency::transfer( - &submitter_account, - relayer_fund_account, - *fee, - // it's fine for the submitter to go below Existential Deposit and die. - ExistenceRequirement::AllowDeath, - ) - .map_err(Into::into) - } - - fn pay_relayers_rewards( - lane_id: LaneId, - messages_relayers: VecDeque>, - confirmation_relayer: &T::AccountId, - received_range: &RangeInclusive, - relayer_fund_account: &T::AccountId, - ) { - let relayers_rewards = - cal_relayers_rewards::(lane_id, messages_relayers, received_range); - if !relayers_rewards.is_empty() { - pay_relayers_rewards::( - confirmation_relayer, - relayers_rewards, - relayer_fund_account, - GetConfirmationFee::get(), - ); - } - } -} - -/// Calculate the relayers rewards -pub(crate) fn cal_relayers_rewards( - lane_id: LaneId, - messages_relayers: VecDeque>, - received_range: &RangeInclusive, -) -> RelayersRewards -where - T: frame_system::Config + crate::Config, - I: 'static, -{ - // remember to reward relayers that have delivered messages - // this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain - let mut relayers_rewards: RelayersRewards<_, T::OutboundMessageFee> = RelayersRewards::new(); - for entry in messages_relayers { - let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start()); - let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end()); - - // loop won't proceed if current entry is ahead of received range (begin > end). - // this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged chain - let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default(); - for nonce in nonce_begin..nonce_end + 1 { - let message_data = OutboundMessages::::get(MessageKey { lane_id, nonce }) - .expect("message was just confirmed; we never prune unconfirmed messages; qed"); - relayer_reward.reward = relayer_reward.reward.saturating_add(&message_data.fee); - relayer_reward.messages += 1; - } - } - relayers_rewards -} - -/// Pay rewards to given relayers, optionally rewarding confirmation relayer. -fn pay_relayers_rewards( - confirmation_relayer: &AccountId, - relayers_rewards: RelayersRewards, - relayer_fund_account: &AccountId, - confirmation_fee: Currency::Balance, -) where - AccountId: Debug + Encode + PartialEq, - Currency: CurrencyT, - Currency::Balance: From, -{ - // reward every relayer except `confirmation_relayer` - let mut confirmation_relayer_reward = Currency::Balance::zero(); - for (relayer, reward) in relayers_rewards { - let mut relayer_reward = reward.reward; - - if relayer != *confirmation_relayer { - // If delivery confirmation is submitted by other relayer, let's deduct confirmation fee - // from relayer reward. - // - // If confirmation fee has been increased (or if it was the only component of message - // fee), then messages relayer may receive zero reward. - let mut confirmation_reward = confirmation_fee.saturating_mul(reward.messages.into()); - if confirmation_reward > relayer_reward { - confirmation_reward = relayer_reward; - } - relayer_reward = relayer_reward.saturating_sub(confirmation_reward); - confirmation_relayer_reward = - confirmation_relayer_reward.saturating_add(confirmation_reward); - } else { - // If delivery confirmation is submitted by this relayer, let's add confirmation fee - // from other relayers to this relayer reward. - confirmation_relayer_reward = confirmation_relayer_reward.saturating_add(reward.reward); - continue - } - - pay_relayer_reward::(relayer_fund_account, &relayer, relayer_reward); - } - - // finally - pay reward to confirmation relayer - pay_relayer_reward::( - relayer_fund_account, - confirmation_relayer, - confirmation_relayer_reward, - ); -} - -/// Transfer funds from relayers fund account to given relayer. -fn pay_relayer_reward( - relayer_fund_account: &AccountId, - relayer_account: &AccountId, - reward: Currency::Balance, -) where - AccountId: Debug, - Currency: CurrencyT, -{ - if reward.is_zero() { - return - } - - let pay_result = Currency::transfer( - relayer_fund_account, - relayer_account, - reward, - // the relayer fund account must stay above ED (needs to be pre-funded) - ExistenceRequirement::KeepAlive, - ); - - match pay_result { - Ok(_) => log::trace!( - target: "runtime::bridge-messages", - "Rewarded relayer {:?} with {:?}", - relayer_account, - reward, - ), - Err(error) => log::trace!( - target: "runtime::bridge-messages", - "Failed to pay relayer {:?} reward {:?}: {:?}", - relayer_account, - reward, - error, - ), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::{ - run_test, AccountId as TestAccountId, Balance as TestBalance, Origin, TestRuntime, - }; - use bp_messages::source_chain::RelayerRewards; - - type Balances = pallet_balances::Pallet; - - const RELAYER_1: TestAccountId = 1; - const RELAYER_2: TestAccountId = 2; - const RELAYER_3: TestAccountId = 3; - const RELAYERS_FUND_ACCOUNT: TestAccountId = crate::mock::ENDOWED_ACCOUNT; - - fn relayers_rewards() -> RelayersRewards { - vec![ - (RELAYER_1, RelayerRewards { reward: 100, messages: 2 }), - (RELAYER_2, RelayerRewards { reward: 100, messages: 3 }), - ] - .into_iter() - .collect() - } - - #[test] - fn pay_delivery_and_dispatch_fee_fails_on_non_zero_fee_and_unknown_payer() { - frame_support::parameter_types! { - const GetConfirmationFee: TestBalance = 0; - }; - - run_test(|| { - let result = InstantCurrencyPayments::< - TestRuntime, - (), - Balances, - GetConfirmationFee, - >::pay_delivery_and_dispatch_fee( - &Origin::root(), - &100, - &RELAYERS_FUND_ACCOUNT, - ); - assert_eq!(result, Err(NON_ZERO_MESSAGE_FEE_CANT_BE_PAID_BY_NONE)); - }); - } - - #[test] - fn pay_delivery_and_dispatch_succeeds_on_zero_fee_and_unknown_payer() { - frame_support::parameter_types! { - const GetConfirmationFee: TestBalance = 0; - }; - - run_test(|| { - let result = InstantCurrencyPayments::< - TestRuntime, - (), - Balances, - GetConfirmationFee, - >::pay_delivery_and_dispatch_fee( - &Origin::root(), - &0, - &RELAYERS_FUND_ACCOUNT, - ); - assert!(result.is_ok()); - }); - } - - #[test] - fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() { - run_test(|| { - pay_relayers_rewards::( - &RELAYER_2, - relayers_rewards(), - &RELAYERS_FUND_ACCOUNT, - 10, - ); - - assert_eq!(Balances::free_balance(&RELAYER_1), 80); - assert_eq!(Balances::free_balance(&RELAYER_2), 120); - }); - } - - #[test] - fn confirmation_relayer_is_rewarded_if_it_has_not_delivered_any_delivered_messages() { - run_test(|| { - pay_relayers_rewards::( - &RELAYER_3, - relayers_rewards(), - &RELAYERS_FUND_ACCOUNT, - 10, - ); - - assert_eq!(Balances::free_balance(&RELAYER_1), 80); - assert_eq!(Balances::free_balance(&RELAYER_2), 70); - assert_eq!(Balances::free_balance(&RELAYER_3), 50); - }); - } - - #[test] - fn only_confirmation_relayer_is_rewarded_if_confirmation_fee_has_significantly_increased() { - run_test(|| { - pay_relayers_rewards::( - &RELAYER_3, - relayers_rewards(), - &RELAYERS_FUND_ACCOUNT, - 1000, - ); - - assert_eq!(Balances::free_balance(&RELAYER_1), 0); - assert_eq!(Balances::free_balance(&RELAYER_2), 0); - assert_eq!(Balances::free_balance(&RELAYER_3), 200); - }); - } -} diff --git a/modules/messages/src/lib.rs b/modules/messages/src/lib.rs index a344cedae2..c2e4dce9b2 100644 --- a/modules/messages/src/lib.rs +++ b/modules/messages/src/lib.rs @@ -37,7 +37,10 @@ // Generated by `decl_event!` #![allow(clippy::unused_unit)] -pub use crate::weights_ext::{ +pub use inbound_lane::StoredInboundLaneData; +pub use outbound_lane::StoredMessageData; +pub use weights::WeightInfo; +pub use weights_ext::{ ensure_able_to_receive_confirmation, ensure_able_to_receive_message, ensure_weights_are_correct, WeightInfoExt, EXPECTED_DEFAULT_MESSAGE_LENGTH, }; @@ -45,39 +48,38 @@ pub use crate::weights_ext::{ use crate::{ inbound_lane::{InboundLane, InboundLaneStorage, ReceivalResult}, outbound_lane::{OutboundLane, OutboundLaneStorage, ReceivalConfirmationResult}, - weights::WeightInfo, }; use bp_messages::{ source_chain::{ LaneMessageVerifier, MessageDeliveryAndDispatchPayment, OnDeliveryConfirmed, - OnMessageAccepted, SendMessageArtifacts, TargetHeaderChain, + OnMessageAccepted, RelayersRewards, SendMessageArtifacts, TargetHeaderChain, }, target_chain::{ DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain, }, - total_unrewarded_messages, DeliveredMessages, InboundLaneData, LaneId, MessageData, MessageKey, - MessageNonce, OperatingMode, OutboundLaneData, Parameter as MessagesParameter, + total_unrewarded_messages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, + MessageData, MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, + OutboundMessageDetails, Parameter as MessagesParameter, UnrewardedRelayer, UnrewardedRelayersState, }; -use bp_runtime::{ChainId, Size}; -use codec::{Decode, Encode}; +use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, Size}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - fail, + ensure, fail, traits::Get, weights::{Pays, PostDispatchInfo}, }; -use frame_system::RawOrigin; use num_traits::{SaturatingAdd, Zero}; -use sp_core::H256; -use sp_runtime::traits::{BadOrigin, Convert}; -use sp_std::{cell::RefCell, cmp::PartialOrd, marker::PhantomData, prelude::*}; +use sp_std::{ + cell::RefCell, cmp::PartialOrd, collections::vec_deque::VecDeque, marker::PhantomData, + ops::RangeInclusive, prelude::*, +}; mod inbound_lane; mod outbound_lane; mod weights_ext; -pub mod instant_payments; pub mod weights; #[cfg(feature = "runtime-benchmarks")] @@ -88,6 +90,9 @@ mod mock; pub use pallet::*; +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-messages"; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -140,6 +145,9 @@ pub mod pallet { /// these messages are from different lanes. type MaxUnconfirmedMessagesAtInboundLane: Get; + /// Maximal size of the outbound payload. + #[pallet::constant] + type MaximalOutboundPayloadSize: Get; /// Payload type of outbound messages. This payload is dispatched on the bridged chain. type OutboundPayload: Parameter + Size; /// Message fee type of outbound messages. This fee is paid on this chain. @@ -149,20 +157,16 @@ pub mod pallet { + Parameter + SaturatingAdd + Zero - + Copy; + + Copy + + MaxEncodedLen; /// Payload type of inbound messages. This payload is dispatched on this chain. type InboundPayload: Decode; /// Message fee type of inbound messages. This fee is paid on the bridged chain. - type InboundMessageFee: Decode; + type InboundMessageFee: Decode + Zero; /// Identifier of relayer that deliver messages to this chain. Relayer reward is paid on the /// bridged chain. - type InboundRelayer: Parameter; - - /// A type which can be turned into an AccountId from a 256-bit hash. - /// - /// Used when deriving the shared relayer fund account. - type AccountIdConverter: sp_runtime::traits::Convert; + type InboundRelayer: Parameter + MaxEncodedLen; // Types that are used by outbound_lane (on source chain). @@ -211,9 +215,15 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(PhantomData<(T, I)>); + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = MessagesOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + #[pallet::call] impl, I: 'static> Pallet { /// Change `PalletOwner`. @@ -221,18 +231,7 @@ pub mod pallet { /// May only be called either by root, or by `PalletOwner`. #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { - ensure_owner_or_root::(origin)?; - match new_owner { - Some(new_owner) => { - PalletOwner::::put(&new_owner); - log::info!(target: "runtime::bridge-messages", "Setting pallet Owner to: {:?}", new_owner); - }, - None => { - PalletOwner::::kill(); - log::info!(target: "runtime::bridge-messages", "Removed Owner of pallet."); - }, - } - Ok(()) + >::set_owner(origin, new_owner) } /// Halt or resume all/some pallet operations. @@ -241,16 +240,9 @@ pub mod pallet { #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] pub fn set_operating_mode( origin: OriginFor, - operating_mode: OperatingMode, + operating_mode: MessagesOperatingMode, ) -> DispatchResult { - ensure_owner_or_root::(origin)?; - PalletOperatingMode::::put(operating_mode); - log::info!( - target: "runtime::bridge-messages", - "Setting messages pallet operating mode to {:?}.", - operating_mode, - ); - Ok(()) + >::set_operating_mode(origin, operating_mode) } /// Update pallet parameter. @@ -264,9 +256,9 @@ pub mod pallet { origin: OriginFor, parameter: T::Parameter, ) -> DispatchResult { - ensure_owner_or_root::(origin)?; + Self::ensure_owner_or_root(origin)?; parameter.save(); - Self::deposit_event(Event::ParameterUpdated(parameter)); + Self::deposit_event(Event::ParameterUpdated { parameter }); Ok(()) } @@ -294,7 +286,7 @@ pub mod pallet { nonce: MessageNonce, additional_fee: T::OutboundMessageFee, ) -> DispatchResultWithPostInfo { - ensure_not_halted::()?; + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; // if someone tries to pay for already-delivered message, we're rejecting this intention // (otherwise this additional fee will be locked forever in relayers fund) // @@ -314,16 +306,14 @@ pub mod pallet { T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee( &origin, &additional_fee, - &relayer_fund_account_id::(), ) .map_err(|err| { log::trace!( - target: "runtime::bridge-messages", - "Submitter can't pay additional fee {:?} for the message {:?}/{:?} to {:?}: {:?}", + target: LOG_TARGET, + "Submitter can't pay additional fee {:?} for the message {:?}/{:?}: {:?}", additional_fee, lane_id, nonce, - relayer_fund_account_id::(), err, ); @@ -365,7 +355,7 @@ pub mod pallet { messages_count: u32, dispatch_weight: Weight, ) -> DispatchResultWithPostInfo { - ensure_not_halted::()?; + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; let relayer_id_at_this_chain = ensure_signed(origin)?; // reject transactions that are declaring too many messages @@ -398,11 +388,7 @@ pub mod pallet { T::InboundPayload, >(proof, messages_count) .map_err(|err| { - log::trace!( - target: "runtime::bridge-messages", - "Rejecting invalid messages proof: {:?}", - err, - ); + log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); Error::::InvalidMessagesProof })?; @@ -418,7 +404,7 @@ pub mod pallet { let updated_latest_confirmed_nonce = lane.receive_state_update(lane_state); if let Some(updated_latest_confirmed_nonce) = updated_latest_confirmed_nonce { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Received lane {:?} state update: latest_confirmed_nonce={}", lane_id, updated_latest_confirmed_nonce, @@ -426,16 +412,16 @@ pub mod pallet { } } - for message in lane_data.messages { + for mut message in lane_data.messages { debug_assert_eq!(message.key.lane_id, lane_id); // ensure that relayer has declared enough weight for dispatching next message // on this lane. We can't dispatch lane messages out-of-order, so if declared // weight is not enough, let's move to next lane - let dispatch_weight = T::MessageDispatch::dispatch_weight(&message); + let dispatch_weight = T::MessageDispatch::dispatch_weight(&mut message); if dispatch_weight > dispatch_weight_left { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Cannot dispatch any more messages on lane {:?}. Weight: declared={}, left={}", lane_id, dispatch_weight, @@ -487,7 +473,7 @@ pub mod pallet { } log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Received messages: total={}, valid={}. Weight used: {}/{}", total_messages, valid_messages, @@ -509,7 +495,7 @@ pub mod pallet { proof: MessagesDeliveryProofOf, relayers_state: UnrewardedRelayersState, ) -> DispatchResultWithPostInfo { - ensure_not_halted::()?; + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; // why do we need to know the weight of this (`receive_messages_delivery_proof`) call? // Because we may want to return some funds for messages that are not processed by the @@ -533,7 +519,7 @@ pub mod pallet { let (lane_id, lane_data) = T::TargetHeaderChain::verify_messages_delivery_proof(proof) .map_err(|err| { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Rejecting invalid messages delivery proof: {:?}", err, ); @@ -551,6 +537,12 @@ pub mod pallet { relayers_state.unrewarded_relayer_entries, Error::::InvalidUnrewardedRelayersState ); + // the `last_delivered_nonce` field may also be used by the signed extension. Even + // though providing wrong value isn't critical, let's also check it here. + ensure!( + lane_data.last_delivered_nonce() == relayers_state.last_delivered_nonce, + Error::::InvalidUnrewardedRelayersState + ); // mark messages as delivered let mut lane = outbound_lane::(lane_id); @@ -567,7 +559,7 @@ pub mod pallet { to_confirm_messages_count, ) => { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Messages delivery proof contains too many messages to confirm: {} vs declared {}", to_confirm_messages_count, relayers_state.total_messages, @@ -577,7 +569,7 @@ pub mod pallet { }, error => { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Messages delivery proof contains invalid unrewarded relayers vec: {:?}", error, ); @@ -596,7 +588,7 @@ pub mod pallet { Some(difference) if difference == 0 => (), Some(difference) => { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "T::OnDeliveryConfirmed callback has spent less weight than expected. Refunding: \ {} - {} = {}", preliminary_callback_overhead, @@ -611,7 +603,7 @@ pub mod pallet { "T::OnDeliveryConfirmed callback consumed too much weight." ); log::error!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "T::OnDeliveryConfirmed callback has spent more weight that it is allowed to: \ {} vs {}", preliminary_callback_overhead, @@ -622,22 +614,22 @@ pub mod pallet { // emit 'delivered' event let received_range = confirmed_messages.begin..=confirmed_messages.end; - Self::deposit_event(Event::MessagesDelivered(lane_id, confirmed_messages)); + Self::deposit_event(Event::MessagesDelivered { + lane_id, + messages: confirmed_messages, + }); // if some new messages have been confirmed, reward relayers - let relayer_fund_account = - relayer_fund_account_id::(); >::MessageDeliveryAndDispatchPayment::pay_relayers_rewards( lane_id, lane_data.relayers, &confirmation_relayer, &received_range, - &relayer_fund_account, ); } log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Received messages delivery proof up to (and including) {} at lane {:?}", last_delivered_nonce, lane_id, @@ -651,17 +643,19 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { /// Pallet parameter has been updated. - ParameterUpdated(T::Parameter), + ParameterUpdated { parameter: T::Parameter }, /// Message has been accepted and is waiting to be delivered. - MessageAccepted(LaneId, MessageNonce), + MessageAccepted { lane_id: LaneId, nonce: MessageNonce }, /// Messages in the inclusive range have been delivered to the bridged chain. - MessagesDelivered(LaneId, DeliveredMessages), + MessagesDelivered { lane_id: LaneId, messages: DeliveredMessages }, } #[pallet::error] pub enum Error { - /// All pallet operations are halted. - Halted, + /// Pallet is not in Normal operating mode. + NotOperatingNormally, + /// The message is too large to be sent over the bridge. + MessageIsTooLarge, /// Message has been treated as invalid by chain verifier. MessageRejectedByChainVerifier, /// Message has been treated as invalid by lane verifier. @@ -686,6 +680,8 @@ pub mod pallet { /// The number of actually confirmed messages is going to be larger than the number of /// messages in the proof. This may mean that this or bridged chain storage is corrupted. TryingToConfirmMoreMessagesThanExpected, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), } /// Optional pallet owner. @@ -704,12 +700,12 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn operating_mode)] pub type PalletOperatingMode, I: 'static = ()> = - StorageValue<_, OperatingMode, ValueQuery>; + StorageValue<_, MessagesOperatingMode, ValueQuery>; /// Map of lane id => inbound lane data. #[pallet::storage] pub type InboundLanes, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, LaneId, InboundLaneData, ValueQuery>; + StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData, ValueQuery>; /// Map of lane id => outbound lane data. #[pallet::storage] @@ -719,12 +715,12 @@ pub mod pallet { /// All queued outbound messages. #[pallet::storage] pub type OutboundMessages, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, MessageKey, MessageData>; + StorageMap<_, Blake2_128Concat, MessageKey, StoredMessageData>; #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { /// Initial pallet operating mode. - pub operating_mode: OperatingMode, + pub operating_mode: MessagesOperatingMode, /// Initial pallet owner. pub owner: Option, /// Dummy marker. @@ -745,7 +741,7 @@ pub mod pallet { #[pallet::genesis_build] impl, I: 'static> GenesisBuild for GenesisConfig { fn build(&self) { - PalletOperatingMode::::put(&self.operating_mode); + PalletOperatingMode::::put(self.operating_mode); if let Some(ref owner) = self.owner { PalletOwner::::put(owner); } @@ -758,20 +754,25 @@ pub mod pallet { lane: LaneId, nonce: MessageNonce, ) -> Option> { - OutboundMessages::::get(MessageKey { lane_id: lane, nonce }) + OutboundMessages::::get(MessageKey { lane_id: lane, nonce }).map(Into::into) } - } -} -/// AccountId of the shared relayer fund account. -/// -/// This account is passed to `MessageDeliveryAndDispatchPayment` trait, and depending -/// on the implementation it can be used to store relayers rewards. -/// See [`InstantCurrencyPayments`] for a concrete implementation. -pub fn relayer_fund_account_id>( -) -> AccountId { - let encoded_id = bp_runtime::derive_relayer_fund_account_id(bp_runtime::NO_INSTANCE_ID); - AccountIdConverter::convert(encoded_id) + /// Prepare data, related to given inbound message. + pub fn inbound_message_data( + lane: LaneId, + payload: MessagePayload, + outbound_details: OutboundMessageDetails, + ) -> InboundMessageDetails { + let mut dispatch_message = DispatchMessage { + key: MessageKey { lane_id: lane, nonce: outbound_details.nonce }, + data: MessageData { payload, fee: outbound_details.delivery_and_dispatch_fee } + .into(), + }; + InboundMessageDetails { + dispatch_weight: T::MessageDispatch::dispatch_weight(&mut dispatch_message), + } + } + } } impl @@ -809,13 +810,19 @@ fn send_message, I: 'static>( > { ensure_normal_operating_mode::()?; + // the most lightweigh check is the message size check + ensure!( + payload.size() <= T::MaximalOutboundPayloadSize::get(), + Error::::MessageIsTooLarge, + ); + // initially, actual (post-dispatch) weight is equal to pre-dispatch weight let mut actual_weight = T::WeightInfo::send_message_weight(&payload, T::DbWeight::get()); // let's first check if message can be delivered to target chain T::TargetHeaderChain::verify_message(&payload).map_err(|err| { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Message to lane {:?} is rejected by target chain: {:?}", lane_id, err, @@ -835,7 +842,7 @@ fn send_message, I: 'static>( ) .map_err(|err| { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Message to lane {:?} is rejected by lane verifier: {:?}", lane_id, err, @@ -848,11 +855,10 @@ fn send_message, I: 'static>( T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee( &submitter, &delivery_and_dispatch_fee, - &relayer_fund_account_id::(), ) .map_err(|err| { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Message to lane {:?} is rejected because submitter is unable to pay fee {:?}: {:?}", lane_id, delivery_and_dispatch_fee, @@ -878,7 +884,7 @@ fn send_message, I: 'static>( Some(difference) if difference == 0 => (), Some(difference) => { log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "T::OnMessageAccepted callback has spent less weight than expected. Refunding: \ {} - {} = {}", single_message_callback_overhead, @@ -890,7 +896,7 @@ fn send_message, I: 'static>( None => { debug_assert!(false, "T::OnMessageAccepted callback consumed too much weight."); log::error!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "T::OnMessageAccepted callback has spent more weight that it is allowed to: \ {} vs {}", single_message_callback_overhead, @@ -909,45 +915,58 @@ fn send_message, I: 'static>( } log::trace!( - target: "runtime::bridge-messages", + target: LOG_TARGET, "Accepted message {} to lane {:?}. Message size: {:?}", nonce, lane_id, encoded_payload_len, ); - Pallet::::deposit_event(Event::MessageAccepted(lane_id, nonce)); + Pallet::::deposit_event(Event::MessageAccepted { lane_id, nonce }); Ok(SendMessageArtifacts { nonce, weight: actual_weight }) } -/// Ensure that the origin is either root, or `PalletOwner`. -fn ensure_owner_or_root, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> { - match origin.into() { - Ok(RawOrigin::Root) => Ok(()), - Ok(RawOrigin::Signed(ref signer)) - if Some(signer) == Pallet::::module_owner().as_ref() => - Ok(()), - _ => Err(BadOrigin), +/// Calculate the relayers rewards +pub fn calc_relayers_rewards( + lane_id: LaneId, + messages_relayers: VecDeque>, + received_range: &RangeInclusive, +) -> RelayersRewards +where + T: frame_system::Config + crate::Config, + I: 'static, +{ + // remember to reward relayers that have delivered messages + // this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain + let mut relayers_rewards: RelayersRewards<_, T::OutboundMessageFee> = RelayersRewards::new(); + for entry in messages_relayers { + let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start()); + let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end()); + + // loop won't proceed if current entry is ahead of received range (begin > end). + // this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged chain + let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default(); + for nonce in nonce_begin..=nonce_end { + let key = MessageKey { lane_id, nonce }; + let message_data = OutboundMessages::::get(key) + .expect("message was just confirmed; we never prune unconfirmed messages; qed"); + relayer_reward.reward = relayer_reward.reward.saturating_add(&message_data.fee); + relayer_reward.messages += 1; + } } + relayers_rewards } /// Ensure that the pallet is in normal operational mode. fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error> { - if PalletOperatingMode::::get() != OperatingMode::Normal { - Err(Error::::Halted) - } else { - Ok(()) + if PalletOperatingMode::::get() == + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + { + return Ok(()) } -} -/// Ensure that the pallet is not halted. -fn ensure_not_halted, I: 'static>() -> Result<(), Error> { - if PalletOperatingMode::::get() == OperatingMode::Halted { - Err(Error::::Halted) - } else { - Ok(()) - } + Err(Error::::NotOperatingNormally) } /// Creates new inbound lane object, backed by runtime storage. @@ -1002,7 +1021,8 @@ impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< match self.cached_data.clone().into_inner() { Some(data) => data, None => { - let data = InboundLanes::::get(&self.lane_id); + let data: InboundLaneData = + InboundLanes::::get(self.lane_id).into(); *self.cached_data.try_borrow_mut().expect( "we're in the single-threaded environment;\ we have no recursive borrows; qed", @@ -1017,7 +1037,7 @@ impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< "we're in the single-threaded environment;\ we have no recursive borrows; qed", ) = Some(data.clone()); - InboundLanes::::insert(&self.lane_id, data) + InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) } } @@ -1035,16 +1055,17 @@ impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag } fn data(&self) -> OutboundLaneData { - OutboundLanes::::get(&self.lane_id) + OutboundLanes::::get(self.lane_id) } fn set_data(&mut self, data: OutboundLaneData) { - OutboundLanes::::insert(&self.lane_id, data) + OutboundLanes::::insert(self.lane_id, data) } #[cfg(test)] fn message(&self, nonce: &MessageNonce) -> Option> { OutboundMessages::::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) + .map(Into::into) } fn save_message( @@ -1088,13 +1109,15 @@ fn verify_and_decode_messages_proof, Fee, Dispatch mod tests { use super::*; use crate::mock::{ - message, message_payload, run_test, unrewarded_relayer, Event as TestEvent, Origin, - TestMessageDeliveryAndDispatchPayment, TestMessagesDeliveryProof, TestMessagesParameter, - TestMessagesProof, TestOnDeliveryConfirmed1, TestOnDeliveryConfirmed2, - TestOnMessageAccepted, TestRuntime, TokenConversionRate, PAYLOAD_REJECTED_BY_TARGET_CHAIN, - REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, + message, message_payload, run_test, unrewarded_relayer, Balance, Event as TestEvent, + Origin, TestMessageDeliveryAndDispatchPayment, TestMessagesDeliveryProof, + TestMessagesParameter, TestMessagesProof, TestOnDeliveryConfirmed1, + TestOnDeliveryConfirmed2, TestOnMessageAccepted, TestRuntime, TokenConversionRate, + MAX_OUTBOUND_PAYLOAD_SIZE, PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, + TEST_RELAYER_A, TEST_RELAYER_B, }; use bp_messages::{UnrewardedRelayer, UnrewardedRelayersState}; + use bp_test_utils::generate_owned_bridge_module_tests; use frame_support::{ assert_noop, assert_ok, storage::generator::{StorageMap, StorageValue}, @@ -1111,7 +1134,9 @@ mod tests { fn inbound_unrewarded_relayers_state( lane: bp_messages::LaneId, ) -> bp_messages::UnrewardedRelayersState { - let relayers = InboundLanes::::get(&lane).relayers; + let inbound_lane_data = InboundLanes::::get(lane).0; + let last_delivered_nonce = inbound_lane_data.last_delivered_nonce(); + let relayers = inbound_lane_data.relayers; bp_messages::UnrewardedRelayersState { unrewarded_relayer_entries: relayers.len() as _, messages_in_oldest_entry: relayers @@ -1119,6 +1144,7 @@ mod tests { .map(|entry| 1 + entry.messages.end - entry.messages.begin) .unwrap_or(0), total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX), + last_delivered_nonce, } } @@ -1142,7 +1168,10 @@ mod tests { System::::events(), vec![EventRecord { phase: Phase::Initialization, - event: TestEvent::Messages(Event::MessageAccepted(TEST_LANE_ID, message_nonce)), + event: TestEvent::Messages(Event::MessageAccepted { + lane_id: TEST_LANE_ID, + nonce: message_nonce + }), topics: vec![], }], ); @@ -1177,6 +1206,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 1, + last_delivered_nonce: 1, ..Default::default() }, )); @@ -1185,94 +1215,15 @@ mod tests { System::::events(), vec![EventRecord { phase: Phase::Initialization, - event: TestEvent::Messages(Event::MessagesDelivered( - TEST_LANE_ID, - DeliveredMessages::new(1, true), - )), + event: TestEvent::Messages(Event::MessagesDelivered { + lane_id: TEST_LANE_ID, + messages: DeliveredMessages::new(1, true), + }), topics: vec![], }], ); } - #[test] - fn pallet_owner_may_change_owner() { - run_test(|| { - PalletOwner::::put(2); - - assert_ok!(Pallet::::set_owner(Origin::root(), Some(1))); - assert_noop!( - Pallet::::set_operating_mode(Origin::signed(2), OperatingMode::Halted), - DispatchError::BadOrigin, - ); - assert_ok!(Pallet::::set_operating_mode( - Origin::root(), - OperatingMode::Halted - )); - - assert_ok!(Pallet::::set_owner(Origin::signed(1), None)); - assert_noop!( - Pallet::::set_operating_mode(Origin::signed(1), OperatingMode::Normal), - DispatchError::BadOrigin, - ); - assert_noop!( - Pallet::::set_operating_mode(Origin::signed(2), OperatingMode::Normal), - DispatchError::BadOrigin, - ); - assert_ok!(Pallet::::set_operating_mode( - Origin::root(), - OperatingMode::Normal - )); - }); - } - - #[test] - fn pallet_may_be_halted_by_root() { - run_test(|| { - assert_ok!(Pallet::::set_operating_mode( - Origin::root(), - OperatingMode::Halted - )); - assert_ok!(Pallet::::set_operating_mode( - Origin::root(), - OperatingMode::Normal - )); - }); - } - - #[test] - fn pallet_may_be_halted_by_owner() { - run_test(|| { - PalletOwner::::put(2); - - assert_ok!(Pallet::::set_operating_mode( - Origin::signed(2), - OperatingMode::Halted - )); - assert_ok!(Pallet::::set_operating_mode( - Origin::signed(2), - OperatingMode::Normal - )); - - assert_noop!( - Pallet::::set_operating_mode(Origin::signed(1), OperatingMode::Halted), - DispatchError::BadOrigin, - ); - assert_noop!( - Pallet::::set_operating_mode(Origin::signed(1), OperatingMode::Normal), - DispatchError::BadOrigin, - ); - - assert_ok!(Pallet::::set_operating_mode( - Origin::signed(2), - OperatingMode::Halted - )); - assert_noop!( - Pallet::::set_operating_mode(Origin::signed(1), OperatingMode::Normal), - DispatchError::BadOrigin, - ); - }); - } - #[test] fn pallet_parameter_may_be_updated_by_root() { run_test(|| { @@ -1289,7 +1240,7 @@ mod tests { System::::events(), vec![EventRecord { phase: Phase::Initialization, - event: TestEvent::Messages(Event::ParameterUpdated(parameter)), + event: TestEvent::Messages(Event::ParameterUpdated { parameter }), topics: vec![], }], ); @@ -1313,7 +1264,7 @@ mod tests { System::::events(), vec![EventRecord { phase: Phase::Initialization, - event: TestEvent::Messages(Event::ParameterUpdated(parameter)), + event: TestEvent::Messages(Event::ParameterUpdated { parameter }), topics: vec![], }], ); @@ -1375,7 +1326,9 @@ mod tests { // send message first to be able to check that delivery_proof fails later send_regular_message(); - PalletOperatingMode::::put(OperatingMode::Halted); + PalletOperatingMode::::put(MessagesOperatingMode::Basic( + BasicOperatingMode::Halted, + )); assert_noop!( Pallet::::send_message( @@ -1384,12 +1337,12 @@ mod tests { REGULAR_PAYLOAD, REGULAR_PAYLOAD.declared_weight, ), - Error::::Halted, + Error::::NotOperatingNormally, ); assert_noop!( Pallet::::increase_message_fee(Origin::signed(1), TEST_LANE_ID, 1, 1,), - Error::::Halted, + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), ); assert_noop!( @@ -1400,7 +1353,7 @@ mod tests { 1, REGULAR_PAYLOAD.declared_weight, ), - Error::::Halted, + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), ); assert_noop!( @@ -1419,9 +1372,10 @@ mod tests { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 1, total_messages: 1, + last_delivered_nonce: 1, }, ), - Error::::Halted, + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), ); }); } @@ -1432,7 +1386,9 @@ mod tests { // send message first to be able to check that delivery_proof fails later send_regular_message(); - PalletOperatingMode::::put(OperatingMode::RejectingOutboundMessages); + PalletOperatingMode::::put( + MessagesOperatingMode::RejectingOutboundMessages, + ); assert_noop!( Pallet::::send_message( @@ -1441,7 +1397,7 @@ mod tests { REGULAR_PAYLOAD, REGULAR_PAYLOAD.declared_weight, ), - Error::::Halted, + Error::::NotOperatingNormally, ); assert_ok!(Pallet::::increase_message_fee( @@ -1474,6 +1430,7 @@ mod tests { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 1, total_messages: 1, + last_delivered_nonce: 1, }, )); }); @@ -1486,6 +1443,39 @@ mod tests { }); } + #[test] + fn send_message_rejects_too_large_message() { + run_test(|| { + let mut message_payload = message_payload(1, 0); + // the payload isn't simply extra, so it'll definitely overflow + // `MAX_OUTBOUND_PAYLOAD_SIZE` if we add `MAX_OUTBOUND_PAYLOAD_SIZE` bytes to extra + message_payload + .extra + .extend_from_slice(&[0u8; MAX_OUTBOUND_PAYLOAD_SIZE as usize]); + assert_noop!( + Pallet::::send_message( + Origin::signed(1), + TEST_LANE_ID, + message_payload.clone(), + Balance::MAX, + ), + Error::::MessageIsTooLarge, + ); + + // let's check that we're able to send `MAX_OUTBOUND_PAYLOAD_SIZE` messages + while message_payload.size() > MAX_OUTBOUND_PAYLOAD_SIZE { + message_payload.extra.pop(); + } + assert_eq!(message_payload.size(), MAX_OUTBOUND_PAYLOAD_SIZE); + assert_ok!(Pallet::::send_message( + Origin::signed(1), + TEST_LANE_ID, + message_payload, + Balance::MAX, + ),); + }) + } + #[test] fn chain_verifier_rejects_invalid_message_in_send_message() { run_test(|| { @@ -1545,7 +1535,7 @@ mod tests { REGULAR_PAYLOAD.declared_weight, )); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); }); } @@ -1571,6 +1561,7 @@ mod tests { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, total_messages: 2, + last_delivered_nonce: 10, }, ); @@ -1589,7 +1580,7 @@ mod tests { )); assert_eq!( - InboundLanes::::get(TEST_LANE_ID), + InboundLanes::::get(TEST_LANE_ID).0, InboundLaneData { last_confirmed_nonce: 9, relayers: vec![ @@ -1606,6 +1597,7 @@ mod tests { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, total_messages: 2, + last_delivered_nonce: 11, }, ); }); @@ -1664,7 +1656,7 @@ mod tests { receive_messages_delivery_proof(); assert_eq!( - OutboundLanes::::get(&TEST_LANE_ID).latest_received_nonce, + OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 1, ); }); @@ -1701,6 +1693,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 1, + last_delivered_nonce: 1, ..Default::default() }, )); @@ -1726,6 +1719,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 2, total_messages: 2, + last_delivered_nonce: 2, ..Default::default() }, )); @@ -1770,6 +1764,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 2, + last_delivered_nonce: 2, ..Default::default() }, ), @@ -1795,6 +1790,33 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 2, total_messages: 1, + last_delivered_nonce: 2, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + + // when last delivered nonce is invalid + assert_noop!( + Pallet::::receive_messages_delivery_proof( + Origin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B) + ] + .into_iter() + .collect(), + ..Default::default() + } + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + total_messages: 2, + last_delivered_nonce: 8, ..Default::default() }, ), @@ -1817,7 +1839,7 @@ mod tests { 0, // weight may be zero in this case (all messages are improperly encoded) ),); - assert_eq!(InboundLanes::::get(&TEST_LANE_ID).last_delivered_nonce(), 1,); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1,); }); } @@ -1838,7 +1860,7 @@ mod tests { REGULAR_PAYLOAD.declared_weight + REGULAR_PAYLOAD.declared_weight, ),); - assert_eq!(InboundLanes::::get(&TEST_LANE_ID).last_delivered_nonce(), 3,); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 3,); }); } @@ -2031,6 +2053,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 2, + last_delivered_nonce: 2, ..Default::default() }, )); @@ -2041,6 +2064,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 1, + last_delivered_nonce: 3, ..Default::default() }, )); @@ -2068,6 +2092,7 @@ mod tests { let relayers_state = UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 3, + last_delivered_nonce: 3, ..Default::default() }; let pre_dispatch_weight = @@ -2142,7 +2167,7 @@ mod tests { TEST_LANE_ID, InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() }, ))), - UnrewardedRelayersState::default(), + UnrewardedRelayersState { last_delivered_nonce: 1, ..Default::default() }, ), Error::::TryingToConfirmMoreMessagesThanExpected, ); @@ -2154,8 +2179,8 @@ mod tests { run_test(|| { let mut small_payload = message_payload(0, 100); let mut large_payload = message_payload(1, 100); - small_payload.extra = vec![1; 100]; - large_payload.extra = vec![2; 16_384]; + small_payload.extra = vec![1; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 10]; + large_payload.extra = vec![2; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 5]; assert_ok!(Pallet::::send_message( Origin::signed(1), @@ -2221,6 +2246,7 @@ mod tests { UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: max_messages_to_prune, + last_delivered_nonce: max_messages_to_prune, ..Default::default() }, )); @@ -2301,4 +2327,30 @@ mod tests { bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, ); } + + #[test] + fn inbound_message_details_works() { + run_test(|| { + assert_eq!( + Pallet::::inbound_message_data( + TEST_LANE_ID, + REGULAR_PAYLOAD.encode(), + OutboundMessageDetails { + nonce: 0, + dispatch_weight: 0, + size: 0, + delivery_and_dispatch_fee: 0, + dispatch_fee_payment: + bp_runtime::messages::DispatchFeePayment::AtTargetChain, + }, + ), + InboundMessageDetails { dispatch_weight: REGULAR_PAYLOAD.declared_weight }, + ); + }); + } + + generate_owned_bridge_module_tests!( + MessagesOperatingMode::Basic(BasicOperatingMode::Normal), + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) + ); } diff --git a/modules/messages/src/mock.rs b/modules/messages/src/mock.rs index 75dcce8df0..9584d17b83 100644 --- a/modules/messages/src/mock.rs +++ b/modules/messages/src/mock.rs @@ -17,7 +17,7 @@ // From construct_runtime macro #![allow(clippy::from_over_into)] -use crate::{instant_payments::cal_relayers_rewards, Config}; +use crate::{calc_relayers_rewards, Config}; use bitvec::prelude::*; use bp_messages::{ @@ -68,14 +68,6 @@ pub struct TestPayload { pub type TestMessageFee = u64; pub type TestRelayer = u64; -pub struct AccountIdConverter; - -impl sp_runtime::traits::Convert for AccountIdConverter { - fn convert(hash: H256) -> AccountId { - hash.to_low_u64_ne() - } -} - type Block = frame_system::mocking::MockBlock; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -149,7 +141,7 @@ parameter_types! { pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16; pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32; pub storage TokenConversionRate: FixedU128 = 1.into(); - pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; + pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; } #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)] @@ -174,6 +166,7 @@ impl Config for TestRuntime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = frame_support::traits::ConstU32; type OutboundPayload = TestPayload; type OutboundMessageFee = TestMessageFee; @@ -181,8 +174,6 @@ impl Config for TestRuntime { type InboundMessageFee = TestMessageFee; type InboundRelayer = TestRelayer; - type AccountIdConverter = AccountIdConverter; - type TargetHeaderChain = TestTargetHeaderChain; type LaneMessageVerifier = TestLaneMessageVerifier; type MessageDeliveryAndDispatchPayment = TestMessageDeliveryAndDispatchPayment; @@ -198,18 +189,21 @@ impl SenderOrigin for Origin { fn linked_account(&self) -> Option { match self.caller { OriginCaller::system(frame_system::RawOrigin::Signed(ref submitter)) => - Some(submitter.clone()), + Some(*submitter), _ => None, } } } impl Size for TestPayload { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 16 + self.extra.len() as u32 } } +/// Maximal outbound payload size. +pub const MAX_OUTBOUND_PAYLOAD_SIZE: u32 = 4096; + /// Account that has balance to use in tests. pub const ENDOWED_ACCOUNT: AccountId = 0xDEAD; @@ -244,7 +238,7 @@ pub struct TestMessagesProof { } impl Size for TestMessagesProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 0 } } @@ -271,7 +265,7 @@ impl From>, ()>> for TestMessagesProof { pub struct TestMessagesDeliveryProof(pub Result<(LaneId, InboundLaneData), ()>); impl Size for TestMessagesDeliveryProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 0 } } @@ -356,7 +350,6 @@ impl MessageDeliveryAndDispatchPayment fn pay_delivery_and_dispatch_fee( submitter: &Origin, fee: &TestMessageFee, - _relayer_fund_account: &AccountId, ) -> Result<(), Self::Error> { if frame_support::storage::unhashed::get(b":reject-message-fee:") == Some(true) { return Err(TEST_ERROR) @@ -372,10 +365,9 @@ impl MessageDeliveryAndDispatchPayment message_relayers: VecDeque>, _confirmation_relayer: &AccountId, received_range: &RangeInclusive, - _relayer_fund_account: &AccountId, ) { let relayers_rewards = - cal_relayers_rewards::(lane_id, message_relayers, received_range); + calc_relayers_rewards::(lane_id, message_relayers, received_range); for (relayer, reward) in &relayers_rewards { let key = (b":relayer-reward:", relayer, reward.reward).encode(); frame_support::storage::unhashed::put(&key, &true); @@ -489,7 +481,7 @@ pub struct TestMessageDispatch; impl MessageDispatch for TestMessageDispatch { type DispatchPayload = TestPayload; - fn dispatch_weight(message: &DispatchMessage) -> Weight { + fn dispatch_weight(message: &mut DispatchMessage) -> Weight { match message.data.payload.as_ref() { Ok(payload) => payload.declared_weight, Err(_) => 0, diff --git a/modules/messages/src/outbound_lane.rs b/modules/messages/src/outbound_lane.rs index cfdc81acc3..bdd503c811 100644 --- a/modules/messages/src/outbound_lane.rs +++ b/modules/messages/src/outbound_lane.rs @@ -16,12 +16,16 @@ //! Everything about outgoing messages sending. +use crate::Config; + use bitvec::prelude::*; use bp_messages::{ DeliveredMessages, DispatchResultsBitVec, LaneId, MessageData, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; -use frame_support::RuntimeDebug; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{traits::Get, RuntimeDebug}; +use scale_info::{Type, TypeInfo}; use sp_std::collections::vec_deque::VecDeque; /// Outbound lane storage. @@ -44,6 +48,58 @@ pub trait OutboundLaneStorage { fn remove_message(&mut self, nonce: &MessageNonce); } +/// Outbound message data wrapper that implements `MaxEncodedLen`. +/// +/// We have already had `MaxEncodedLen`-like functionality before, but its usage has +/// been localized and we haven't been passing it everywhere. This wrapper allows us +/// to avoid passing these generic bounds all over the code. +/// +/// The encoding of this type matches encoding of the corresponding `MessageData`. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] +pub struct StoredMessageData, I: 'static>(pub MessageData); + +impl, I: 'static> sp_std::ops::Deref for StoredMessageData { + type Target = MessageData; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl, I: 'static> sp_std::ops::DerefMut for StoredMessageData { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl, I: 'static> From> + for MessageData +{ + fn from(data: StoredMessageData) -> Self { + data.0 + } +} + +impl, I: 'static> TypeInfo for StoredMessageData { + type Identity = Self; + + fn type_info() -> Type { + MessageData::::type_info() + } +} + +impl, I: 'static> EncodeLike> + for MessageData +{ +} + +impl, I: 'static> MaxEncodedLen for StoredMessageData { + fn max_encoded_len() -> usize { + T::OutboundMessageFee::max_encoded_len() + .saturating_add(T::MaximalOutboundPayloadSize::get() as usize) + } +} + /// Result of messages receival confirmation. #[derive(RuntimeDebug, PartialEq, Eq)] pub enum ReceivalConfirmationResult { @@ -74,7 +130,7 @@ pub struct OutboundLane { } impl OutboundLane { - /// Create new inbound lane backed by given storage. + /// Create new outbound lane backed by given storage. pub fn new(storage: S) -> Self { OutboundLane { storage } } @@ -148,19 +204,17 @@ impl OutboundLane { /// Returns number of pruned messages. pub fn prune_messages(&mut self, max_messages_to_prune: MessageNonce) -> MessageNonce { let mut pruned_messages = 0; - let mut anything_changed = false; let mut data = self.storage.data(); while pruned_messages < max_messages_to_prune && data.oldest_unpruned_nonce <= data.latest_received_nonce { self.storage.remove_message(&data.oldest_unpruned_nonce); - anything_changed = true; pruned_messages += 1; data.oldest_unpruned_nonce += 1; } - if anything_changed { + if pruned_messages > 0 { self.storage.set_data(data); } diff --git a/modules/messages/src/weights.rs b/modules/messages/src/weights.rs index 462f768a08..3f9ea8bbb1 100644 --- a/modules/messages/src/weights.rs +++ b/modules/messages/src/weights.rs @@ -17,14 +17,15 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-28, STEPS: 50, REPEAT: 20 +//! DATE: 2022-07-20, STEPS: 50, REPEAT: 20 //! LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled -//! CHAIN: Some("dev"), DB CACHE: 128 +//! CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/release/millau-bridge-node // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 @@ -39,6 +40,7 @@ #![allow(clippy::all)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{ traits::Get, @@ -68,149 +70,149 @@ pub trait WeightInfo { pub struct MillauWeight(PhantomData); impl WeightInfo for MillauWeight { fn send_minimal_message_worst_case() -> Weight { - (117_480_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + (38_822_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(10 as Weight)) } fn send_1_kb_message_worst_case() -> Weight { - (128_391_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + (39_799_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(10 as Weight)) } fn send_16_kb_message_worst_case() -> Weight { - (149_149_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(12 as Weight)) + (47_772_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(10 as Weight)) } fn maximal_increase_message_fee() -> Weight { - (6_015_058_000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (3_081_804_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn increase_message_fee(i: u32) -> Weight { (0 as Weight) - .saturating_add((2_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn receive_single_message_proof() -> Weight { - (179_892_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (26_523_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn receive_two_messages_proof() -> Weight { - (291_793_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (39_278_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn receive_single_message_proof_with_outbound_lane_state() -> Weight { - (192_191_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (32_416_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn receive_single_message_proof_1_kb() -> Weight { - (202_104_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (27_078_000 as Weight) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn receive_single_message_proof_16_kb() -> Weight { - (357_144_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - } - fn receive_single_prepaid_message_proof() -> Weight { - (122_648_000 as Weight) + (78_235_000 as Weight) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } + fn receive_single_prepaid_message_proof() -> Weight { + (27_635_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } fn receive_delivery_proof_for_single_message() -> Weight { - (107_631_000 as Weight) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (34_576_000 as Weight) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { - (113_885_000 as Weight) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (37_318_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { - (155_151_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + (41_245_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn send_minimal_message_worst_case() -> Weight { - (117_480_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + (38_822_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(10 as Weight)) } fn send_1_kb_message_worst_case() -> Weight { - (128_391_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + (39_799_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(10 as Weight)) } fn send_16_kb_message_worst_case() -> Weight { - (149_149_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(12 as Weight)) + (47_772_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(10 as Weight)) } fn maximal_increase_message_fee() -> Weight { - (6_015_058_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (3_081_804_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn increase_message_fee(i: u32) -> Weight { (0 as Weight) - .saturating_add((2_000 as Weight).saturating_mul(i as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + .saturating_add((1_000 as Weight).saturating_mul(i as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn receive_single_message_proof() -> Weight { - (179_892_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (26_523_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn receive_two_messages_proof() -> Weight { - (291_793_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (39_278_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn receive_single_message_proof_with_outbound_lane_state() -> Weight { - (192_191_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (32_416_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn receive_single_message_proof_1_kb() -> Weight { - (202_104_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (27_078_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn receive_single_message_proof_16_kb() -> Weight { - (357_144_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - } - fn receive_single_prepaid_message_proof() -> Weight { - (122_648_000 as Weight) + (78_235_000 as Weight) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } + fn receive_single_prepaid_message_proof() -> Weight { + (27_635_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } fn receive_delivery_proof_for_single_message() -> Weight { - (107_631_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (34_576_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { - (113_885_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(7 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (37_318_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { - (155_151_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + (41_245_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } } diff --git a/modules/messages/src/weights_ext.rs b/modules/messages/src/weights_ext.rs index 483a22eda1..3c5a24788e 100644 --- a/modules/messages/src/weights_ext.rs +++ b/modules/messages/src/weights_ext.rs @@ -79,10 +79,12 @@ pub fn ensure_weights_are_correct( // verify `receive_messages_delivery_proof` weight components assert_ne!(W::receive_messages_delivery_proof_overhead(), 0); - assert_ne!(W::receive_messages_delivery_proof_messages_overhead(1), 0); - assert_ne!(W::receive_messages_delivery_proof_relayers_overhead(1), 0); assert_ne!(W::storage_proof_size_overhead(1), 0); + // `receive_messages_delivery_proof_messages_overhead` and + // `receive_messages_delivery_proof_relayers_overhead` may return zero if rewards are not paid + // during confirmations delivery, so we're not checking it here + // verify that the hardcoded value covers `receive_messages_delivery_proof` weight let actual_messages_delivery_confirmation_tx_weight = W::receive_messages_delivery_proof_weight( &PreComputedSize(W::expected_extra_storage_proof_size() as usize), @@ -199,7 +201,7 @@ pub trait WeightInfoExt: WeightInfo { /// Weight of message send extrinsic. fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight { let transaction_overhead = Self::send_message_overhead(); - let message_size_overhead = Self::send_message_size_overhead(message.size_hint()); + let message_size_overhead = Self::send_message_size_overhead(message.size()); let call_back_overhead = Self::single_message_callback_overhead(db_weight); transaction_overhead @@ -225,7 +227,7 @@ pub trait WeightInfoExt: WeightInfo { let expected_proof_size = EXPECTED_DEFAULT_MESSAGE_LENGTH .saturating_mul(messages_count.saturating_sub(1)) .saturating_add(Self::expected_extra_storage_proof_size()); - let actual_proof_size = proof.size_hint(); + let actual_proof_size = proof.size(); let proof_size_overhead = Self::storage_proof_size_overhead( actual_proof_size.saturating_sub(expected_proof_size), ); @@ -253,7 +255,7 @@ pub trait WeightInfoExt: WeightInfo { // proof size overhead weight let expected_proof_size = Self::expected_extra_storage_proof_size(); - let actual_proof_size = proof.size_hint(); + let actual_proof_size = proof.size(); let proof_size_overhead = Self::storage_proof_size_overhead( actual_proof_size.saturating_sub(expected_proof_size), ); diff --git a/modules/dispatch/Cargo.toml b/modules/parachains/Cargo.toml similarity index 51% rename from modules/dispatch/Cargo.toml rename to modules/parachains/Cargo.toml index 833d5cca77..99e91180b3 100644 --- a/modules/dispatch/Cargo.toml +++ b/modules/parachains/Cargo.toml @@ -1,42 +1,56 @@ [package] -name = "pallet-bridge-dispatch" -description = "A Substrate Runtime module that dispatches a bridge message, treating it simply as encoded Call" +name = "pallet-bridge-parachains" version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.101", optional = true } -# Bridge dependencies +# Bridge Dependencies -bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false } +bp-parachains = { path = "../../primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } bp-runtime = { path = "../../primitives/runtime", default-features = false } +pallet-bridge-grandpa = { path = "../grandpa", default-features = false } # Substrate Dependencies +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [dev-dependencies] +bp-header-chain = { path = "../../primitives/header-chain" } +bp-test-utils = { path = "../../primitives/test-utils" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = ["std"] std = [ - "bp-message-dispatch/std", + "bp-parachains/std", + "bp-polkadot-core/std", "bp-runtime/std", + "codec/std", "frame-support/std", "frame-system/std", "log/std", + "pallet-bridge-grandpa/std", "scale-info/std", + "serde", "sp-core/std", "sp-runtime/std", "sp-std/std", + "sp-trie/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", ] diff --git a/modules/parachains/src/benchmarking.rs b/modules/parachains/src/benchmarking.rs new file mode 100644 index 0000000000..aba296dfc1 --- /dev/null +++ b/modules/parachains/src/benchmarking.rs @@ -0,0 +1,106 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Parachains finality pallet benchmarking. + +use crate::{ + weights_ext::DEFAULT_PARACHAIN_HEAD_SIZE, Call, RelayBlockHash, RelayBlockHasher, + RelayBlockNumber, +}; + +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use bp_runtime::StorageProofSize; +use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_system::RawOrigin; +use sp_std::prelude::*; + +/// Pallet we're benchmarking here. +pub struct Pallet, I: 'static>(crate::Pallet); + +/// Trait that must be implemented by runtime to benchmark the parachains finality pallet. +pub trait Config: crate::Config { + /// Generate parachain heads proof and prepare environment for verifying this proof. + fn prepare_parachain_heads_proof( + parachains: &[ParaId], + parachain_head_size: u32, + proof_size: StorageProofSize, + ) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>); +} + +benchmarks_instance_pallet! { + where_clause { + where + >::BridgedChain: + bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, + } + + // Benchmark `submit_parachain_heads` extrinsic with different number of parachains. + submit_parachain_heads_with_n_parachains { + let p in 1..1024; + + let sender = account("sender", 0, 0); + let parachains = (1..=p).map(ParaId).collect::>(); + let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( + ¶chains, + DEFAULT_PARACHAIN_HEAD_SIZE, + StorageProofSize::Minimal(0), + ); + let at_relay_block = (relay_block_number, relay_block_hash); + }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) + verify { + for parachain in parachains { + assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); + } + } + + // Benchmark `submit_parachain_heads` extrinsic with 1kb proof size. + submit_parachain_heads_with_1kb_proof { + let sender = account("sender", 0, 0); + let parachains = vec![ParaId(1)]; + let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( + ¶chains, + DEFAULT_PARACHAIN_HEAD_SIZE, + StorageProofSize::HasExtraNodes(1024), + ); + let at_relay_block = (relay_block_number, relay_block_hash); + }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) + verify { + for parachain in parachains { + assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); + } + } + + // Benchmark `submit_parachain_heads` extrinsic with 16kb proof size. + submit_parachain_heads_with_16kb_proof { + let sender = account("sender", 0, 0); + let parachains = vec![ParaId(1)]; + let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( + ¶chains, + DEFAULT_PARACHAIN_HEAD_SIZE, + StorageProofSize::HasExtraNodes(16 * 1024), + ); + let at_relay_block = (relay_block_number, relay_block_hash); + }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) + verify { + for parachain in parachains { + assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); + } + } +} diff --git a/modules/parachains/src/extension.rs b/modules/parachains/src/extension.rs new file mode 100644 index 0000000000..05500cf41d --- /dev/null +++ b/modules/parachains/src/extension.rs @@ -0,0 +1,165 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use crate::{Config, Pallet, RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use bp_runtime::FilterCall; +use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; +use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}; + +/// Validate parachain heads in order to avoid "mining" transactions that provide +/// outdated bridged parachain heads. Without this validation, even honest relayers +/// may lose their funds if there are multiple relays running and submitting the +/// same information. +/// +/// This validation only works with transactions that are updating single parachain +/// head. We can't use unbounded validation - it may take too long and either break +/// block production, or "eat" significant portion of block production time literally +/// for nothing. In addition, the single-parachain-head-per-transaction is how the +/// pallet will be used in our environment. +impl< + Call: IsSubType, T>>, + T: frame_system::Config + Config, + I: 'static, + > FilterCall for Pallet +where + >::BridgedChain: + bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, +{ + fn validate(call: &Call) -> TransactionValidity { + let (updated_at_relay_block_number, parachains) = match call.is_sub_type() { + Some(crate::Call::::submit_parachain_heads { + ref at_relay_block, + ref parachains, + .. + }) => (at_relay_block.0, parachains), + _ => return Ok(ValidTransaction::default()), + }; + let (parachain, parachain_head_hash) = match parachains.as_slice() { + &[(parachain, parachain_head_hash)] => (parachain, parachain_head_hash), + _ => return Ok(ValidTransaction::default()), + }; + + let maybe_stored_best_head = crate::ParasInfo::::get(parachain); + let is_valid = Self::validate_updated_parachain_head( + parachain, + &maybe_stored_best_head, + updated_at_relay_block_number, + parachain_head_hash, + "Rejecting obsolete parachain-head transaction", + ); + + if is_valid { + Ok(ValidTransaction::default()) + } else { + InvalidTransaction::Stale.into() + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + extension::FilterCall, + mock::{run_test, Call, TestRuntime}, + ParaInfo, ParasInfo, RelayBlockNumber, + }; + use bp_parachains::BestParaHeadHash; + use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; + + fn validate_submit_parachain_heads( + num: RelayBlockNumber, + parachains: Vec<(ParaId, ParaHash)>, + ) -> bool { + crate::Pallet::::validate(&Call::Parachains( + crate::Call::::submit_parachain_heads { + at_relay_block: (num, Default::default()), + parachains, + parachain_heads_proof: ParaHeadsProof(Vec::new()), + }, + )) + .is_ok() + } + + fn sync_to_relay_header_10() { + ParasInfo::::insert( + ParaId(1), + ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 10, + head_hash: [1u8; 32].into(), + }, + next_imported_hash_position: 0, + }, + ); + } + + #[test] + fn extension_rejects_header_from_the_obsolete_relay_block() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#5 => tx is + // rejected + sync_to_relay_header_10(); + assert!(!validate_submit_parachain_heads(5, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_header_from_the_same_relay_block() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#10 => tx is + // rejected + sync_to_relay_header_10(); + assert!(!validate_submit_parachain_heads(10, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_header_from_new_relay_block_with_same_hash() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#10 => tx is + // rejected + sync_to_relay_header_10(); + assert!(!validate_submit_parachain_heads(20, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_accepts_new_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#15 => tx is + // accepted + sync_to_relay_header_10(); + assert!(validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())])); + }); + } + + #[test] + fn extension_accepts_if_more_than_one_parachain_is_submitted() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#5, but another + // parachain head is also supplied => tx is accepted + sync_to_relay_header_10(); + assert!(validate_submit_parachain_heads( + 5, + vec![(ParaId(1), [1u8; 32].into()), (ParaId(2), [1u8; 32].into())] + )); + }); + } +} diff --git a/modules/parachains/src/lib.rs b/modules/parachains/src/lib.rs new file mode 100644 index 0000000000..290bdadf04 --- /dev/null +++ b/modules/parachains/src/lib.rs @@ -0,0 +1,1300 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Parachains finality module. +//! +//! This module needs to be deployed with GRANDPA module, which is syncing relay +//! chain blocks. The main entry point of this module is `submit_parachain_heads`, which +//! accepts storage proof of some parachain `Heads` entries from bridged relay chain. +//! It requires corresponding relay headers to be already synced. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use weights::WeightInfo; +pub use weights_ext::WeightInfoExt; + +use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo}; +use bp_polkadot_core::parachains::{ParaHash, ParaHasher, ParaHead, ParaHeadsProof, ParaId}; +use bp_runtime::StorageProofError; +use frame_support::{traits::Contains, weights::PostDispatchInfo}; +use sp_runtime::traits::Header as HeaderT; +use sp_std::vec::Vec; + +// Re-export in crate namespace for `construct_runtime!`. +pub use pallet::*; + +pub mod weights; +pub mod weights_ext; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +mod extension; +#[cfg(test)] +mod mock; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-parachains"; + +/// Block hash of the bridged relay chain. +pub type RelayBlockHash = bp_polkadot_core::Hash; +/// Block number of the bridged relay chain. +pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; +/// Hasher of the bridged relay chain. +pub type RelayBlockHasher = bp_polkadot_core::Hasher; + +/// Artifacts of the parachains head update. +struct UpdateParachainHeadArtifacts { + /// New best head of the parachain. + pub best_head: ParaInfo, + /// If `true`, some old parachain head has been pruned during update. + pub prune_happened: bool, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use bp_parachains::{BestParaHeadHash, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider}; + use bp_runtime::{ + BasicOperatingMode, OwnedBridgeModule, StorageDoubleMapKeyProvider, StorageMapKeyProvider, + }; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + /// Weight info of the given parachains pallet. + pub type WeightInfoOf = >::WeightInfo; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// The caller has provided head of parachain that the pallet is not configured to track. + UntrackedParachainRejected { parachain: ParaId }, + /// The caller has declared that he has provided given parachain head, but it is missing + /// from the storage proof. + MissingParachainHead { parachain: ParaId }, + /// The caller has provided parachain head hash that is not matching the hash read from the + /// storage proof. + IncorrectParachainHeadHash { + parachain: ParaId, + parachain_head_hash: ParaHash, + actual_parachain_head_hash: ParaHash, + }, + /// The caller has provided obsolete parachain head, which is already known to the pallet. + RejectedObsoleteParachainHead { parachain: ParaId, parachain_head_hash: ParaHash }, + /// Parachain head has been updated. + UpdatedParachainHead { parachain: ParaId, parachain_head_hash: ParaHash }, + } + + #[pallet::error] + pub enum Error { + /// Relay chain block hash is unknown to us. + UnknownRelayChainBlock, + /// The number of stored relay block is different from what the relayer has provided. + InvalidRelayChainBlockNumber, + /// Invalid storage proof has been passed. + InvalidStorageProof, + /// Given parachain head is unknown. + UnknownParaHead, + /// The storage proof doesn't contains storage root. So it is invalid for given header. + StorageRootMismatch, + /// Failed to extract state root from given parachain head. + FailedToExtractStateRoot, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), + } + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: + pallet_bridge_grandpa::Config + { + /// The overarching event type. + type Event: From> + IsType<::Event>; + /// Benchmarks results from runtime we're plugged into. + type WeightInfo: WeightInfoExt; + + /// Instance of bridges GRANDPA pallet (within this runtime) that this pallet is linked to. + /// + /// The GRANDPA pallet instance must be configured to import headers of relay chain that + /// we're interested in. + type BridgesGrandpaPalletInstance: 'static; + + /// Name of the original `paras` pallet in the `construct_runtime!()` call at the bridged + /// chain. + /// + /// Please keep in mind that this should be the name of the `runtime_parachains::paras` + /// pallet from polkadot repository, not the `pallet-bridge-parachains`. + #[pallet::constant] + type ParasPalletName: Get<&'static str>; + + /// Set of parachains that are tracked by this pallet. + /// + /// The set may be extended easily, without requiring any runtime upgrades. Removing tracked + /// parachain requires special handling - pruning existing heads and cleaning related data + /// structures. + type TrackedParachains: Contains; + + /// Maximal number of single parachain heads to keep in the storage. + /// + /// The setting is there to prevent growing the on-chain state indefinitely. Note + /// the setting does not relate to parachain block numbers - we will simply keep as much + /// items in the storage, so it doesn't guarantee any fixed timeframe for heads. + /// + /// Incautious change of this constant may lead to orphan entries in the runtime storage. + #[pallet::constant] + type HeadsToKeep: Get; + } + + /// Optional pallet owner. + /// + /// Pallet owner has a right to halt all pallet operations and then resume them. If it is + /// `None`, then there are no direct ways to halt/resume pallet operations, but other + /// runtime methods may still be used to do that (i.e. democracy::referendum to update halt + /// flag directly or call the `halt_operations`). + #[pallet::storage] + pub type PalletOwner, I: 'static = ()> = + StorageValue<_, T::AccountId, OptionQuery>; + + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, or no transactions will be allowed. + #[pallet::storage] + pub type PalletOperatingMode, I: 'static = ()> = + StorageValue<_, BasicOperatingMode, ValueQuery>; + + /// Parachains info. + /// + /// Contains the following info: + /// - best parachain head hash + /// - the head of the `ImportedParaHashes` ring buffer + #[pallet::storage] + pub type ParasInfo, I: 'static = ()> = StorageMap< + _, + ::Hasher, + ::Key, + ::Value, + >; + + /// Parachain heads which have been imported into the pallet. + #[pallet::storage] + pub type ImportedParaHeads, I: 'static = ()> = StorageDoubleMap< + _, + ::Hasher1, + ::Key1, + ::Hasher2, + ::Key2, + ::Value, + >; + + /// A ring buffer of imported parachain head hashes. Ordered by the insertion time. + #[pallet::storage] + pub(super) type ImportedParaHashes, I: 'static = ()> = + StorageDoubleMap<_, Blake2_128Concat, ParaId, Twox64Concat, u32, ParaHash>; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData<(T, I)>); + + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = BasicOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + + #[pallet::call] + impl, I: 'static> Pallet + where + >::BridgedChain: + bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, + { + /// Submit proof of one or several parachain heads. + /// + /// The proof is supposed to be proof of some `Heads` entries from the + /// `polkadot-runtime-parachains::paras` pallet instance, deployed at the bridged chain. + /// The proof is supposed to be crafted at the `relay_header_hash` that must already be + /// imported by corresponding GRANDPA pallet at this chain. + #[pallet::weight(WeightInfoOf::::submit_parachain_heads_weight( + T::DbWeight::get(), + parachain_heads_proof, + parachains.len() as _, + ))] + pub fn submit_parachain_heads( + _origin: OriginFor, + at_relay_block: (RelayBlockNumber, RelayBlockHash), + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> DispatchResultWithPostInfo { + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + // we'll need relay chain header to verify that parachains heads are always increasing. + let (relay_block_number, relay_block_hash) = at_relay_block; + let relay_block = pallet_bridge_grandpa::ImportedHeaders::< + T, + T::BridgesGrandpaPalletInstance, + >::get(relay_block_hash) + .ok_or(Error::::UnknownRelayChainBlock)?; + ensure!( + *relay_block.number() == relay_block_number, + Error::::InvalidRelayChainBlockNumber, + ); + + // now parse storage proof and read parachain heads + let mut actual_weight = WeightInfoOf::::submit_parachain_heads_weight( + T::DbWeight::get(), + ¶chain_heads_proof, + parachains.len() as _, + ); + + pallet_bridge_grandpa::Pallet::::parse_finalized_storage_proof( + relay_block_hash, + sp_trie::StorageProof::new(parachain_heads_proof.0), + move |storage| { + for (parachain, parachain_head_hash) in parachains { + // if we're not tracking this parachain, we'll just ignore its head proof here + if !T::TrackedParachains::contains(¶chain) { + log::trace!( + target: LOG_TARGET, + "The head of parachain {:?} has been provided, but it is not tracked by the pallet", + parachain, + ); + Self::deposit_event(Event::UntrackedParachainRejected { parachain }); + continue; + } + + let parachain_head = match Pallet::::read_parachain_head(&storage, parachain) { + Ok(Some(parachain_head)) => parachain_head, + Ok(None) => { + log::trace!( + target: LOG_TARGET, + "The head of parachain {:?} is None. {}", + parachain, + if ParasInfo::::contains_key(parachain) { + "Looks like it is not yet registered at the source relay chain" + } else { + "Looks like it has been deregistered from the source relay chain" + }, + ); + Self::deposit_event(Event::MissingParachainHead { parachain }); + continue; + }, + Err(e) => { + log::trace!( + target: LOG_TARGET, + "The read of head of parachain {:?} has failed: {:?}", + parachain, + e, + ); + Self::deposit_event(Event::MissingParachainHead { parachain }); + continue; + }, + }; + + // if relayer has specified invalid parachain head hash, ignore the head + // (this isn't strictly necessary, but better safe than sorry) + let actual_parachain_head_hash = parachain_head.hash(); + if parachain_head_hash != actual_parachain_head_hash { + log::trace!( + target: LOG_TARGET, + "The submitter has specified invalid parachain {:?} head hash: {:?} vs {:?}", + parachain, + parachain_head_hash, + actual_parachain_head_hash, + ); + Self::deposit_event(Event::IncorrectParachainHeadHash { + parachain, + parachain_head_hash, + actual_parachain_head_hash, + }); + continue; + } + + let update_result: Result<_, ()> = ParasInfo::::try_mutate(parachain, |stored_best_head| { + let artifacts = Pallet::::update_parachain_head( + parachain, + stored_best_head.take(), + relay_block_number, + parachain_head, + parachain_head_hash, + )?; + *stored_best_head = Some(artifacts.best_head); + Ok(artifacts.prune_happened) + }); + + // we're refunding weight if update has not happened and if pruning has not happened + let is_update_happened = matches!(update_result, Ok(_)); + if !is_update_happened { + actual_weight = actual_weight + .saturating_sub(WeightInfoOf::::parachain_head_storage_write_weight(T::DbWeight::get())); + } + let is_prune_happened = matches!(update_result, Ok(true)); + if !is_prune_happened { + actual_weight = actual_weight + .saturating_sub(WeightInfoOf::::parachain_head_pruning_weight(T::DbWeight::get())); + } + } + }, + ) + .map_err(|_| Error::::InvalidStorageProof)?; + + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes }) + } + + /// Change `PalletOwner`. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) + } + + /// Halt or resume all pallet operations. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_operating_mode( + origin: OriginFor, + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) + } + } + + impl, I: 'static> Pallet { + /// Get best finalized header of the given parachain. + pub fn best_parachain_head(parachain: ParaId) -> Option { + let best_para_head_hash = ParasInfo::::get(parachain)?.best_head_hash.head_hash; + ImportedParaHeads::::get(parachain, best_para_head_hash) + } + + /// Get parachain head with given hash. + pub fn parachain_head(parachain: ParaId, hash: ParaHash) -> Option { + ImportedParaHeads::::get(parachain, hash) + } + + /// Verify that the passed storage proof is valid, given it is crafted using + /// known finalized header. If the proof is valid, then the `parse` callback + /// is called and the function returns its result. + pub fn parse_finalized_storage_proof( + parachain: ParaId, + hash: ParaHash, + storage_proof: sp_trie::StorageProof, + decode_state_root: impl FnOnce(ParaHead) -> Option, + parse: impl FnOnce(bp_runtime::StorageProofChecker) -> R, + ) -> Result { + let para_head = + Self::parachain_head(parachain, hash).ok_or(Error::::UnknownParaHead)?; + let state_root = + decode_state_root(para_head).ok_or(Error::::FailedToExtractStateRoot)?; + let storage_proof_checker = + bp_runtime::StorageProofChecker::new(state_root, storage_proof) + .map_err(|_| Error::::StorageRootMismatch)?; + + Ok(parse(storage_proof_checker)) + } + + /// Read parachain head from storage proof. + fn read_parachain_head( + storage: &bp_runtime::StorageProofChecker, + parachain: ParaId, + ) -> Result, StorageProofError> { + let parachain_head_key = + parachain_head_storage_key_at_source(T::ParasPalletName::get(), parachain); + storage.read_and_decode_value(parachain_head_key.0.as_ref()) + } + + /// Check if para head has been already updated at better relay chain block. + /// Without this check, we may import heads in random order. + /// + /// Returns `true` if the pallet is ready to import given parachain head. + /// Returns `false` if the pallet already knows the same or better parachain head. + #[must_use] + pub fn validate_updated_parachain_head( + parachain: ParaId, + maybe_stored_best_head: &Option, + updated_at_relay_block_number: RelayBlockNumber, + updated_head_hash: ParaHash, + err_log_prefix: &str, + ) -> bool { + let stored_best_head = match maybe_stored_best_head { + Some(stored_best_head) => stored_best_head, + None => return true, + }; + + if stored_best_head.best_head_hash.at_relay_block_number >= + updated_at_relay_block_number + { + log::trace!( + target: LOG_TARGET, + "{}. The parachain head for {:?} was already updated at better relay chain block {} >= {}.", + err_log_prefix, + parachain, + stored_best_head.best_head_hash.at_relay_block_number, + updated_at_relay_block_number + ); + return false + } + + if stored_best_head.best_head_hash.head_hash == updated_head_hash { + log::trace!( + target: LOG_TARGET, + "{}. The parachain head hash for {:?} was already updated to {} at block {} < {}.", + err_log_prefix, + parachain, + updated_head_hash, + stored_best_head.best_head_hash.at_relay_block_number, + updated_at_relay_block_number + ); + return false + } + + true + } + + /// Try to update parachain head. + pub(super) fn update_parachain_head( + parachain: ParaId, + stored_best_head: Option, + updated_at_relay_block_number: RelayBlockNumber, + updated_head: ParaHead, + updated_head_hash: ParaHash, + ) -> Result { + // check if head has been already updated at better relay chain block. Without this + // check, we may import heads in random order + let is_valid = Self::validate_updated_parachain_head( + parachain, + &stored_best_head, + updated_at_relay_block_number, + updated_head_hash, + "The parachain head can't be updated", + ); + if !is_valid { + Self::deposit_event(Event::RejectedObsoleteParachainHead { + parachain, + parachain_head_hash: updated_head_hash, + }); + return Err(()) + } + let next_imported_hash_position = stored_best_head + .map_or(0, |stored_best_head| stored_best_head.next_imported_hash_position); + + // insert updated best parachain head + let head_hash_to_prune = + ImportedParaHashes::::try_get(parachain, next_imported_hash_position); + let updated_best_para_head = ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: updated_at_relay_block_number, + head_hash: updated_head_hash, + }, + next_imported_hash_position: (next_imported_hash_position + 1) % + T::HeadsToKeep::get(), + }; + ImportedParaHashes::::insert( + parachain, + next_imported_hash_position, + updated_head_hash, + ); + ImportedParaHeads::::insert(parachain, updated_head_hash, updated_head); + log::trace!( + target: LOG_TARGET, + "Updated head of parachain {:?} to {}", + parachain, + updated_head_hash, + ); + + // remove old head + let prune_happened = head_hash_to_prune.is_ok(); + if let Ok(head_hash_to_prune) = head_hash_to_prune { + log::trace!( + target: LOG_TARGET, + "Pruning old head of parachain {:?}: {}", + parachain, + head_hash_to_prune, + ); + ImportedParaHeads::::remove(parachain, head_hash_to_prune); + } + Self::deposit_event(Event::UpdatedParachainHead { + parachain, + parachain_head_hash: updated_head_hash, + }); + + Ok(UpdateParachainHeadArtifacts { best_head: updated_best_para_head, prune_happened }) + } + } + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + /// Initial pallet operating mode. + pub operating_mode: BasicOperatingMode, + /// Initial pallet owner. + pub owner: Option, + /// Dummy marker. + pub phantom: sp_std::marker::PhantomData, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + operating_mode: Default::default(), + owner: Default::default(), + phantom: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + PalletOperatingMode::::put(self.operating_mode); + if let Some(ref owner) = self.owner { + PalletOwner::::put(owner); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ + run_test, test_relay_header, Event as TestEvent, Origin, TestRuntime, PARAS_PALLET_NAME, + UNTRACKED_PARACHAIN_ID, + }; + use codec::Encode; + + use bp_parachains::{BestParaHeadHash, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider}; + use bp_runtime::{ + record_all_trie_keys, BasicOperatingMode, OwnedBridgeModuleError, + StorageDoubleMapKeyProvider, StorageMapKeyProvider, + }; + use bp_test_utils::{ + authority_list, generate_owned_bridge_module_tests, make_default_justification, + }; + use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchResultWithPostInfo, + storage::generator::{StorageDoubleMap, StorageMap}, + traits::{Get, OnInitialize}, + weights::Weight, + }; + use frame_system::{EventRecord, Pallet as System, Phase}; + use sp_runtime::DispatchError; + use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut}; + + type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1; + type WeightInfo = ::WeightInfo; + type DbWeight = ::DbWeight; + + fn initialize(state_root: RelayBlockHash) { + pallet_bridge_grandpa::Pallet::::initialize( + Origin::root(), + bp_header_chain::InitializationData { + header: Box::new(test_relay_header(0, state_root)), + authority_list: authority_list(), + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + }, + ) + .unwrap(); + } + + fn proceed(num: RelayBlockNumber, state_root: RelayBlockHash) { + pallet_bridge_grandpa::Pallet::::on_initialize( + 0, + ); + + let header = test_relay_header(num, state_root); + let justification = make_default_justification(&header); + assert_ok!( + pallet_bridge_grandpa::Pallet::::submit_finality_proof( + Origin::signed(1), + Box::new(header), + justification, + ) + ); + } + + fn prepare_parachain_heads_proof( + heads: Vec<(u32, ParaHead)>, + ) -> (RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) { + let mut parachains = Vec::with_capacity(heads.len()); + let mut root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); + for (parachain, head) in heads { + let storage_key = + parachain_head_storage_key_at_source(PARAS_PALLET_NAME, ParaId(parachain)); + trie.insert(&storage_key.0, &head.encode()) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in tests"); + parachains.push((ParaId(parachain), head.hash())); + } + } + + // generate storage proof to be delivered to This chain + let mut proof_recorder = Recorder::>::new(); + record_all_trie_keys::, _>(&mdb, &root, &mut proof_recorder) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); + let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); + + (root, ParaHeadsProof(storage_proof), parachains) + } + + fn initial_best_head(parachain: u32) -> ParaInfo { + ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(parachain, 0).hash(), + }, + next_imported_hash_position: 1, + } + } + + fn head_data(parachain: u32, head_number: u32) -> ParaHead { + ParaHead((parachain, head_number).encode()) + } + + fn head_hash(parachain: u32, head_number: u32) -> ParaHash { + head_data(parachain, head_number).hash() + } + + fn import_parachain_1_head( + relay_chain_block: RelayBlockNumber, + relay_state_root: RelayBlockHash, + parachains: Vec<(ParaId, ParaHash)>, + proof: ParaHeadsProof, + ) -> DispatchResultWithPostInfo { + Pallet::::submit_parachain_heads( + Origin::signed(1), + (relay_chain_block, test_relay_header(relay_chain_block, relay_state_root).hash()), + parachains, + proof, + ) + } + + fn weight_of_import_parachain_1_head(proof: &ParaHeadsProof, prune_expected: bool) -> Weight { + let db_weight = ::DbWeight::get(); + WeightInfoOf::::submit_parachain_heads_weight(db_weight, proof, 1) + .saturating_sub(if prune_expected { + 0 + } else { + WeightInfoOf::::parachain_head_pruning_weight(db_weight) + }) + } + + #[test] + fn submit_parachain_heads_checks_operating_mode() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + + run_test(|| { + initialize(state_root); + + // `submit_parachain_heads()` should fail when the pallet is halted. + PalletOperatingMode::::put(BasicOperatingMode::Halted); + assert_noop!( + Pallet::::submit_parachain_heads( + Origin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains.clone(), + proof.clone(), + ), + Error::::BridgeModule(OwnedBridgeModuleError::Halted) + ); + + // `submit_parachain_heads()` should succeed now that the pallet is resumed. + PalletOperatingMode::::put(BasicOperatingMode::Normal); + assert_ok!(Pallet::::submit_parachain_heads( + Origin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ),); + }); + } + + #[test] + fn imports_initial_parachain_heads() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 0)), (3, head_data(3, 10))]); + run_test(|| { + initialize(state_root); + + // we're trying to update heads of parachains 1, 2 and 3 + let expected_weight = + WeightInfo::submit_parachain_heads_weight(DbWeight::get(), &proof, 2); + let result = Pallet::::submit_parachain_heads( + Origin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + + // but only 1 and 2 are updated, because proof is missing head of parachain#2 + assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); + assert_eq!(ParasInfo::::get(ParaId(2)), None); + assert_eq!( + ParasInfo::::get(ParaId(3)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(3, 10).hash() + }, + next_imported_hash_position: 1, + }) + ); + + assert_eq!( + ImportedParaHeads::::get( + ParaId(1), + initial_best_head(1).best_head_hash.head_hash + ), + Some(head_data(1, 0)) + ); + assert_eq!( + ImportedParaHeads::::get( + ParaId(2), + initial_best_head(2).best_head_hash.head_hash + ), + None + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(3), head_hash(3, 10)), + Some(head_data(3, 10)) + ); + + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(3), + parachain_head_hash: head_data(3, 10).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn imports_parachain_heads_is_able_to_progress() { + let (state_root_5, proof_5, parachains_5) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + let (state_root_10, proof_10, parachains_10) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]); + run_test(|| { + // start with relay block #0 and import head#5 of parachain#1 + initialize(state_root_5); + assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 5).hash()), + Some(head_data(1, 5)) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 10).hash()), + None + ); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }], + ); + + // import head#10 of parachain#1 at relay block #1 + proceed(1, state_root_10); + assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 1, + head_hash: head_data(1, 10).hash() + }, + next_imported_hash_position: 2, + }) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 5).hash()), + Some(head_data(1, 5)) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 10).hash()), + Some(head_data(1, 10)) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn ignores_untracked_parachain() { + let (state_root, proof, parachains) = prepare_parachain_heads_proof(vec![ + (1, head_data(1, 5)), + (UNTRACKED_PARACHAIN_ID, head_data(1, 5)), + (2, head_data(1, 5)), + ]); + run_test(|| { + // start with relay block #0 and try to import head#5 of parachain#1 and untracked + // parachain + let expected_weight = + WeightInfo::submit_parachain_heads_weight(DbWeight::get(), &proof, 3) + .saturating_sub(WeightInfo::parachain_head_storage_write_weight( + DbWeight::get(), + )); + initialize(state_root); + let result = Pallet::::submit_parachain_heads( + Origin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!(ParasInfo::::get(ParaId(UNTRACKED_PARACHAIN_ID)), None,); + assert_eq!( + ParasInfo::::get(ParaId(2)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UntrackedParachainRejected { + parachain: ParaId(UNTRACKED_PARACHAIN_ID), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(2), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn does_nothing_when_already_imported_this_head_at_previous_relay_header() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + run_test(|| { + // import head#0 of parachain#1 at relay block#0 + initialize(state_root); + assert_ok!(import_parachain_1_head(0, state_root, parachains.clone(), proof.clone())); + assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + }], + ); + + // try to import head#0 of parachain#1 at relay block#1 + // => call succeeds, but nothing is changed + proceed(1, state_root); + assert_ok!(import_parachain_1_head(1, state_root, parachains, proof)); + assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::RejectedObsoleteParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn does_nothing_when_already_imported_head_at_better_relay_header() { + let (state_root_5, proof_5, parachains_5) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + let (state_root_10, proof_10, parachains_10) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]); + run_test(|| { + // start with relay block #0 + initialize(state_root_5); + + // head#10 of parachain#1 at relay block#1 + proceed(1, state_root_10); + assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 1, + head_hash: head_data(1, 10).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + }), + topics: vec![], + }], + ); + + // now try to import head#5 at relay block#0 + // => nothing is changed, because better head has already been imported + assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 1, + head_hash: head_data(1, 10).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::RejectedObsoleteParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn prunes_old_heads() { + run_test(|| { + let heads_to_keep = crate::mock::HeadsToKeep::get(); + + // import exactly `HeadsToKeep` headers + for i in 0..heads_to_keep { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, i))]); + if i == 0 { + initialize(state_root); + } else { + proceed(i, state_root); + } + + let expected_weight = weight_of_import_parachain_1_head(&proof, false); + let result = import_parachain_1_head(i, state_root, parachains, proof); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + } + + // nothing is pruned yet + for i in 0..heads_to_keep { + assert!(ImportedParaHeads::::get(ParaId(1), head_data(1, i).hash()) + .is_some()); + } + + // import next relay chain header and next parachain head + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, heads_to_keep))]); + proceed(heads_to_keep, state_root); + let expected_weight = weight_of_import_parachain_1_head(&proof, true); + let result = import_parachain_1_head(heads_to_keep, state_root, parachains, proof); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + + // and the head#0 is pruned + assert!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 0).hash()).is_none() + ); + for i in 1..=heads_to_keep { + assert!(ImportedParaHeads::::get(ParaId(1), head_data(1, i).hash()) + .is_some()); + } + }); + } + + #[test] + fn fails_on_unknown_relay_chain_block() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + run_test(|| { + // start with relay block #0 + initialize(state_root); + + // try to import head#5 of parachain#1 at unknown relay chain block #1 + assert_noop!( + import_parachain_1_head(1, state_root, parachains, proof), + Error::::UnknownRelayChainBlock + ); + }); + } + + #[test] + fn fails_on_invalid_storage_proof() { + let (_state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + run_test(|| { + // start with relay block #0 + initialize(Default::default()); + + // try to import head#5 of parachain#1 at relay chain block #0 + assert_noop!( + import_parachain_1_head(0, Default::default(), parachains, proof), + Error::::InvalidStorageProof + ); + }); + } + + #[test] + fn is_not_rewriting_existing_head_if_failed_to_read_updated_head() { + let (state_root_5, proof_5, parachains_5) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + let (state_root_10_at_20, proof_10_at_20, parachains_10_at_20) = + prepare_parachain_heads_proof(vec![(2, head_data(2, 10))]); + let (state_root_10_at_30, proof_10_at_30, parachains_10_at_30) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]); + run_test(|| { + // we've already imported head#5 of parachain#1 at relay block#10 + initialize(state_root_5); + import_parachain_1_head(0, state_root_5, parachains_5, proof_5).expect("ok"); + assert_eq!( + Pallet::::best_parachain_head(ParaId(1)), + Some(head_data(1, 5)) + ); + + // then if someone is pretending to provide updated head#10 of parachain#1 at relay + // block#20, but fails to do that + // + // => we'll leave previous value + proceed(20, state_root_10_at_20); + assert_ok!(Pallet::::submit_parachain_heads( + Origin::signed(1), + (20, test_relay_header(20, state_root_10_at_20).hash()), + parachains_10_at_20, + proof_10_at_20, + ),); + assert_eq!( + Pallet::::best_parachain_head(ParaId(1)), + Some(head_data(1, 5)) + ); + + // then if someone is pretending to provide updated head#10 of parachain#1 at relay + // block#30, and actualy provides it + // + // => we'll update value + proceed(30, state_root_10_at_30); + assert_ok!(Pallet::::submit_parachain_heads( + Origin::signed(1), + (30, test_relay_header(30, state_root_10_at_30).hash()), + parachains_10_at_30, + proof_10_at_30, + ),); + assert_eq!( + Pallet::::best_parachain_head(ParaId(1)), + Some(head_data(1, 10)) + ); + }); + } + + #[test] + fn storage_keys_computed_properly() { + assert_eq!( + ParasInfo::::storage_map_final_key(ParaId(42)).to_vec(), + ParasInfoKeyProvider::final_key("Parachains", &ParaId(42)).0 + ); + + assert_eq!( + ImportedParaHeads::::storage_double_map_final_key( + ParaId(42), + ParaHash::from([21u8; 32]) + ) + .to_vec(), + ImportedParaHeadsKeyProvider::final_key( + "Parachains", + &ParaId(42), + &ParaHash::from([21u8; 32]) + ) + .0, + ); + } + + #[test] + fn ignores_parachain_head_if_it_is_missing_from_storage_proof() { + let (state_root, proof, _) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + let parachains = vec![(ParaId(2), Default::default())]; + run_test(|| { + initialize(state_root); + assert_ok!(Pallet::::submit_parachain_heads( + Origin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + )); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::MissingParachainHead { + parachain: ParaId(2), + }), + topics: vec![], + }], + ); + }); + } + + #[test] + fn ignores_parachain_head_if_parachain_head_hash_is_wrong() { + let (state_root, proof, _) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + let parachains = vec![(ParaId(1), head_data(1, 10).hash())]; + run_test(|| { + initialize(state_root); + assert_ok!(Pallet::::submit_parachain_heads( + Origin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + )); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::IncorrectParachainHeadHash { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + actual_parachain_head_hash: head_data(1, 0).hash(), + }), + topics: vec![], + }], + ); + }); + } + + generate_owned_bridge_module_tests!(BasicOperatingMode::Normal, BasicOperatingMode::Halted); +} diff --git a/modules/parachains/src/mock.rs b/modules/parachains/src/mock.rs new file mode 100644 index 0000000000..292856f35a --- /dev/null +++ b/modules/parachains/src/mock.rs @@ -0,0 +1,188 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use bp_polkadot_core::parachains::ParaId; +use bp_runtime::Chain; +use frame_support::{construct_runtime, parameter_types, traits::IsInVec, weights::Weight}; +use sp_runtime::{ + testing::{Header, H256}, + traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, + Perbill, +}; + +use crate as pallet_bridge_parachains; + +pub type AccountId = u64; +pub type TestNumber = u64; + +pub type RelayBlockHeader = + sp_runtime::generic::Header; + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +pub const PARAS_PALLET_NAME: &str = "Paras"; +pub const UNTRACKED_PARACHAIN_ID: u32 = 10; + +construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Grandpa1: pallet_bridge_grandpa::::{Pallet}, + Grandpa2: pallet_bridge_grandpa::::{Pallet}, + Parachains: pallet_bridge_parachains::{Call, Pallet, Event}, + } +} + +parameter_types! { + pub const BlockHashCount: TestNumber = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); +} + +impl frame_system::Config for TestRuntime { + type Origin = Origin; + type Index = u64; + type Call = Call; + type BlockNumber = TestNumber; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type BaseCallFilter = frame_support::traits::Everything; + type SystemWeightInfo = (); + type DbWeight = (); + type BlockWeights = (); + type BlockLength = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const MaxRequests: u32 = 2; + pub const HeadersToKeep: u32 = 5; + pub const SessionLength: u64 = 5; + pub const NumValidators: u32 = 5; +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type BridgedChain = TestBridgedChain; + type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; + type WeightInfo = (); +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type BridgedChain = TestBridgedChain; + type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; + type WeightInfo = (); +} + +parameter_types! { + pub const HeadsToKeep: u32 = 4; + pub const ParasPalletName: &'static str = PARAS_PALLET_NAME; + pub GetTenFirstParachains: Vec = (0..10).map(ParaId).collect(); +} + +impl pallet_bridge_parachains::Config for TestRuntime { + type Event = Event; + type WeightInfo = (); + type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1; + type ParasPalletName = ParasPalletName; + type TrackedParachains = IsInVec; + type HeadsToKeep = HeadsToKeep; +} + +#[derive(Debug)] +pub struct TestBridgedChain; + +impl Chain for TestBridgedChain { + type BlockNumber = crate::RelayBlockNumber; + type Hash = crate::RelayBlockHash; + type Hasher = crate::RelayBlockHasher; + type Header = RelayBlockHeader; + + type AccountId = AccountId; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +#[derive(Debug)] +pub struct OtherBridgedChain; + +impl Chain for OtherBridgedChain { + type BlockNumber = u64; + type Hash = crate::RelayBlockHash; + type Hasher = crate::RelayBlockHasher; + type Header = sp_runtime::generic::Header; + + type AccountId = AccountId; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +pub fn run_test(test: impl FnOnce() -> T) -> T { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + System::set_block_number(1); + System::reset_events(); + test() + }) +} + +pub fn test_relay_header( + num: crate::RelayBlockNumber, + state_root: crate::RelayBlockHash, +) -> RelayBlockHeader { + RelayBlockHeader::new( + num, + Default::default(), + state_root, + Default::default(), + Default::default(), + ) +} diff --git a/modules/parachains/src/weights.rs b/modules/parachains/src/weights.rs new file mode 100644 index 0000000000..b96e24752d --- /dev/null +++ b/modules/parachains/src/weights.rs @@ -0,0 +1,99 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Autogenerated weights for `pallet_bridge_parachains` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-07-06, STEPS: 50, REPEAT: 20 +//! LOW RANGE: [], HIGH RANGE: [] +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled +//! CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/millau-bridge-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_bridge_parachains +// --extrinsic=* +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --output=./modules/parachains/src/weights.rs +// --template=./.maintain/millau-weight-template.hbs + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for `pallet_bridge_parachains`. +pub trait WeightInfo { + fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight; + fn submit_parachain_heads_with_1kb_proof() -> Weight; + fn submit_parachain_heads_with_16kb_proof() -> Weight; +} + +/// Weights for `pallet_bridge_parachains` using the Millau node and recommended hardware. +pub struct MillauWeight(PhantomData); +impl WeightInfo for MillauWeight { + fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight { + (0 as Weight) + .saturating_add((18_706_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(p as Weight))) + .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(p as Weight))) + } + fn submit_parachain_heads_with_1kb_proof() -> Weight { + (27_549_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + fn submit_parachain_heads_with_16kb_proof() -> Weight { + (80_792_000 as Weight) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight { + (0 as Weight) + .saturating_add((18_706_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(p as Weight))) + .saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(p as Weight))) + } + fn submit_parachain_heads_with_1kb_proof() -> Weight { + (27_549_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + fn submit_parachain_heads_with_16kb_proof() -> Weight { + (80_792_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } +} diff --git a/modules/parachains/src/weights_ext.rs b/modules/parachains/src/weights_ext.rs new file mode 100644 index 0000000000..98655a6ea4 --- /dev/null +++ b/modules/parachains/src/weights_ext.rs @@ -0,0 +1,108 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Weight-related utilities. + +use crate::weights::{MillauWeight, WeightInfo}; + +use bp_runtime::Size; +use frame_support::weights::{RuntimeDbWeight, Weight}; + +/// Size of the regular parachain head. +/// +/// It's not that we are expecting all parachain heads to share the same size or that we would +/// reject all heads that have larger/lesser size. It is about head size that we use in benchmarks. +/// Relayer would need to pay additional fee for extra bytes. +/// +/// 384 is a bit larger (1.3 times) than the size of the randomly chosen Polkadot block. +pub const DEFAULT_PARACHAIN_HEAD_SIZE: u32 = 384; + +/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at +/// the Rialto chain. +pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; + +/// Extended weight info. +pub trait WeightInfoExt: WeightInfo { + /// Storage proof overhead, that is included in every storage proof. + /// + /// The relayer would pay some extra fee for additional proof bytes, since they mean + /// more hashing operations. + fn expected_extra_storage_proof_size() -> u32; + + /// Weight of the parachain heads delivery extrinsic. + fn submit_parachain_heads_weight( + db_weight: RuntimeDbWeight, + proof: &impl Size, + parachains_count: u32, + ) -> Weight { + // weight of the `submit_parachain_heads` with exactly `parachains_count` parachain + // heads of the default size (`DEFAULT_PARACHAIN_HEAD_SIZE`) + let base_weight = Self::submit_parachain_heads_with_n_parachains(parachains_count); + + // overhead because of extra storage proof bytes + let expected_proof_size = parachains_count + .saturating_mul(DEFAULT_PARACHAIN_HEAD_SIZE) + .saturating_add(Self::expected_extra_storage_proof_size()); + let actual_proof_size = proof.size(); + let proof_size_overhead = Self::storage_proof_size_overhead( + actual_proof_size.saturating_sub(expected_proof_size), + ); + + // potential pruning weight (refunded if hasn't happened) + let pruning_weight = (parachains_count as Weight) + .saturating_mul(Self::parachain_head_pruning_weight(db_weight)); + + base_weight.saturating_add(proof_size_overhead).saturating_add(pruning_weight) + } + + /// Returns weight of single parachain head storage update. + /// + /// This weight only includes db write operations that happens if parachain head is actually + /// updated. All extra weights (weight of storage proof validation, additional checks, ...) is + /// not included. + fn parachain_head_storage_write_weight(db_weight: RuntimeDbWeight) -> Weight { + // it's just a couple of operations - we need to write the hash (`ImportedParaHashes`) and + // the head itself (`ImportedParaHeads`. Pruning is not included here + db_weight.writes(2) + } + + /// Returns weight of single parachain head pruning. + fn parachain_head_pruning_weight(db_weight: RuntimeDbWeight) -> Weight { + // it's just one write operation, we don't want any benchmarks for that + db_weight.writes(1) + } + + /// Returns weight that needs to be accounted when storage proof of given size is received. + fn storage_proof_size_overhead(extra_proof_bytes: u32) -> Weight { + let extra_proof_bytes_in_bytes = extra_proof_bytes as Weight; + let extra_byte_weight = (Self::submit_parachain_heads_with_16kb_proof() - + Self::submit_parachain_heads_with_1kb_proof()) / + (15 * 1024); + extra_proof_bytes_in_bytes.saturating_mul(extra_byte_weight) + } +} + +impl WeightInfoExt for () { + fn expected_extra_storage_proof_size() -> u32 { + EXTRA_STORAGE_PROOF_SIZE + } +} + +impl WeightInfoExt for MillauWeight { + fn expected_extra_storage_proof_size() -> u32 { + EXTRA_STORAGE_PROOF_SIZE + } +} diff --git a/modules/token-swap/Cargo.toml b/modules/relayers/Cargo.toml similarity index 59% rename from modules/token-swap/Cargo.toml rename to modules/relayers/Cargo.toml index aad395fb7a..70720a211c 100644 --- a/modules/token-swap/Cargo.toml +++ b/modules/relayers/Cargo.toml @@ -1,24 +1,22 @@ [package] -name = "pallet-bridge-token-swap" -description = "An Substrate pallet that allows parties on different chains (bridged using messages pallet) to swap their tokens" +name = "pallet-bridge-relayers" +description = "Module used to store relayer rewards and coordinate relayers set." version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } -serde = { version = "1.0", optional = true } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +log = { version = "0.4.17", default-features = false } +num-traits = { version = "0.2", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.101", optional = true, features = ["derive"] } # Bridge dependencies -bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false } bp-messages = { path = "../../primitives/messages", default-features = false } -bp-runtime = { path = "../../primitives/runtime", default-features = false } -bp-token-swap = { path = "../../primitives/token-swap", default-features = false } -pallet-bridge-dispatch = { path = "../dispatch", default-features = false } +bp-relayers = { path = "../../primitives/relayers", default-features = false } pallet-bridge-messages = { path = "../messages", default-features = false } # Substrate Dependencies @@ -26,32 +24,30 @@ pallet-bridge-messages = { path = "../messages", default-features = false } frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [dev-dependencies] +bp-runtime = { path = "../../primitives/runtime" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = ["std"] std = [ - "codec/std", - "bp-message-dispatch/std", "bp-messages/std", - "bp-runtime/std", - "bp-token-swap/std", + "bp-relayers/std", + "codec/std", "frame-support/std", "frame-system/std", "log/std", - "pallet-bridge-dispatch/std", + "num-traits/std", "pallet-bridge-messages/std", "scale-info/std", "serde", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", + "sp-arithmetic/std", "sp-std/std", ] runtime-benchmarks = [ diff --git a/modules/relayers/src/benchmarking.rs b/modules/relayers/src/benchmarking.rs new file mode 100644 index 0000000000..706454e049 --- /dev/null +++ b/modules/relayers/src/benchmarking.rs @@ -0,0 +1,40 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Benchmarks for the relayers Pallet. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::*; + +use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_system::RawOrigin; + +/// Reward amount that is (hopefully) is larger than existential deposit across all chains. +const REWARD_AMOUNT: u32 = u32::MAX; + +benchmarks! { + // Benchmark `claim_rewards` call. + claim_rewards { + let relayer: T::AccountId = whitelisted_caller(); + RelayerRewards::::insert(&relayer, T::Reward::from(REWARD_AMOUNT)); + }: _(RawOrigin::Signed(relayer)) + verify { + // we can't check anything here, because `PaymentProcedure` is responsible for + // payment logic, so we assume that if call has succeeded, the procedure has + // also completed successfully + } +} diff --git a/modules/relayers/src/lib.rs b/modules/relayers/src/lib.rs new file mode 100644 index 0000000000..779cc285c9 --- /dev/null +++ b/modules/relayers/src/lib.rs @@ -0,0 +1,195 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Runtime module that is used to store relayer rewards and (in the future) to +//! coordinate relations between relayers. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +use bp_relayers::PaymentProcedure; +use sp_arithmetic::traits::AtLeast32BitUnsigned; +use sp_std::marker::PhantomData; +use weights::WeightInfo; + +pub use pallet::*; +pub use payment_adapter::MessageDeliveryAndDispatchPaymentAdapter; + +mod benchmarking; +mod mock; +mod payment_adapter; + +pub mod weights; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-relayers"; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + /// Type of relayer reward. + type Reward: AtLeast32BitUnsigned + Copy + Parameter + MaxEncodedLen; + /// Pay rewards adapter. + type PaymentProcedure: PaymentProcedure; + /// Pallet call weights. + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::call] + impl Pallet { + /// Claim accumulated rewards. + #[pallet::weight(T::WeightInfo::claim_rewards())] + pub fn claim_rewards(origin: OriginFor) -> DispatchResult { + let relayer = ensure_signed(origin)?; + + RelayerRewards::::try_mutate_exists(&relayer, |maybe_reward| -> DispatchResult { + let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; + T::PaymentProcedure::pay_reward(&relayer, reward).map_err(|e| { + log::trace!( + target: LOG_TARGET, + "Failed to pay rewards to {:?}: {:?}", + relayer, + e, + ); + Error::::FailedToPayReward + })?; + + Self::deposit_event(Event::::RewardPaid { relayer: relayer.clone(), reward }); + Ok(()) + }) + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Reward has been paid to the relayer. + RewardPaid { + /// Relayer account that has been rewarded. + relayer: T::AccountId, + /// Reward amount. + reward: T::Reward, + }, + } + + #[pallet::error] + pub enum Error { + /// No reward can be claimed by given relayer. + NoRewardForRelayer, + /// Reward payment procedure has failed. + FailedToPayReward, + } + + /// Map of the relayer => accumulated reward. + #[pallet::storage] + pub type RelayerRewards = + StorageMap<_, Blake2_128Concat, T::AccountId, T::Reward, OptionQuery>; +} + +#[cfg(test)] +mod tests { + use super::*; + use mock::{Event as TestEvent, *}; + + use crate::Event::RewardPaid; + use frame_support::{assert_noop, assert_ok, traits::fungible::Inspect}; + use frame_system::{EventRecord, Pallet as System, Phase}; + use sp_runtime::DispatchError; + + fn get_ready_for_events() { + System::::set_block_number(1); + System::::reset_events(); + } + + #[test] + fn root_cant_claim_anything() { + run_test(|| { + assert_noop!( + Pallet::::claim_rewards(Origin::root()), + DispatchError::BadOrigin, + ); + }); + } + + #[test] + fn relayer_cant_claim_if_no_reward_exists() { + run_test(|| { + assert_noop!( + Pallet::::claim_rewards(Origin::signed(REGULAR_RELAYER)), + Error::::NoRewardForRelayer, + ); + }); + } + + #[test] + fn relayer_cant_claim_if_payment_procedure_fails() { + run_test(|| { + RelayerRewards::::insert(FAILING_RELAYER, 100); + assert_noop!( + Pallet::::claim_rewards(Origin::signed(FAILING_RELAYER)), + Error::::FailedToPayReward, + ); + }); + } + + #[test] + fn relayer_can_claim_reward() { + run_test(|| { + get_ready_for_events(); + + RelayerRewards::::insert(REGULAR_RELAYER, 100); + assert_ok!(Pallet::::claim_rewards(Origin::signed(REGULAR_RELAYER))); + assert_eq!(RelayerRewards::::get(REGULAR_RELAYER), None); + + //Check if the `RewardPaid` event was emitted. + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Relayers(RewardPaid { + relayer: REGULAR_RELAYER, + reward: 100 + }), + topics: vec![], + }], + ); + }); + } + + #[test] + fn mint_reward_payment_procedure_actually_mints_tokens() { + type Balances = pallet_balances::Pallet; + + run_test(|| { + assert_eq!(Balances::balance(&1), 0); + assert_eq!(Balances::total_issuance(), 0); + bp_relayers::MintReward::::pay_reward(&1, 100).unwrap(); + assert_eq!(Balances::balance(&1), 100); + assert_eq!(Balances::total_issuance(), 100); + }); + } +} diff --git a/modules/relayers/src/mock.rs b/modules/relayers/src/mock.rs new file mode 100644 index 0000000000..2ceabc6621 --- /dev/null +++ b/modules/relayers/src/mock.rs @@ -0,0 +1,156 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +#![cfg(test)] + +use crate as pallet_bridge_relayers; + +use bp_messages::{source_chain::ForbidOutboundMessages, target_chain::ForbidInboundMessages}; +use bp_relayers::PaymentProcedure; +use frame_support::{parameter_types, weights::RuntimeDbWeight}; +use sp_core::H256; +use sp_runtime::{ + testing::Header as SubstrateHeader, + traits::{BlakeTwo256, IdentityLookup}, +}; + +pub type AccountId = u64; +pub type Balance = u64; + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +frame_support::construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Event}, + Messages: pallet_bridge_messages::{Pallet, Event}, + Relayers: pallet_bridge_relayers::{Pallet, Call, Event}, + } +} + +parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; +} + +impl frame_system::Config for TestRuntime { + type Origin = Origin; + type Index = u64; + type Call = Call; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = SubstrateHeader; + type Event = Event; + type BlockHashCount = frame_support::traits::ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type BaseCallFilter = frame_support::traits::Everything; + type SystemWeightInfo = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = DbWeight; + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for TestRuntime { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = frame_support::traits::ConstU64<1>; + type AccountStore = frame_system::Pallet; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); +} + +parameter_types! { + pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; +} + +// we're not testing messages pallet here, so values in this config might be crazy +impl pallet_bridge_messages::Config for TestRuntime { + type Event = Event; + type WeightInfo = (); + type Parameter = (); + type MaxMessagesToPruneAtOnce = frame_support::traits::ConstU64<0>; + type MaxUnrewardedRelayerEntriesAtInboundLane = frame_support::traits::ConstU64<8>; + type MaxUnconfirmedMessagesAtInboundLane = frame_support::traits::ConstU64<8>; + + type MaximalOutboundPayloadSize = frame_support::traits::ConstU32<1024>; + type OutboundPayload = (); + type OutboundMessageFee = Balance; + + type InboundPayload = (); + type InboundMessageFee = Balance; + type InboundRelayer = AccountId; + + type TargetHeaderChain = ForbidOutboundMessages; + type LaneMessageVerifier = ForbidOutboundMessages; + type MessageDeliveryAndDispatchPayment = (); + type OnMessageAccepted = (); + type OnDeliveryConfirmed = (); + + type SourceHeaderChain = ForbidInboundMessages; + type MessageDispatch = ForbidInboundMessages; + type BridgedChainId = TestBridgedChainId; +} + +impl pallet_bridge_relayers::Config for TestRuntime { + type Event = Event; + type Reward = Balance; + type PaymentProcedure = TestPaymentProcedure; + type WeightInfo = (); +} + +/// Regular relayer that may receive rewards. +pub const REGULAR_RELAYER: AccountId = 1; + +/// Relayer that can't receive rewards. +pub const FAILING_RELAYER: AccountId = 2; + +/// Payment procedure that rejects payments to the `FAILING_RELAYER`. +pub struct TestPaymentProcedure; + +impl PaymentProcedure for TestPaymentProcedure { + type Error = (); + + fn pay_reward(relayer: &AccountId, _reward: Balance) -> Result<(), Self::Error> { + match *relayer { + FAILING_RELAYER => Err(()), + _ => Ok(()), + } + } +} + +/// Run pallet test. +pub fn run_test(test: impl FnOnce() -> T) -> T { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(test) +} diff --git a/modules/relayers/src/payment_adapter.rs b/modules/relayers/src/payment_adapter.rs new file mode 100644 index 0000000000..f027ab6429 --- /dev/null +++ b/modules/relayers/src/payment_adapter.rs @@ -0,0 +1,177 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Code that allows relayers pallet to be used as a delivery+dispatch payment mechanism +//! for the messages pallet. + +use crate::{Config, RelayerRewards}; + +use bp_messages::source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards}; +use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; +use sp_arithmetic::traits::{Saturating, Zero}; +use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; + +/// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism +/// for the messages pallet. +pub struct MessageDeliveryAndDispatchPaymentAdapter( + PhantomData<(T, MessagesInstance, GetConfirmationFee)>, +); + +impl + MessageDeliveryAndDispatchPayment + for MessageDeliveryAndDispatchPaymentAdapter +where + T: Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + GetConfirmationFee: Get, +{ + type Error = &'static str; + + fn pay_delivery_and_dispatch_fee( + _submitter: &T::Origin, + _fee: &T::Reward, + ) -> Result<(), Self::Error> { + // nothing shall happen here, because XCM deals with fee payment (planned to be burnt? + // or transferred to the treasury?) + Ok(()) + } + + fn pay_relayers_rewards( + lane_id: bp_messages::LaneId, + messages_relayers: VecDeque>, + confirmation_relayer: &T::AccountId, + received_range: &RangeInclusive, + ) { + let relayers_rewards = pallet_bridge_messages::calc_relayers_rewards::( + lane_id, + messages_relayers, + received_range, + ); + + register_relayers_rewards::( + confirmation_relayer, + relayers_rewards, + GetConfirmationFee::get(), + ); + } +} + +// Update rewards to given relayers, optionally rewarding confirmation relayer. +fn register_relayers_rewards( + confirmation_relayer: &T::AccountId, + relayers_rewards: RelayersRewards, + confirmation_fee: T::Reward, +) { + // reward every relayer except `confirmation_relayer` + let mut confirmation_relayer_reward = T::Reward::zero(); + for (relayer, reward) in relayers_rewards { + let mut relayer_reward = reward.reward; + + if relayer != *confirmation_relayer { + // If delivery confirmation is submitted by other relayer, let's deduct confirmation fee + // from relayer reward. + // + // If confirmation fee has been increased (or if it was the only component of message + // fee), then messages relayer may receive zero reward. + let mut confirmation_reward = + T::Reward::saturated_from(reward.messages).saturating_mul(confirmation_fee); + confirmation_reward = sp_std::cmp::min(confirmation_reward, relayer_reward); + relayer_reward = relayer_reward.saturating_sub(confirmation_reward); + confirmation_relayer_reward = + confirmation_relayer_reward.saturating_add(confirmation_reward); + + register_relayer_reward::(&relayer, relayer_reward); + } else { + // If delivery confirmation is submitted by this relayer, let's add confirmation fee + // from other relayers to this relayer reward. + confirmation_relayer_reward = + confirmation_relayer_reward.saturating_add(relayer_reward); + } + } + + // finally - pay reward to confirmation relayer + register_relayer_reward::(confirmation_relayer, confirmation_relayer_reward); +} + +/// Remember that the reward shall be paid to the relayer. +fn register_relayer_reward(relayer: &T::AccountId, reward: T::Reward) { + if reward.is_zero() { + return + } + + RelayerRewards::::mutate(relayer, |old_reward: &mut Option| { + let new_reward = old_reward.unwrap_or_else(Zero::zero).saturating_add(reward); + *old_reward = Some(new_reward); + + log::trace!( + target: crate::LOG_TARGET, + "Relayer {:?} can now claim reward: {:?}", + relayer, + new_reward, + ); + }); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::*; + + const RELAYER_1: AccountId = 1; + const RELAYER_2: AccountId = 2; + const RELAYER_3: AccountId = 3; + + fn relayers_rewards() -> RelayersRewards { + vec![ + (RELAYER_1, bp_messages::source_chain::RelayerRewards { reward: 100, messages: 2 }), + (RELAYER_2, bp_messages::source_chain::RelayerRewards { reward: 100, messages: 3 }), + ] + .into_iter() + .collect() + } + + #[test] + fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() { + run_test(|| { + register_relayers_rewards::(&RELAYER_2, relayers_rewards(), 10); + + assert_eq!(RelayerRewards::::get(RELAYER_1), Some(80)); + assert_eq!(RelayerRewards::::get(RELAYER_2), Some(120)); + }); + } + + #[test] + fn confirmation_relayer_is_rewarded_if_it_has_not_delivered_any_delivered_messages() { + run_test(|| { + register_relayers_rewards::(&RELAYER_3, relayers_rewards(), 10); + + assert_eq!(RelayerRewards::::get(RELAYER_1), Some(80)); + assert_eq!(RelayerRewards::::get(RELAYER_2), Some(70)); + assert_eq!(RelayerRewards::::get(RELAYER_3), Some(50)); + }); + } + + #[test] + fn only_confirmation_relayer_is_rewarded_if_confirmation_fee_has_significantly_increased() { + run_test(|| { + register_relayers_rewards::(&RELAYER_3, relayers_rewards(), 1000); + + assert_eq!(RelayerRewards::::get(RELAYER_1), None); + assert_eq!(RelayerRewards::::get(RELAYER_2), None); + assert_eq!(RelayerRewards::::get(RELAYER_3), Some(200)); + }); + } +} diff --git a/modules/token-swap/src/weights.rs b/modules/relayers/src/weights.rs similarity index 51% rename from modules/token-swap/src/weights.rs rename to modules/relayers/src/weights.rs index 51c5d99de9..fd7efe940d 100644 --- a/modules/token-swap/src/weights.rs +++ b/modules/relayers/src/weights.rs @@ -14,31 +14,33 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Autogenerated weights for `pallet_bridge_token_swap` +//! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-12-28, STEPS: 50, REPEAT: 20 +//! DATE: 2022-07-20, STEPS: 50, REPEAT: 20 //! LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled -//! CHAIN: Some("dev"), DB CACHE: 128 +//! CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/release/millau-bridge-node // benchmark +// pallet // --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_bridge_token_swap +// --pallet=pallet_bridge_relayers // --extrinsic=* // --execution=wasm // --wasm-execution=Compiled // --heap-pages=4096 -// --output=./modules/token-swap/src/weights.rs +// --output=./modules/relayers/src/weights.rs // --template=./.maintain/millau-weight-template.hbs #![allow(clippy::all)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{ traits::Get, @@ -46,48 +48,26 @@ use frame_support::{ }; use sp_std::marker::PhantomData; -/// Weight functions needed for `pallet_bridge_token_swap`. +/// Weight functions needed for `pallet_bridge_relayers`. pub trait WeightInfo { - fn create_swap() -> Weight; - fn claim_swap() -> Weight; - fn cancel_swap() -> Weight; + fn claim_rewards() -> Weight; } -/// Weights for `pallet_bridge_token_swap` using the Millau node and recommended hardware. +/// Weights for `pallet_bridge_relayers` using the Millau node and recommended hardware. pub struct MillauWeight(PhantomData); impl WeightInfo for MillauWeight { - fn create_swap() -> Weight { - (90_368_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - } - fn claim_swap() -> Weight { - (88_397_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - } - fn cancel_swap() -> Weight { - (91_253_000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + fn claim_rewards() -> Weight { + (38_435_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { - fn create_swap() -> Weight { - (90_368_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) - } - fn claim_swap() -> Weight { - (88_397_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) - } - fn cancel_swap() -> Weight { - (91_253_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(3 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + fn claim_rewards() -> Weight { + (38_435_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } } diff --git a/modules/shift-session-manager/Cargo.toml b/modules/shift-session-manager/Cargo.toml index 30a5618b11..5dae3e00fd 100644 --- a/modules/shift-session-manager/Cargo.toml +++ b/modules/shift-session-manager/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } # Substrate Dependencies diff --git a/modules/shift-session-manager/src/lib.rs b/modules/shift-session-manager/src/lib.rs index 9cf8441257..f8475851bb 100644 --- a/modules/shift-session-manager/src/lib.rs +++ b/modules/shift-session-manager/src/lib.rs @@ -19,6 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use frame_support::traits::{ValidatorSet, ValidatorSetWithIdentification}; use sp_std::prelude::*; pub use pallet::*; @@ -49,6 +50,24 @@ pub mod pallet { pub(super) type InitialValidators = StorageValue<_, Vec>; } +impl ValidatorSet for Pallet { + type ValidatorId = T::ValidatorId; + type ValidatorIdOf = T::ValidatorIdOf; + + fn session_index() -> sp_staking::SessionIndex { + pallet_session::Pallet::::current_index() + } + + fn validators() -> Vec { + pallet_session::Pallet::::validators() + } +} + +impl ValidatorSetWithIdentification for Pallet { + type Identification = (); + type IdentificationOf = (); +} + impl pallet_session::SessionManager for Pallet { fn end_session(_: sp_staking::SessionIndex) {} fn start_session(_: sp_staking::SessionIndex) {} diff --git a/modules/token-swap/src/benchmarking.rs b/modules/token-swap/src/benchmarking.rs deleted file mode 100644 index 878cb20993..0000000000 --- a/modules/token-swap/src/benchmarking.rs +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Token-swap pallet benchmarking. - -use crate::{ - swap_account_id, target_account_at_this_chain, BridgedAccountIdOf, BridgedAccountPublicOf, - BridgedAccountSignatureOf, BridgedBalanceOf, Call, Origin, Pallet, ThisChainBalance, - TokenSwapCreationOf, TokenSwapOf, -}; - -use bp_token_swap::{TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType}; -use codec::{Decode, Encode}; -use frame_benchmarking::{account, benchmarks_instance_pallet}; -use frame_support::{traits::Currency, Parameter}; -use frame_system::RawOrigin; -use sp_core::H256; -use sp_io::hashing::blake2_256; -use sp_runtime::traits::{Bounded, TrailingZeroInput}; -use sp_std::{boxed::Box, vec::Vec}; - -const SEED: u32 = 0; - -/// Trait that must be implemented by runtime. -pub trait Config: crate::Config { - /// Initialize environment for token swap. - fn initialize_environment(); -} - -benchmarks_instance_pallet! { - where_clause { - where - Origin: Into, - BridgedAccountPublicOf: Decode + Parameter, - BridgedAccountSignatureOf: Decode, - } - - // - // Benchmarks that are used directly by the runtime. - // - - // Benchmark `create_swap` extrinsic. - // - // This benchmark assumes that message is **NOT** actually sent. Instead we're using `send_message_weight` - // from the `WeightInfoExt` trait. - // - // There aren't any factors that affect `create_swap` performance, so everything - // is straightforward here. - create_swap { - T::initialize_environment(); - - let sender = funded_account::("source_account_at_this_chain", 0); - let swap: TokenSwapOf = test_swap::(sender.clone(), true); - let swap_creation: TokenSwapCreationOf = test_swap_creation::(); - }: create_swap( - RawOrigin::Signed(sender.clone()), - swap, - Box::new(swap_creation) - ) - verify { - assert!(crate::PendingSwaps::::contains_key(test_swap_hash::(sender, true))); - } - - // Benchmark `claim_swap` extrinsic with the worst possible conditions: - // - // * swap is locked until some block, so current block number is read. - claim_swap { - T::initialize_environment(); - - let sender: T::AccountId = account("source_account_at_this_chain", 0, SEED); - crate::PendingSwaps::::insert( - test_swap_hash::(sender.clone(), false), - TokenSwapState::Confirmed, - ); - - let swap: TokenSwapOf = test_swap::(sender.clone(), false); - let claimer = target_account_at_this_chain::(&swap); - let token_swap_account = swap_account_id::(&swap); - T::ThisCurrency::make_free_balance_be(&token_swap_account, ThisChainBalance::::max_value()); - }: claim_swap(RawOrigin::Signed(claimer), swap) - verify { - assert!(!crate::PendingSwaps::::contains_key(test_swap_hash::(sender, false))); - } - - // Benchmark `cancel_swap` extrinsic with the worst possible conditions: - // - // * swap is locked until some block, so current block number is read. - cancel_swap { - T::initialize_environment(); - - let sender: T::AccountId = account("source_account_at_this_chain", 0, SEED); - crate::PendingSwaps::::insert( - test_swap_hash::(sender.clone(), false), - TokenSwapState::Failed, - ); - - let swap: TokenSwapOf = test_swap::(sender.clone(), false); - let token_swap_account = swap_account_id::(&swap); - T::ThisCurrency::make_free_balance_be(&token_swap_account, ThisChainBalance::::max_value()); - - }: cancel_swap(RawOrigin::Signed(sender.clone()), swap) - verify { - assert!(!crate::PendingSwaps::::contains_key(test_swap_hash::(sender, false))); - } -} - -/// Returns test token swap. -fn test_swap, I: 'static>(sender: T::AccountId, is_create: bool) -> TokenSwapOf { - TokenSwap { - swap_type: TokenSwapType::LockClaimUntilBlock( - if is_create { 10u32.into() } else { 0u32.into() }, - 0.into(), - ), - source_balance_at_this_chain: source_balance_to_swap::(), - source_account_at_this_chain: sender, - target_balance_at_bridged_chain: target_balance_to_swap::(), - target_account_at_bridged_chain: target_account_at_bridged_chain::(), - } -} - -/// Returns test token swap hash. -fn test_swap_hash, I: 'static>(sender: T::AccountId, is_create: bool) -> H256 { - test_swap::(sender, is_create).using_encoded(blake2_256).into() -} - -/// Returns test token swap creation params. -fn test_swap_creation, I: 'static>() -> TokenSwapCreationOf -where - BridgedAccountPublicOf: Decode, - BridgedAccountSignatureOf: Decode, -{ - TokenSwapCreation { - target_public_at_bridged_chain: target_public_at_bridged_chain::(), - swap_delivery_and_dispatch_fee: swap_delivery_and_dispatch_fee::(), - bridged_chain_spec_version: 0, - bridged_currency_transfer: Vec::new(), - bridged_currency_transfer_weight: 0, - bridged_currency_transfer_signature: bridged_currency_transfer_signature::(), - } -} - -/// Account that has some balance. -fn funded_account, I: 'static>(name: &'static str, index: u32) -> T::AccountId { - let account: T::AccountId = account(name, index, SEED); - T::ThisCurrency::make_free_balance_be(&account, ThisChainBalance::::max_value()); - account -} - -/// Currency transfer message fee. -fn swap_delivery_and_dispatch_fee, I: 'static>() -> ThisChainBalance { - ThisChainBalance::::max_value() / 4u32.into() -} - -/// Balance at the source chain that we're going to swap. -fn source_balance_to_swap, I: 'static>() -> ThisChainBalance { - ThisChainBalance::::max_value() / 2u32.into() -} - -/// Balance at the target chain that we're going to swap. -fn target_balance_to_swap, I: 'static>() -> BridgedBalanceOf { - BridgedBalanceOf::::max_value() / 2u32.into() -} - -/// Public key of `target_account_at_bridged_chain`. -fn target_public_at_bridged_chain, I: 'static>() -> BridgedAccountPublicOf -where - BridgedAccountPublicOf: Decode, -{ - BridgedAccountPublicOf::::decode(&mut TrailingZeroInput::zeroes()) - .expect("failed to decode `BridgedAccountPublicOf` from zeroes") -} - -/// Signature of `target_account_at_bridged_chain` over message. -fn bridged_currency_transfer_signature, I: 'static>() -> BridgedAccountSignatureOf -where - BridgedAccountSignatureOf: Decode, -{ - BridgedAccountSignatureOf::::decode(&mut TrailingZeroInput::zeroes()) - .expect("failed to decode `BridgedAccountSignatureOf` from zeroes") -} - -/// Account at the bridged chain that is participating in the swap. -fn target_account_at_bridged_chain, I: 'static>() -> BridgedAccountIdOf { - account("target_account_at_bridged_chain", 0, SEED) -} diff --git a/modules/token-swap/src/lib.rs b/modules/token-swap/src/lib.rs deleted file mode 100644 index e46a4bc2dd..0000000000 --- a/modules/token-swap/src/lib.rs +++ /dev/null @@ -1,1191 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Runtime module that allows token swap between two parties acting on different chains. -//! -//! The swap is made using message lanes between This (where `pallet-bridge-token-swap` pallet -//! is deployed) and some other Bridged chain. No other assumptions about the Bridged chain are -//! made, so we don't need it to have an instance of the `pallet-bridge-token-swap` pallet deployed. -//! -//! There are four accounts participating in the swap: -//! -//! 1) account of This chain that has signed the `create_swap` transaction and has balance on This -//! chain. We'll be referring to this account as `source_account_at_this_chain`; -//! -//! 2) account of the Bridged chain that is sending the `claim_swap` message from the Bridged to -//! This chain. This account has balance on Bridged chain and is willing to swap these tokens to -//! This chain tokens of the `source_account_at_this_chain`. We'll be referring to this account -//! as `target_account_at_bridged_chain`; -//! -//! 3) account of the Bridged chain that is indirectly controlled by the -//! `source_account_at_this_chain`. We'll be referring this account as -//! `source_account_at_bridged_chain`; -//! -//! 4) account of This chain that is indirectly controlled by the `target_account_at_bridged_chain`. -//! We'll be referring this account as `target_account_at_this_chain`. -//! -//! So the tokens swap is an intention of `source_account_at_this_chain` to swap his -//! `source_balance_at_this_chain` tokens to the `target_balance_at_bridged_chain` tokens owned by -//! `target_account_at_bridged_chain`. The swap process goes as follows: -//! -//! 1) the `source_account_at_this_chain` account submits the `create_swap` transaction on This -//! chain; -//! -//! 2) the tokens transfer message that would transfer `target_balance_at_bridged_chain` -//! tokens from the `target_account_at_bridged_chain` to the `source_account_at_bridged_chain`, -//! is sent over the bridge; -//! -//! 3) when transfer message is delivered and dispatched, the pallet receives notification; -//! -//! 4) if message has been successfully dispatched, the `target_account_at_bridged_chain` sends the -//! message that would transfer `source_balance_at_this_chain` tokens to his -//! `target_account_at_this_chain` account; -//! -//! 5) if message dispatch has failed, the `source_account_at_this_chain` may submit the -//! `cancel_swap` transaction and return his `source_balance_at_this_chain` back to his account. -//! -//! While swap is pending, the `source_balance_at_this_chain` tokens are owned by the special -//! temporary `swap_account_at_this_chain` account. It is destroyed upon swap completion. - -#![cfg_attr(not(feature = "std"), no_std)] - -use bp_messages::{ - source_chain::{MessagesBridge, OnDeliveryConfirmed}, - DeliveredMessages, LaneId, MessageNonce, -}; -use bp_runtime::{messages::DispatchFeePayment, ChainId}; -use bp_token_swap::{ - RawBridgedTransferCall, TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType, -}; -use codec::{Decode, Encode}; -use frame_support::{ - fail, - traits::{Currency, ExistenceRequirement}, - weights::PostDispatchInfo, - RuntimeDebug, -}; -use scale_info::TypeInfo; -use sp_core::H256; -use sp_io::hashing::blake2_256; -use sp_runtime::traits::{Convert, Saturating}; -use sp_std::{boxed::Box, marker::PhantomData}; -use weights::WeightInfo; - -pub use weights_ext::WeightInfoExt; - -#[cfg(test)] -mod mock; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -pub mod weights; -pub mod weights_ext; - -pub use pallet::*; - -/// Name of the `PendingSwaps` storage map. -pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps"; - -/// Origin for the token swap pallet. -#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub enum RawOrigin { - /// The call is originated by the token swap account. - TokenSwap { - /// Id of the account that has started the swap. - source_account_at_this_chain: AccountId, - /// Id of the account that holds the funds during this swap. The message fee is paid from - /// this account funds. - swap_account_at_this_chain: AccountId, - }, - /// Dummy to manage the fact we have instancing. - _Phantom(PhantomData), -} - -// comes from #[pallet::event] -#[allow(clippy::unused_unit)] -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type Event: From> + IsType<::Event>; - /// Benchmarks results from runtime we're plugged into. - type WeightInfo: WeightInfoExt; - - /// Id of the bridge with the Bridged chain. - type BridgedChainId: Get; - /// The identifier of outbound message lane on This chain used to send token transfer - /// messages to the Bridged chain. - /// - /// It is highly recommended to use dedicated lane for every instance of token swap - /// pallet. Messages delivery confirmation callback is implemented in the way that - /// for every confirmed message, there is (at least) a storage read. Which mean, - /// that if pallet will see unrelated confirmations, it'll just burn storage-read - /// weight, achieving nothing. - type OutboundMessageLaneId: Get; - /// Messages bridge with Bridged chain. - type MessagesBridge: MessagesBridge< - Self::Origin, - Self::AccountId, - >::Balance, - MessagePayloadOf, - >; - - /// This chain Currency used in the tokens swap. - type ThisCurrency: Currency; - /// Converter from raw hash (derived from swap) to This chain account. - type FromSwapToThisAccountIdConverter: Convert; - - /// The chain we're bridged to. - type BridgedChain: bp_runtime::Chain; - /// Converter from raw hash (derived from Bridged chain account) to This chain account. - type FromBridgedToThisAccountIdConverter: Convert; - } - - /// Tokens balance at This chain. - pub type ThisChainBalance = <>::ThisCurrency as Currency< - ::AccountId, - >>::Balance; - - /// Type of the Bridged chain. - pub type BridgedChainOf = >::BridgedChain; - /// Tokens balance type at the Bridged chain. - pub type BridgedBalanceOf = bp_runtime::BalanceOf>; - /// Account identifier type at the Bridged chain. - pub type BridgedAccountIdOf = bp_runtime::AccountIdOf>; - /// Account public key type at the Bridged chain. - pub type BridgedAccountPublicOf = bp_runtime::AccountPublicOf>; - /// Account signature type at the Bridged chain. - pub type BridgedAccountSignatureOf = bp_runtime::SignatureOf>; - - /// Bridge message payload used by the pallet. - pub type MessagePayloadOf = bp_message_dispatch::MessagePayload< - ::AccountId, - BridgedAccountPublicOf, - BridgedAccountSignatureOf, - RawBridgedTransferCall, - >; - /// Type of `TokenSwap` used by the pallet. - pub type TokenSwapOf = TokenSwap< - BlockNumberFor, - ThisChainBalance, - ::AccountId, - BridgedBalanceOf, - BridgedAccountIdOf, - >; - /// Type of `TokenSwapCreation` used by the pallet. - pub type TokenSwapCreationOf = TokenSwapCreation< - BridgedAccountPublicOf, - ThisChainBalance, - BridgedAccountSignatureOf, - >; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] - pub struct Pallet(PhantomData<(T, I)>); - - #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet {} - - #[pallet::call] - impl, I: 'static> Pallet - where - BridgedAccountPublicOf: Parameter, - Origin: Into, - { - /// Start token swap procedure. - /// - /// The dispatch origin for this call must be exactly the - /// `swap.source_account_at_this_chain` account. - /// - /// Method arguments are: - /// - /// - `swap` - token swap intention; - /// - `swap_creation_params` - additional parameters required to start tokens swap. - /// - /// The `source_account_at_this_chain` MUST have enough balance to cover both token swap and - /// message transfer. Message fee may be estimated using corresponding `OutboundLaneApi` of - /// This runtime. - /// - /// **WARNING**: the submitter of this transaction is responsible for verifying: - /// - /// 1) that the `swap_creation_params.bridged_currency_transfer` represents a valid token - /// transfer call that transfers `swap.target_balance_at_bridged_chain` to his - /// `swap.source_account_at_bridged_chain` account; - /// - /// 2) that either the `swap.source_account_at_bridged_chain` already exists, or the - /// `swap.target_balance_at_bridged_chain` is above existential deposit of the Bridged - /// chain; - /// - /// 3) the `swap_creation_params.target_public_at_bridged_chain` matches the - /// `swap.target_account_at_bridged_chain`; - /// - /// 4) the `bridged_currency_transfer_signature` is valid and generated by the owner of - /// the `swap_creation_params.target_public_at_bridged_chain` account (read more - /// about [`CallOrigin::TargetAccount`]). - /// - /// Violating rule#1 will lead to losing your `source_balance_at_this_chain` tokens. - /// Violating other rules will lead to losing message fees for this and other transactions + - /// losing fees for message transfer. - #[allow(clippy::boxed_local)] - #[pallet::weight( - T::WeightInfo::create_swap() - .saturating_add(T::WeightInfo::send_message_weight( - &&swap_creation_params.bridged_currency_transfer[..], - T::DbWeight::get(), - )) - )] - pub fn create_swap( - origin: OriginFor, - swap: TokenSwapOf, - swap_creation_params: Box>, - ) -> DispatchResultWithPostInfo { - let TokenSwapCreation { - target_public_at_bridged_chain, - swap_delivery_and_dispatch_fee, - bridged_chain_spec_version, - bridged_currency_transfer, - bridged_currency_transfer_weight, - bridged_currency_transfer_signature, - } = *swap_creation_params; - - // ensure that the `origin` is the same account that is mentioned in the `swap` - // intention - let origin_account = ensure_signed(origin)?; - ensure!( - origin_account == swap.source_account_at_this_chain, - Error::::MismatchedSwapSourceOrigin, - ); - - // remember weight components - let base_weight = T::WeightInfo::create_swap(); - - // we can't exchange less than existential deposit (the temporary `swap_account` account - // won't be created then) - // - // the same can also happen with the `swap.bridged_balance`, but we can't check it - // here (without additional knowledge of the Bridged chain). So it is the `origin` - // responsibility to check that the swap is valid. - ensure!( - swap.source_balance_at_this_chain >= T::ThisCurrency::minimum_balance(), - Error::::TooLowBalanceOnThisChain, - ); - - // if the swap is replay-protected, then we need to ensure that we have not yet passed - // the specified block yet - match swap.swap_type { - TokenSwapType::TemporaryTargetAccountAtBridgedChain => (), - TokenSwapType::LockClaimUntilBlock(block_number, _) => ensure!( - block_number >= frame_system::Pallet::::block_number(), - Error::::SwapPeriodIsFinished, - ), - } - - let swap_account = swap_account_id::(&swap); - let actual_send_message_weight = frame_support::storage::with_transaction(|| { - // funds are transferred from This account to the temporary Swap account - let transfer_result = T::ThisCurrency::transfer( - &swap.source_account_at_this_chain, - &swap_account, - // saturating_add is ok, or we have the chain where single holder owns all - // tokens - swap.source_balance_at_this_chain - .saturating_add(swap_delivery_and_dispatch_fee), - // if we'll allow account to die, then he'll be unable to `cancel_claim` - // if something won't work - ExistenceRequirement::KeepAlive, - ); - if let Err(err) = transfer_result { - log::error!( - target: "runtime::bridge-token-swap", - "Failed to transfer This chain tokens for the swap {:?} to Swap account ({:?}): {:?}", - swap, - swap_account, - err, - ); - - return sp_runtime::TransactionOutcome::Rollback(Err( - Error::::FailedToTransferToSwapAccount, - )) - } - - // the transfer message is sent over the bridge. The message is supposed to be a - // `Currency::transfer` call on the bridged chain, but no checks are made - it is - // the transaction submitter to ensure it is valid. - let send_message_result = T::MessagesBridge::send_message( - RawOrigin::TokenSwap { - source_account_at_this_chain: swap.source_account_at_this_chain.clone(), - swap_account_at_this_chain: swap_account.clone(), - } - .into(), - T::OutboundMessageLaneId::get(), - bp_message_dispatch::MessagePayload { - spec_version: bridged_chain_spec_version, - weight: bridged_currency_transfer_weight, - origin: bp_message_dispatch::CallOrigin::TargetAccount( - swap_account, - target_public_at_bridged_chain, - bridged_currency_transfer_signature, - ), - dispatch_fee_payment: DispatchFeePayment::AtTargetChain, - call: bridged_currency_transfer, - }, - swap_delivery_and_dispatch_fee, - ); - let sent_message = match send_message_result { - Ok(sent_message) => sent_message, - Err(err) => { - log::error!( - target: "runtime::bridge-token-swap", - "Failed to send token transfer message for swap {:?} to the Bridged chain: {:?}", - swap, - err, - ); - - return sp_runtime::TransactionOutcome::Rollback(Err( - Error::::FailedToSendTransferMessage, - )) - }, - }; - - // remember that we have started the swap - let swap_hash = swap.using_encoded(blake2_256).into(); - let insert_swap_result = - PendingSwaps::::try_mutate(swap_hash, |maybe_state| { - if maybe_state.is_some() { - return Err(()) - } - - *maybe_state = Some(TokenSwapState::Started); - Ok(()) - }); - if insert_swap_result.is_err() { - log::error!( - target: "runtime::bridge-token-swap", - "Failed to start token swap {:?}: the swap is already started", - swap, - ); - - return sp_runtime::TransactionOutcome::Rollback(Err( - Error::::SwapAlreadyStarted, - )) - } - - log::trace!( - target: "runtime::bridge-token-swap", - "The swap {:?} (hash {:?}) has been started", - swap, - swap_hash, - ); - - // remember that we're waiting for the transfer message delivery confirmation - PendingMessages::::insert(sent_message.nonce, swap_hash); - - // finally - emit the event - Self::deposit_event(Event::SwapStarted(swap_hash, sent_message.nonce)); - - sp_runtime::TransactionOutcome::Commit(Ok(sent_message.weight)) - })?; - - Ok(PostDispatchInfo { - actual_weight: Some(base_weight.saturating_add(actual_send_message_weight)), - pays_fee: Pays::Yes, - }) - } - - /// Claim previously reserved `source_balance_at_this_chain` by - /// `target_account_at_this_chain`. - /// - /// **WARNING**: the correct way to call this function is to call it over the messages - /// bridge with dispatch origin set to - /// `pallet_bridge_dispatch::CallOrigin::SourceAccount(target_account_at_bridged_chain)`. - /// - /// This should be called only when successful transfer confirmation has been received. - #[pallet::weight(T::WeightInfo::claim_swap())] - pub fn claim_swap( - origin: OriginFor, - swap: TokenSwapOf, - ) -> DispatchResultWithPostInfo { - // ensure that the `origin` is controlled by the `swap.target_account_at_bridged_chain` - let origin_account = ensure_signed(origin)?; - let target_account_at_this_chain = target_account_at_this_chain::(&swap); - ensure!(origin_account == target_account_at_this_chain, Error::::InvalidClaimant,); - - // ensure that the swap is confirmed - let swap_hash = swap.using_encoded(blake2_256).into(); - let swap_state = PendingSwaps::::get(swap_hash); - match swap_state { - Some(TokenSwapState::Started) => fail!(Error::::SwapIsPending), - Some(TokenSwapState::Confirmed) => { - let is_claim_allowed = match swap.swap_type { - TokenSwapType::TemporaryTargetAccountAtBridgedChain => true, - TokenSwapType::LockClaimUntilBlock(block_number, _) => - block_number < frame_system::Pallet::::block_number(), - }; - - ensure!(is_claim_allowed, Error::::SwapIsTemporaryLocked); - }, - Some(TokenSwapState::Failed) => fail!(Error::::SwapIsFailed), - None => fail!(Error::::SwapIsInactive), - } - - complete_claim::(swap, swap_hash, origin_account, Event::SwapClaimed(swap_hash)) - } - - /// Return previously reserved `source_balance_at_this_chain` back to the - /// `source_account_at_this_chain`. - /// - /// This should be called only when transfer has failed at Bridged chain and we have - /// received notification about that. - #[pallet::weight(T::WeightInfo::cancel_swap())] - pub fn cancel_swap( - origin: OriginFor, - swap: TokenSwapOf, - ) -> DispatchResultWithPostInfo { - // ensure that the `origin` is the same account that is mentioned in the `swap` - // intention - let origin_account = ensure_signed(origin)?; - ensure!( - origin_account == swap.source_account_at_this_chain, - Error::::MismatchedSwapSourceOrigin, - ); - - // ensure that the swap has failed - let swap_hash = swap.using_encoded(blake2_256).into(); - let swap_state = PendingSwaps::::get(swap_hash); - match swap_state { - Some(TokenSwapState::Started) => fail!(Error::::SwapIsPending), - Some(TokenSwapState::Confirmed) => fail!(Error::::SwapIsConfirmed), - Some(TokenSwapState::Failed) => { - // we allow canceling swap even before lock period is over - the - // `source_account_at_this_chain` has already paid for nothing and it is up to - // him to decide whether he want to try again - }, - None => fail!(Error::::SwapIsInactive), - } - - complete_claim::(swap, swap_hash, origin_account, Event::SwapCanceled(swap_hash)) - } - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event, I: 'static = ()> { - /// Tokens swap has been started and message has been sent to the bridged message. - /// - /// The payload is the swap hash and the transfer message nonce. - SwapStarted(H256, MessageNonce), - /// Token swap has been claimed. - SwapClaimed(H256), - /// Token swap has been canceled. - SwapCanceled(H256), - } - - #[pallet::error] - pub enum Error { - /// The account that has submitted the `start_claim` doesn't match the - /// `TokenSwap::source_account_at_this_chain`. - MismatchedSwapSourceOrigin, - /// The swap balance in This chain tokens is below existential deposit and can't be made. - TooLowBalanceOnThisChain, - /// Transfer from This chain account to temporary Swap account has failed. - FailedToTransferToSwapAccount, - /// Transfer from the temporary Swap account to the derived account of Bridged account has - /// failed. - FailedToTransferFromSwapAccount, - /// The message to transfer tokens on Target chain can't be sent. - FailedToSendTransferMessage, - /// The same swap is already started. - SwapAlreadyStarted, - /// Swap outcome is not yet received. - SwapIsPending, - /// Someone is trying to claim swap that has failed. - SwapIsFailed, - /// Claiming swap is not allowed. - /// - /// Now the only possible case when you may get this error, is when you're trying to claim - /// swap with `TokenSwapType::LockClaimUntilBlock` before lock period is over. - SwapIsTemporaryLocked, - /// Swap period is finished and you can not restart it. - /// - /// Now the only possible case when you may get this error, is when you're trying to start - /// swap with `TokenSwapType::LockClaimUntilBlock` after lock period is over. - SwapPeriodIsFinished, - /// Someone is trying to cancel swap that has been confirmed. - SwapIsConfirmed, - /// Someone is trying to claim/cancel swap that is either not started or already - /// claimed/canceled. - SwapIsInactive, - /// The swap claimant is invalid. - InvalidClaimant, - } - - /// Origin for the token swap pallet. - #[pallet::origin] - pub type Origin = RawOrigin<::AccountId, I>; - - /// Pending token swaps states. - #[pallet::storage] - pub type PendingSwaps, I: 'static = ()> = - StorageMap<_, Identity, H256, TokenSwapState>; - - /// Pending transfer messages. - #[pallet::storage] - pub type PendingMessages, I: 'static = ()> = - StorageMap<_, Identity, MessageNonce, H256>; - - impl, I: 'static> OnDeliveryConfirmed for Pallet { - fn on_messages_delivered(lane: &LaneId, delivered_messages: &DeliveredMessages) -> Weight { - // we're only interested in our lane messages - if *lane != T::OutboundMessageLaneId::get() { - return 0 - } - - // so now we're dealing with our lane messages. Ideally we'll have dedicated lane - // and every message from `delivered_messages` is actually our transfer message. - // But it may be some shared lane (which is not recommended). - let mut reads = 0; - let mut writes = 0; - for message_nonce in delivered_messages.begin..=delivered_messages.end { - reads += 1; - if let Some(swap_hash) = PendingMessages::::take(message_nonce) { - writes += 1; - - let token_swap_state = - if delivered_messages.message_dispatch_result(message_nonce) { - TokenSwapState::Confirmed - } else { - TokenSwapState::Failed - }; - - log::trace!( - target: "runtime::bridge-token-swap", - "The dispatch of swap {:?} has been completed with {:?} status", - swap_hash, - token_swap_state, - ); - - PendingSwaps::::insert(swap_hash, token_swap_state); - } - } - - ::DbWeight::get().reads_writes(reads, writes) - } - } - - /// Returns temporary account id used to lock funds during swap on This chain. - pub(crate) fn swap_account_id, I: 'static>( - swap: &TokenSwapOf, - ) -> T::AccountId { - T::FromSwapToThisAccountIdConverter::convert(swap.using_encoded(blake2_256).into()) - } - - /// Expected target account representation on This chain (aka `target_account_at_this_chain`). - pub(crate) fn target_account_at_this_chain, I: 'static>( - swap: &TokenSwapOf, - ) -> T::AccountId { - T::FromBridgedToThisAccountIdConverter::convert(bp_runtime::derive_account_id( - T::BridgedChainId::get(), - bp_runtime::SourceAccount::Account(swap.target_account_at_bridged_chain.clone()), - )) - } - - /// Complete claim with given outcome. - pub(crate) fn complete_claim, I: 'static>( - swap: TokenSwapOf, - swap_hash: H256, - destination_account: T::AccountId, - event: Event, - ) -> DispatchResultWithPostInfo { - let swap_account = swap_account_id::(&swap); - frame_support::storage::with_transaction(|| { - // funds are transferred from the temporary Swap account to the destination account - let transfer_result = T::ThisCurrency::transfer( - &swap_account, - &destination_account, - swap.source_balance_at_this_chain, - ExistenceRequirement::AllowDeath, - ); - if let Err(err) = transfer_result { - log::error!( - target: "runtime::bridge-token-swap", - "Failed to transfer This chain tokens for the swap {:?} from the Swap account {:?} to {:?}: {:?}", - swap, - swap_account, - destination_account, - err, - ); - - return sp_runtime::TransactionOutcome::Rollback(Err( - Error::::FailedToTransferFromSwapAccount.into(), - )) - } - - log::trace!( - target: "runtime::bridge-token-swap", - "The swap {:?} (hash {:?}) has been completed with {} status", - swap, - swap_hash, - match event { - Event::SwapClaimed(_) => "claimed", - Event::SwapCanceled(_) => "canceled", - _ => "", - }, - ); - - // forget about swap - PendingSwaps::::remove(swap_hash); - - // finally - emit the event - Pallet::::deposit_event(event); - - sp_runtime::TransactionOutcome::Commit(Ok(().into())) - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::*; - use frame_support::{assert_noop, assert_ok, storage::generator::StorageMap}; - - const CAN_START_BLOCK_NUMBER: u64 = 10; - const CAN_CLAIM_BLOCK_NUMBER: u64 = CAN_START_BLOCK_NUMBER + 1; - - const BRIDGED_CHAIN_ACCOUNT: BridgedAccountId = 3; - const BRIDGED_CHAIN_SPEC_VERSION: u32 = 4; - const BRIDGED_CHAIN_CALL_WEIGHT: Balance = 5; - - fn bridged_chain_account_public() -> BridgedAccountPublic { - 1.into() - } - - fn bridged_chain_account_signature() -> BridgedAccountSignature { - sp_runtime::testing::TestSignature(2, Vec::new()) - } - - fn test_swap() -> TokenSwapOf { - bp_token_swap::TokenSwap { - swap_type: TokenSwapType::LockClaimUntilBlock(CAN_START_BLOCK_NUMBER, 0.into()), - source_balance_at_this_chain: 100, - source_account_at_this_chain: THIS_CHAIN_ACCOUNT, - target_balance_at_bridged_chain: 200, - target_account_at_bridged_chain: BRIDGED_CHAIN_ACCOUNT, - } - } - - fn test_swap_creation() -> TokenSwapCreationOf { - TokenSwapCreation { - target_public_at_bridged_chain: bridged_chain_account_public(), - swap_delivery_and_dispatch_fee: SWAP_DELIVERY_AND_DISPATCH_FEE, - bridged_chain_spec_version: BRIDGED_CHAIN_SPEC_VERSION, - bridged_currency_transfer: test_transfer(), - bridged_currency_transfer_weight: BRIDGED_CHAIN_CALL_WEIGHT, - bridged_currency_transfer_signature: bridged_chain_account_signature(), - } - } - - fn test_swap_hash() -> H256 { - test_swap().using_encoded(blake2_256).into() - } - - fn test_transfer() -> RawBridgedTransferCall { - vec![OK_TRANSFER_CALL] - } - - fn start_test_swap() { - assert_ok!(Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(TokenSwapCreation { - target_public_at_bridged_chain: bridged_chain_account_public(), - swap_delivery_and_dispatch_fee: SWAP_DELIVERY_AND_DISPATCH_FEE, - bridged_chain_spec_version: BRIDGED_CHAIN_SPEC_VERSION, - bridged_currency_transfer: test_transfer(), - bridged_currency_transfer_weight: BRIDGED_CHAIN_CALL_WEIGHT, - bridged_currency_transfer_signature: bridged_chain_account_signature(), - }), - )); - } - - fn receive_test_swap_confirmation(success: bool) { - Pallet::::on_messages_delivered( - &OutboundMessageLaneId::get(), - &DeliveredMessages::new(MESSAGE_NONCE, success), - ); - } - - #[test] - fn create_swap_fails_if_origin_is_incorrect() { - run_test(|| { - assert_noop!( - Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1), - test_swap(), - Box::new(test_swap_creation()), - ), - Error::::MismatchedSwapSourceOrigin - ); - }); - } - - #[test] - fn create_swap_fails_if_this_chain_balance_is_below_existential_deposit() { - run_test(|| { - let mut swap = test_swap(); - swap.source_balance_at_this_chain = ExistentialDeposit::get() - 1; - assert_noop!( - Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - swap, - Box::new(test_swap_creation()), - ), - Error::::TooLowBalanceOnThisChain - ); - }); - } - - #[test] - fn create_swap_fails_if_currency_transfer_to_swap_account_fails() { - run_test(|| { - let mut swap = test_swap(); - swap.source_balance_at_this_chain = THIS_CHAIN_ACCOUNT_BALANCE + 1; - assert_noop!( - Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - swap, - Box::new(test_swap_creation()), - ), - Error::::FailedToTransferToSwapAccount - ); - }); - } - - #[test] - fn create_swap_fails_if_send_message_fails() { - run_test(|| { - let mut transfer = test_transfer(); - transfer[0] = BAD_TRANSFER_CALL; - let mut swap_creation = test_swap_creation(); - swap_creation.bridged_currency_transfer = transfer; - assert_noop!( - Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(swap_creation), - ), - Error::::FailedToSendTransferMessage - ); - }); - } - - #[test] - fn create_swap_fails_if_swap_is_active() { - run_test(|| { - assert_ok!(Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(test_swap_creation()), - )); - - assert_noop!( - Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(test_swap_creation()), - ), - Error::::SwapAlreadyStarted - ); - }); - } - - #[test] - fn create_swap_fails_if_trying_to_start_swap_after_lock_period_is_finished() { - run_test(|| { - frame_system::Pallet::::set_block_number(CAN_START_BLOCK_NUMBER + 1); - assert_noop!( - Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(test_swap_creation()), - ), - Error::::SwapPeriodIsFinished - ); - }); - } - - #[test] - fn create_swap_succeeds_if_trying_to_start_swap_at_lock_period_end() { - run_test(|| { - frame_system::Pallet::::set_block_number(CAN_START_BLOCK_NUMBER); - assert_ok!(Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(test_swap_creation()), - )); - }); - } - - #[test] - fn create_swap_succeeds() { - run_test(|| { - frame_system::Pallet::::set_block_number(1); - frame_system::Pallet::::reset_events(); - - assert_ok!(Pallet::::create_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap(), - Box::new(test_swap_creation()), - )); - - let swap_hash = test_swap_hash(); - assert_eq!(PendingSwaps::::get(swap_hash), Some(TokenSwapState::Started)); - assert_eq!(PendingMessages::::get(MESSAGE_NONCE), Some(swap_hash)); - assert_eq!( - pallet_balances::Pallet::::free_balance(&swap_account_id::< - TestRuntime, - (), - >(&test_swap())), - test_swap().source_balance_at_this_chain + SWAP_DELIVERY_AND_DISPATCH_FEE, - ); - assert!( - frame_system::Pallet::::events().iter().any(|e| e.event == - crate::mock::Event::TokenSwap(crate::Event::SwapStarted( - swap_hash, - MESSAGE_NONCE, - ))), - "Missing SwapStarted event: {:?}", - frame_system::Pallet::::events(), - ); - }); - } - - #[test] - fn claim_swap_fails_if_origin_is_incorrect() { - run_test(|| { - assert_noop!( - Pallet::::claim_swap( - mock::Origin::signed( - 1 + target_account_at_this_chain::(&test_swap()) - ), - test_swap(), - ), - Error::::InvalidClaimant - ); - }); - } - - #[test] - fn claim_swap_fails_if_swap_is_pending() { - run_test(|| { - PendingSwaps::::insert(test_swap_hash(), TokenSwapState::Started); - - assert_noop!( - Pallet::::claim_swap( - mock::Origin::signed(target_account_at_this_chain::( - &test_swap() - )), - test_swap(), - ), - Error::::SwapIsPending - ); - }); - } - - #[test] - fn claim_swap_fails_if_swap_is_failed() { - run_test(|| { - PendingSwaps::::insert(test_swap_hash(), TokenSwapState::Failed); - - assert_noop!( - Pallet::::claim_swap( - mock::Origin::signed(target_account_at_this_chain::( - &test_swap() - )), - test_swap(), - ), - Error::::SwapIsFailed - ); - }); - } - - #[test] - fn claim_swap_fails_if_swap_is_inactive() { - run_test(|| { - assert_noop!( - Pallet::::claim_swap( - mock::Origin::signed(target_account_at_this_chain::( - &test_swap() - )), - test_swap(), - ), - Error::::SwapIsInactive - ); - }); - } - - #[test] - fn claim_swap_fails_if_currency_transfer_from_swap_account_fails() { - run_test(|| { - frame_system::Pallet::::set_block_number(CAN_CLAIM_BLOCK_NUMBER); - PendingSwaps::::insert(test_swap_hash(), TokenSwapState::Confirmed); - - assert_noop!( - Pallet::::claim_swap( - mock::Origin::signed(target_account_at_this_chain::( - &test_swap() - )), - test_swap(), - ), - Error::::FailedToTransferFromSwapAccount - ); - }); - } - - #[test] - fn claim_swap_fails_before_lock_period_is_completed() { - run_test(|| { - start_test_swap(); - receive_test_swap_confirmation(true); - - frame_system::Pallet::::set_block_number(CAN_CLAIM_BLOCK_NUMBER - 1); - - assert_noop!( - Pallet::::claim_swap( - mock::Origin::signed(target_account_at_this_chain::( - &test_swap() - )), - test_swap(), - ), - Error::::SwapIsTemporaryLocked - ); - }); - } - - #[test] - fn claim_swap_succeeds() { - run_test(|| { - start_test_swap(); - receive_test_swap_confirmation(true); - - frame_system::Pallet::::set_block_number(CAN_CLAIM_BLOCK_NUMBER); - frame_system::Pallet::::reset_events(); - - assert_ok!(Pallet::::claim_swap( - mock::Origin::signed(target_account_at_this_chain::(&test_swap())), - test_swap(), - )); - - let swap_hash = test_swap_hash(); - assert_eq!(PendingSwaps::::get(swap_hash), None); - assert_eq!( - pallet_balances::Pallet::::free_balance(&swap_account_id::< - TestRuntime, - (), - >(&test_swap())), - 0, - ); - assert_eq!( - pallet_balances::Pallet::::free_balance( - &target_account_at_this_chain::(&test_swap()), - ), - test_swap().source_balance_at_this_chain, - ); - assert!( - frame_system::Pallet::::events().iter().any(|e| e.event == - crate::mock::Event::TokenSwap(crate::Event::SwapClaimed(swap_hash,))), - "Missing SwapClaimed event: {:?}", - frame_system::Pallet::::events(), - ); - }); - } - - #[test] - fn cancel_swap_fails_if_origin_is_incorrect() { - run_test(|| { - start_test_swap(); - receive_test_swap_confirmation(false); - - assert_noop!( - Pallet::::cancel_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1), - test_swap() - ), - Error::::MismatchedSwapSourceOrigin - ); - }); - } - - #[test] - fn cancel_swap_fails_if_swap_is_pending() { - run_test(|| { - start_test_swap(); - - assert_noop!( - Pallet::::cancel_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap() - ), - Error::::SwapIsPending - ); - }); - } - - #[test] - fn cancel_swap_fails_if_swap_is_confirmed() { - run_test(|| { - start_test_swap(); - receive_test_swap_confirmation(true); - - assert_noop!( - Pallet::::cancel_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap() - ), - Error::::SwapIsConfirmed - ); - }); - } - - #[test] - fn cancel_swap_fails_if_swap_is_inactive() { - run_test(|| { - assert_noop!( - Pallet::::cancel_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap() - ), - Error::::SwapIsInactive - ); - }); - } - - #[test] - fn cancel_swap_fails_if_currency_transfer_from_swap_account_fails() { - run_test(|| { - start_test_swap(); - receive_test_swap_confirmation(false); - let _ = pallet_balances::Pallet::::slash( - &swap_account_id::(&test_swap()), - test_swap().source_balance_at_this_chain, - ); - - assert_noop!( - Pallet::::cancel_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap() - ), - Error::::FailedToTransferFromSwapAccount - ); - }); - } - - #[test] - fn cancel_swap_succeeds() { - run_test(|| { - start_test_swap(); - receive_test_swap_confirmation(false); - - frame_system::Pallet::::set_block_number(1); - frame_system::Pallet::::reset_events(); - - assert_ok!(Pallet::::cancel_swap( - mock::Origin::signed(THIS_CHAIN_ACCOUNT), - test_swap() - )); - - let swap_hash = test_swap_hash(); - assert_eq!(PendingSwaps::::get(swap_hash), None); - assert_eq!( - pallet_balances::Pallet::::free_balance(&swap_account_id::< - TestRuntime, - (), - >(&test_swap())), - 0, - ); - assert_eq!( - pallet_balances::Pallet::::free_balance(&THIS_CHAIN_ACCOUNT), - THIS_CHAIN_ACCOUNT_BALANCE - SWAP_DELIVERY_AND_DISPATCH_FEE, - ); - assert!( - frame_system::Pallet::::events().iter().any(|e| e.event == - crate::mock::Event::TokenSwap(crate::Event::SwapCanceled(swap_hash,))), - "Missing SwapCanceled event: {:?}", - frame_system::Pallet::::events(), - ); - }); - } - - #[test] - fn messages_delivery_confirmations_are_accepted() { - run_test(|| { - start_test_swap(); - assert_eq!( - PendingMessages::::get(MESSAGE_NONCE), - Some(test_swap_hash()) - ); - assert_eq!( - PendingSwaps::::get(test_swap_hash()), - Some(TokenSwapState::Started) - ); - - // when unrelated messages are delivered - let mut messages = DeliveredMessages::new(MESSAGE_NONCE - 2, true); - messages.note_dispatched_message(false); - Pallet::::on_messages_delivered( - &OutboundMessageLaneId::get(), - &messages, - ); - assert_eq!( - PendingMessages::::get(MESSAGE_NONCE), - Some(test_swap_hash()) - ); - assert_eq!( - PendingSwaps::::get(test_swap_hash()), - Some(TokenSwapState::Started) - ); - - // when message we're interested in is accompanied by a bunch of other messages - let mut messages = DeliveredMessages::new(MESSAGE_NONCE - 1, false); - messages.note_dispatched_message(true); - messages.note_dispatched_message(false); - Pallet::::on_messages_delivered( - &OutboundMessageLaneId::get(), - &messages, - ); - assert_eq!(PendingMessages::::get(MESSAGE_NONCE), None); - assert_eq!( - PendingSwaps::::get(test_swap_hash()), - Some(TokenSwapState::Confirmed) - ); - }); - } - - #[test] - fn storage_keys_computed_properly() { - assert_eq!( - PendingSwaps::::storage_map_final_key(test_swap_hash()), - bp_token_swap::storage_keys::pending_swaps_key("TokenSwap", test_swap_hash()).0, - ); - } -} diff --git a/modules/token-swap/src/mock.rs b/modules/token-swap/src/mock.rs deleted file mode 100644 index ece7b16acc..0000000000 --- a/modules/token-swap/src/mock.rs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use crate as pallet_bridge_token_swap; -use crate::MessagePayloadOf; - -use bp_messages::{ - source_chain::{MessagesBridge, SendMessageArtifacts}, - LaneId, MessageNonce, -}; -use bp_runtime::ChainId; -use frame_support::weights::Weight; -use sp_core::H256; -use sp_runtime::{ - testing::Header as SubstrateHeader, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, -}; - -pub type AccountId = u64; -pub type Balance = u64; -pub type Block = frame_system::mocking::MockBlock; -pub type BridgedAccountId = u64; -pub type BridgedAccountPublic = sp_runtime::testing::UintAuthorityId; -pub type BridgedAccountSignature = sp_runtime::testing::TestSignature; -pub type BridgedBalance = u64; -pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - -pub const OK_TRANSFER_CALL: u8 = 1; -pub const BAD_TRANSFER_CALL: u8 = 2; -pub const MESSAGE_NONCE: MessageNonce = 3; - -pub const THIS_CHAIN_ACCOUNT: AccountId = 1; -pub const THIS_CHAIN_ACCOUNT_BALANCE: Balance = 100_000; - -pub const SWAP_DELIVERY_AND_DISPATCH_FEE: Balance = 1; - -frame_support::construct_runtime! { - pub enum TestRuntime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Event}, - TokenSwap: pallet_bridge_token_swap::{Pallet, Call, Event, Origin}, - } -} - -frame_support::parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); -} - -impl frame_system::Config for TestRuntime { - type Origin = Origin; - type Index = u64; - type Call = Call; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = SubstrateHeader; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -frame_support::parameter_types! { - pub const ExistentialDeposit: u64 = 10; - pub const MaxReserves: u32 = 50; -} - -impl pallet_balances::Config for TestRuntime { - type MaxLocks = (); - type Balance = Balance; - type DustRemoval = (); - type Event = Event; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = frame_system::Pallet; - type WeightInfo = (); - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; -} - -frame_support::parameter_types! { - pub const BridgedChainId: ChainId = *b"inst"; - pub const OutboundMessageLaneId: LaneId = *b"lane"; -} - -impl pallet_bridge_token_swap::Config for TestRuntime { - type Event = Event; - type WeightInfo = (); - - type BridgedChainId = BridgedChainId; - type OutboundMessageLaneId = OutboundMessageLaneId; - type MessagesBridge = TestMessagesBridge; - - type ThisCurrency = pallet_balances::Pallet; - type FromSwapToThisAccountIdConverter = TestAccountConverter; - - type BridgedChain = BridgedChain; - type FromBridgedToThisAccountIdConverter = TestAccountConverter; -} - -pub struct BridgedChain; - -impl bp_runtime::Chain for BridgedChain { - type BlockNumber = u64; - type Hash = H256; - type Hasher = BlakeTwo256; - type Header = sp_runtime::generic::Header; - - type AccountId = BridgedAccountId; - type Balance = BridgedBalance; - type Index = u64; - type Signature = BridgedAccountSignature; - - fn max_extrinsic_size() -> u32 { - unreachable!() - } - fn max_extrinsic_weight() -> Weight { - unreachable!() - } -} - -pub struct TestMessagesBridge; - -impl MessagesBridge> - for TestMessagesBridge -{ - type Error = (); - - fn send_message( - sender: Origin, - lane: LaneId, - message: MessagePayloadOf, - delivery_and_dispatch_fee: Balance, - ) -> Result { - assert_eq!(lane, OutboundMessageLaneId::get()); - assert_eq!(delivery_and_dispatch_fee, SWAP_DELIVERY_AND_DISPATCH_FEE); - match sender.caller { - OriginCaller::TokenSwap(_) => (), - _ => panic!("unexpected origin"), - } - match message.call[0] { - OK_TRANSFER_CALL => Ok(SendMessageArtifacts { nonce: MESSAGE_NONCE, weight: 0 }), - BAD_TRANSFER_CALL => Err(()), - _ => unreachable!(), - } - } -} - -pub struct TestAccountConverter; - -impl sp_runtime::traits::Convert for TestAccountConverter { - fn convert(hash: H256) -> AccountId { - hash.to_low_u64_ne() - } -} - -/// Run pallet test. -pub fn run_test(test: impl FnOnce() -> T) -> T { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![(THIS_CHAIN_ACCOUNT, THIS_CHAIN_ACCOUNT_BALANCE)], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(test) -} diff --git a/modules/token-swap/src/weights_ext.rs b/modules/token-swap/src/weights_ext.rs deleted file mode 100644 index 2d27c76cbe..0000000000 --- a/modules/token-swap/src/weights_ext.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Weight-related utilities. - -use crate::weights::WeightInfo; - -use bp_runtime::Size; -use frame_support::weights::{RuntimeDbWeight, Weight}; - -/// Extended weight info. -pub trait WeightInfoExt: WeightInfo { - // Functions that are directly mapped to extrinsics weights. - - /// Weight of message send extrinsic. - fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight; -} - -impl WeightInfoExt for () { - fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight { - <() as pallet_bridge_messages::WeightInfoExt>::send_message_weight(message, db_weight) - } -} - -impl WeightInfoExt for crate::weights::MillauWeight { - fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight { - <() as pallet_bridge_messages::WeightInfoExt>::send_message_weight(message, db_weight) - } -} diff --git a/primitives/chain-kusama/src/lib.rs b/primitives/chain-kusama/src/lib.rs index a0a5990ca0..0b218b2225 100644 --- a/primitives/chain-kusama/src/lib.rs +++ b/primitives/chain-kusama/src/lib.rs @@ -18,7 +18,9 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_messages::{LaneId, MessageDetails, MessageNonce}; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; use frame_support::weights::{ WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; @@ -27,6 +29,7 @@ use sp_std::prelude::*; use sp_version::RuntimeVersion; pub use bp_polkadot_core::*; +use bp_runtime::decl_bridge_runtime_apis; /// Kusama Chain pub type Kusama = PolkadotLike; @@ -61,13 +64,6 @@ impl WeightToFeePolynomial for WeightToFee { } } -// We use this to get the account on Kusama (target) which is derived from Polkadot's (source) -// account. -pub fn derive_account_from_polkadot_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::POLKADOT_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} - /// Per-byte fee for Kusama transactions. pub const TRANSACTION_BYTE_FEE: Balance = 10 * 1_000_000_000_000 / 30_000 / 1_000; @@ -95,54 +91,4 @@ pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = /// Name of the Polkadot fee multiplier parameter, stored in the Polkadot runtime. pub const POLKADOT_FEE_MULTIPLIER_PARAMETER_NAME: &str = "PolkadotFeeMultiplier"; -/// Name of the `KusamaFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized"; - -/// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToKusamaOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToKusamaOutboundLaneApi::message_details` runtime method. -pub const TO_KUSAMA_MESSAGE_DETAILS_METHOD: &str = "ToKusamaOutboundLaneApi_message_details"; - -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Kusama headers. - /// - /// This API is implemented by runtimes that are bridging with the Kusama chain, not the - /// Kusama runtime itself. - pub trait KusamaFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } - - /// Outbound message lane API for messages that are sent to Kusama chain. - /// - /// This API is implemented by runtimes that are sending messages to Kusama chain, not the - /// Kusama runtime itself. - pub trait ToKusamaOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Kusama from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - kusama_to_this_conversion_rate: Option, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - } -} +decl_bridge_runtime_apis!(kusama); diff --git a/primitives/chain-millau/Cargo.toml b/primitives/chain-millau/Cargo.toml index 0aaeb5b6bf..4cd8b30f7f 100644 --- a/primitives/chain-millau/Cargo.toml +++ b/primitives/chain-millau/Cargo.toml @@ -17,7 +17,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } impl-codec = { version = "0.6", default-features = false } impl-serde = { version = "0.3.1", optional = true } parity-util-mem = { version = "0.11", default-features = false, features = ["primitive-types"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Substrate Based Dependencies diff --git a/primitives/chain-millau/src/lib.rs b/primitives/chain-millau/src/lib.rs index ff8d538595..2f5b12eed0 100644 --- a/primitives/chain-millau/src/lib.rs +++ b/primitives/chain-millau/src/lib.rs @@ -20,8 +20,10 @@ mod millau_hash; -use bp_messages::{LaneId, MessageDetails, MessageNonce}; -use bp_runtime::Chain; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use bp_runtime::{decl_bridge_runtime_apis, Chain}; use frame_support::{ weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, Weight}, Parameter, RuntimeDebug, @@ -30,7 +32,7 @@ use frame_system::limits; use scale_info::TypeInfo; use sp_core::{storage::StateVersion, Hasher as HasherT}; use sp_runtime::{ - traits::{Convert, IdentifyAccount, Verify}, + traits::{IdentifyAccount, Verify}, FixedU128, MultiSignature, MultiSigner, Perbill, }; use sp_std::prelude::*; @@ -51,9 +53,6 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Can be computed by subtracting encoded call size from raw transaction size. pub const TX_EXTRA_BYTES: u32 = 103; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// Maximum weight of single Millau block. /// /// This represents 0.5 seconds of compute assuming a target block time of six seconds. @@ -219,28 +218,6 @@ impl sp_runtime::traits::Hash for BlakeTwoAndKeccak256 { } } -/// Convert a 256-bit hash into an AccountId. -pub struct AccountIdConverter; - -impl sp_runtime::traits::Convert for AccountIdConverter { - fn convert(hash: sp_core::H256) -> AccountId { - hash.to_fixed_bytes().into() - } -} - -/// We use this to get the account on Millau (target) which is derived from Rialto's (source) -/// account. We do this so we can fund the derived account on Millau at Genesis to it can pay -/// transaction fees. -/// -/// The reason we can use the same `AccountId` type for both chains is because they share the same -/// development seed phrase. -/// -/// Note that this should only be used for testing. -pub fn derive_account_from_rialto_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::RIALTO_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} - frame_support::parameter_types! { pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio(2 * 1024 * 1024, NORMAL_DISPATCH_RATIO); @@ -265,77 +242,16 @@ frame_support::parameter_types! { pub const WITH_MILLAU_GRANDPA_PALLET_NAME: &str = "BridgeMillauGrandpa"; /// Name of the With-Millau messages pallet instance that is deployed at bridged chains. pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages"; +/// Name of the transaction payment pallet at the Millau runtime. +pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment"; /// Name of the Rialto->Millau (actually DOT->KSM) conversion rate stored in the Millau runtime. pub const RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = "RialtoToMillauConversionRate"; - -/// Name of the With-Rialto token swap pallet instance in the Millau runtime. -pub const WITH_RIALTO_TOKEN_SWAP_PALLET_NAME: &str = "BridgeRialtoTokenSwap"; - -/// Name of the `MillauFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_MILLAU_HEADER_METHOD: &str = "MillauFinalityApi_best_finalized"; - -/// Name of the `ToMillauOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToMillauOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToMillauOutboundLaneApi::message_details` runtime method. -pub const TO_MILLAU_MESSAGE_DETAILS_METHOD: &str = "ToMillauOutboundLaneApi_message_details"; - -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Millau headers. - /// - /// This API is implemented by runtimes that are bridging with the Millau chain, not the - /// Millau runtime itself. - pub trait MillauFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } - - /// Outbound message lane API for messages that are sent to Millau chain. - /// - /// This API is implemented by runtimes that are sending messages to Millau chain, not the - /// Millau runtime itself. - pub trait ToMillauOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Millau from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - millau_to_this_conversion_rate: Option, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_account_size_does_not_overflow_constant() { - assert!( - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize >= AccountId::from([0u8; 32]).encode().len(), - "Actual maximal size of encoded AccountId ({}) overflows expected ({})", - AccountId::from([0u8; 32]).encode().len(), - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } -} +/// Name of the RialtoParachain->Millau (actually DOT->KSM) conversion rate stored in the Millau +/// runtime. +pub const RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = + "RialtoParachainToMillauConversionRate"; +/// Name of the RialtoParachain fee multiplier parameter, stored in the Millau runtime. +pub const RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME: &str = "RialtoParachainFeeMultiplier"; + +decl_bridge_runtime_apis!(millau); diff --git a/primitives/chain-polkadot/src/lib.rs b/primitives/chain-polkadot/src/lib.rs index d95e29c8b0..6f584f5526 100644 --- a/primitives/chain-polkadot/src/lib.rs +++ b/primitives/chain-polkadot/src/lib.rs @@ -18,7 +18,9 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_messages::{LaneId, MessageDetails, MessageNonce}; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; use frame_support::weights::{ WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; @@ -27,6 +29,7 @@ use sp_std::prelude::*; use sp_version::RuntimeVersion; pub use bp_polkadot_core::*; +use bp_runtime::decl_bridge_runtime_apis; /// Polkadot Chain pub type Polkadot = PolkadotLike; @@ -61,13 +64,6 @@ impl WeightToFeePolynomial for WeightToFee { } } -// We use this to get the account on Polkadot (target) which is derived from Kusama's (source) -// account. -pub fn derive_account_from_kusama_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::KUSAMA_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} - /// Per-byte fee for Polkadot transactions. pub const TRANSACTION_BYTE_FEE: Balance = 10 * 10_000_000_000 / 100 / 1_000; @@ -95,54 +91,4 @@ pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = /// Name of the Kusama fee multiplier parameter, stored in the Polkadot runtime. pub const KUSAMA_FEE_MULTIPLIER_PARAMETER_NAME: &str = "KusamaFeeMultiplier"; -/// Name of the `PolkadotFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized"; - -/// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToPolkadotOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToPolkadotOutboundLaneApi::message_details` runtime method. -pub const TO_POLKADOT_MESSAGE_DETAILS_METHOD: &str = "ToPolkadotOutboundLaneApi_message_details"; - -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Polkadot headers. - /// - /// This API is implemented by runtimes that are bridging with the Polkadot chain, not the - /// Polkadot runtime itself. - pub trait PolkadotFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } - - /// Outbound message lane API for messages that are sent to Polkadot chain. - /// - /// This API is implemented by runtimes that are sending messages to Polkadot chain, not the - /// Polkadot runtime itself. - pub trait ToPolkadotOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Polkadot from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - polkadot_to_this_conversion_rate: Option, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - } -} +decl_bridge_runtime_apis!(polkadot); diff --git a/primitives/chain-rialto-parachain/src/lib.rs b/primitives/chain-rialto-parachain/src/lib.rs index f3f449c7af..8afbf87725 100644 --- a/primitives/chain-rialto-parachain/src/lib.rs +++ b/primitives/chain-rialto-parachain/src/lib.rs @@ -18,19 +18,39 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_runtime::Chain; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use bp_runtime::{decl_bridge_runtime_apis, Chain}; use frame_support::{ weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, Weight}, - RuntimeDebug, + Parameter, RuntimeDebug, }; use frame_system::limits; use sp_core::Hasher as HasherT; use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, Verify}, - MultiSignature, MultiSigner, Perbill, + FixedU128, MultiSignature, MultiSigner, Perbill, }; +use sp_std::vec::Vec; + +/// Identifier of RialtoParachain in the Rialto relay chain. +/// +/// This identifier is not something that is declared either by Rialto or RialtoParachain. This +/// is an identifier of registration. So in theory it may be changed. But since bridge is going +/// to be deployed after parachain registration AND since parachain de-registration is highly +/// likely impossible, it is fine to declare this constant here. +pub const RIALTO_PARACHAIN_ID: u32 = 2000; + +/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at +/// RialtoParachain chain. This mostly depends on number of entries (and their density) in the +/// storage trie. Some reserve is reserved to account future chain growth. +pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; + +/// Can be computed by subtracting encoded call size from raw transaction size. +pub const TX_EXTRA_BYTES: u32 = 104; -/// Maximal weight of single Rialto parachain block. +/// Maximal weight of single RialtoParachain block. /// /// This represents two seconds of compute assuming a target block time of six seconds. pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; @@ -42,6 +62,44 @@ pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// Represents the portion of a block that will be used by Normal extrinsics. pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// Maximal number of unrewarded relayer entries in Rialto confirmation transaction. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// Maximal number of unconfirmed messages in Rialto confirmation transaction. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// Weight of single regular message delivery transaction on RialtoParachain chain. +/// +/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call +/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH` +/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be +/// rounded up to account possible future runtime upgrades. +pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = 1_500_000_000; + +/// Increase of delivery transaction weight on RialtoParachain chain with every additional message +/// byte. +/// +/// This value is a result of +/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then +/// must be rounded up to account possible future runtime upgrades. +pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = 25_000; + +/// Maximal weight of single message delivery confirmation transaction on RialtoParachain chain. +/// +/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof` +/// weight formula computation for the case when single message is confirmed. The result then must +/// be rounded up to account possible future runtime upgrades. +pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000; + +/// Weight of pay-dispatch-fee operation for inbound messages at Rialto chain. +/// +/// This value corresponds to the result of +/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your +/// chain. Don't put too much reserve there, because it is used to **decrease** +/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery +/// transactions cheaper. +pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000; + /// Block number type used in Rialto. pub type BlockNumber = u32; @@ -122,3 +180,17 @@ frame_support::parameter_types! { .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) .build_or_panic(); } + +/// Name of the With-Rialto-Parachain messages pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME: &str = "BridgeRialtoParachainMessages"; +/// Name of the transaction payment pallet at the Rialto parachain runtime. +pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment"; + +/// Name of the Millau->RialtoParachain (actually KSM->DOT) conversion rate stored in the Rialto +/// parachain runtime. +pub const MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME: &str = + "MillauToRialtoParachainConversionRate"; +/// Name of the Millau fee multiplier parameter, stored in the Rialto parachain runtime. +pub const MILLAU_FEE_MULTIPLIER_PARAMETER_NAME: &str = "MillauFeeMultiplier"; + +decl_bridge_runtime_apis!(rialto_parachain); diff --git a/primitives/chain-rialto/src/lib.rs b/primitives/chain-rialto/src/lib.rs index 4bf20489bc..1b8d19249e 100644 --- a/primitives/chain-rialto/src/lib.rs +++ b/primitives/chain-rialto/src/lib.rs @@ -18,8 +18,10 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_messages::{LaneId, MessageDetails, MessageNonce}; -use bp_runtime::Chain; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use bp_runtime::{decl_bridge_runtime_apis, Chain}; use frame_support::{ weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, Weight}, Parameter, RuntimeDebug, @@ -27,7 +29,7 @@ use frame_support::{ use frame_system::limits; use sp_core::Hasher as HasherT; use sp_runtime::{ - traits::{BlakeTwo256, Convert, IdentifyAccount, Verify}, + traits::{BlakeTwo256, IdentifyAccount, Verify}, FixedU128, MultiSignature, MultiSigner, Perbill, }; use sp_std::prelude::*; @@ -42,9 +44,6 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Can be computed by subtracting encoded call size from raw transaction size. pub const TX_EXTRA_BYTES: u32 = 104; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// Maximal weight of single Rialto block. /// /// This represents two seconds of compute assuming a target block time of six seconds. @@ -182,28 +181,6 @@ impl Chain for Rialto { } } -/// Convert a 256-bit hash into an AccountId. -pub struct AccountIdConverter; - -impl Convert for AccountIdConverter { - fn convert(hash: sp_core::H256) -> AccountId { - hash.to_fixed_bytes().into() - } -} - -// We use this to get the account on Rialto (target) which is derived from Millau's (source) -// account. We do this so we can fund the derived account on Rialto at Genesis to it can pay -// transaction fees. -// -// The reason we can use the same `AccountId` type for both chains is because they share the same -// development seed phrase. -// -// Note that this should only be used for testing. -pub fn derive_account_from_millau_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::MILLAU_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} - frame_support::parameter_types! { pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); @@ -228,6 +205,8 @@ frame_support::parameter_types! { pub const WITH_RIALTO_GRANDPA_PALLET_NAME: &str = "BridgeRialtoGrandpa"; /// Name of the With-Rialto messages pallet instance that is deployed at bridged chains. pub const WITH_RIALTO_MESSAGES_PALLET_NAME: &str = "BridgeRialtoMessages"; +/// Name of the With-Rialto parachains bridge pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeRialtoParachains"; /// Name of the Millau->Rialto (actually KSM->DOT) conversion rate stored in the Rialto runtime. pub const MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME: &str = "MillauToRialtoConversionRate"; @@ -238,70 +217,4 @@ pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar"; /// Name of the parachains pallet in the Rialto runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; -/// Name of the `RialtoFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_RIALTO_HEADER_METHOD: &str = "RialtoFinalityApi_best_finalized"; - -/// Name of the `ToRialtoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToRialtoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToRialtoOutboundLaneApi::message_details` runtime method. -pub const TO_RIALTO_MESSAGE_DETAILS_METHOD: &str = "ToRialtoOutboundLaneApi_message_details"; - -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Rialto headers. - /// - /// This API is implemented by runtimes that are bridging with the Rialto chain, not the - /// Millau runtime itself. - pub trait RialtoFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } - - /// Outbound message lane API for messages that are sent to Rialto chain. - /// - /// This API is implemented by runtimes that are sending messages to Rialto chain, not the - /// Rialto runtime itself. - pub trait ToRialtoOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Rialto from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - rialto_to_this_conversion_rate: Option, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - } -} - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_account_size_does_not_overflow_constant() { - assert!( - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize >= AccountId::from([0u8; 32]).encode().len(), - "Actual maximal size of encoded AccountId ({}) overflows expected ({})", - AccountId::from([0u8; 32]).encode().len(), - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } -} +decl_bridge_runtime_apis!(rialto); diff --git a/primitives/chain-rococo/Cargo.toml b/primitives/chain-rococo/Cargo.toml index 814cd09bf1..fe6b07eeb7 100644 --- a/primitives/chain-rococo/Cargo.toml +++ b/primitives/chain-rococo/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } smallvec = "1.7" # Bridge Dependencies @@ -29,7 +29,7 @@ std = [ "bp-polkadot-core/std", "bp-runtime/std", "frame-support/std", - "parity-scale-codec/std", + "codec/std", "sp-api/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/chain-rococo/src/lib.rs b/primitives/chain-rococo/src/lib.rs index 127e75d5f8..aa1d40ce92 100644 --- a/primitives/chain-rococo/src/lib.rs +++ b/primitives/chain-rococo/src/lib.rs @@ -18,7 +18,9 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_messages::{LaneId, MessageDetails, MessageNonce}; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; use frame_support::weights::{ Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; @@ -27,6 +29,7 @@ use sp_std::prelude::*; use sp_version::RuntimeVersion; pub use bp_polkadot_core::*; +use bp_runtime::decl_bridge_runtime_apis; /// Rococo Chain pub type Rococo = PolkadotLike; @@ -43,7 +46,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: sp_version::create_runtime_str!("rococo"), impl_name: sp_version::create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 9180, + spec_version: 9200, impl_version: 0, apis: sp_version::create_apis_vec![[]], transaction_version: 0, @@ -67,28 +70,11 @@ impl WeightToFeePolynomial for WeightToFee { } } -// We use this to get the account on Rococo (target) which is derived from Wococo's (source) -// account. -pub fn derive_account_from_wococo_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::WOCOCO_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} - /// Name of the With-Rococo GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_ROCOCO_GRANDPA_PALLET_NAME: &str = "BridgeRococoGrandpa"; /// Name of the With-Rococo messages pallet instance that is deployed at bridged chains. pub const WITH_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages"; -/// Name of the `RococoFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized"; - -/// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToRococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToRococoOutboundLaneApi::message_details` runtime method. -pub const TO_ROCOCO_MESSAGE_DETAILS_METHOD: &str = "ToRococoOutboundLaneApi_message_details"; - /// Existential deposit on Rococo. pub const EXISTENTIAL_DEPOSIT: Balance = 1_000_000_000_000 / 100; @@ -101,44 +87,4 @@ pub const EXISTENTIAL_DEPOSIT: Balance = 1_000_000_000_000 / 100; /// transactions cheaper. pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000; -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Rococo headers. - /// - /// This API is implemented by runtimes that are bridging with the Rococo chain, not the - /// Rococo runtime itself. - pub trait RococoFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } - - /// Outbound message lane API for messages that are sent to Rococo chain. - /// - /// This API is implemented by runtimes that are sending messages to Rococo chain, not the - /// Rococo runtime itself. - pub trait ToRococoOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Rococo from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - rococo_to_this_conversion_rate: Option, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - } -} +decl_bridge_runtime_apis!(rococo); diff --git a/primitives/chain-westend/Cargo.toml b/primitives/chain-westend/Cargo.toml index ee6e2b9be9..f37aa3b0e3 100644 --- a/primitives/chain-westend/Cargo.toml +++ b/primitives/chain-westend/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } smallvec = "1.7" # Bridge Dependencies @@ -32,7 +32,7 @@ std = [ "bp-polkadot-core/std", "bp-runtime/std", "frame-support/std", - "parity-scale-codec/std", + "codec/std", "scale-info/std", "sp-api/std", "sp-runtime/std", diff --git a/primitives/chain-westend/src/lib.rs b/primitives/chain-westend/src/lib.rs index c7ebe4b00f..1e023295a8 100644 --- a/primitives/chain-westend/src/lib.rs +++ b/primitives/chain-westend/src/lib.rs @@ -26,6 +26,7 @@ use sp_std::prelude::*; use sp_version::RuntimeVersion; pub use bp_polkadot_core::*; +use bp_runtime::decl_bridge_finality_runtime_apis; /// Westend Chain pub type Westend = PolkadotLike; @@ -63,9 +64,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { /// Westend Runtime `Call` enum. /// /// We are not currently submitting any Westend transactions => it is empty. -#[derive( - parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone, TypeInfo, -)] +#[derive(codec::Encode, codec::Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum Call {} impl sp_runtime::traits::Dispatchable for Call { @@ -79,18 +78,13 @@ impl sp_runtime::traits::Dispatchable for Call { } } -// We use this to get the account on Westend (target) which is derived from Rococo's (source) -// account. -pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::ROCOCO_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} +/// Name of the parachains pallet at the Westend runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; /// Name of the With-Westend GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_WESTEND_GRANDPA_PALLET_NAME: &str = "BridgeWestendGrandpa"; - -/// Name of the `WestendFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_finalized"; +/// Name of the With-Westend parachains bridge pallet instance that is deployed at bridged chains. +pub const WITH_WESTEND_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeWestendParachains"; /// The target length of a session (how often authorities change) on Westend measured in of number /// of blocks. @@ -99,13 +93,9 @@ pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_ /// conditions. pub const SESSION_LENGTH: BlockNumber = 10 * time_units::MINUTES; -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Westend headers. - /// - /// This API is implemented by runtimes that are bridging with the Westend chain, not the - /// Westend runtime itself. - pub trait WestendFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } -} +/// Identifier of Westmint parachain at the Westend relay chain. +pub const WESTMINT_PARACHAIN_ID: u32 = 2000; + +decl_bridge_finality_runtime_apis!(westend); + +decl_bridge_finality_runtime_apis!(westmint); diff --git a/primitives/chain-wococo/Cargo.toml b/primitives/chain-wococo/Cargo.toml index 633cdd15c1..92e7c9e80e 100644 --- a/primitives/chain-wococo/Cargo.toml +++ b/primitives/chain-wococo/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } # Bridge Dependencies bp-messages = { path = "../messages", default-features = false } @@ -27,7 +27,7 @@ std = [ "bp-polkadot-core/std", "bp-runtime/std", "bp-rococo/std", - "parity-scale-codec/std", + "codec/std", "sp-api/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/chain-wococo/src/lib.rs b/primitives/chain-wococo/src/lib.rs index f39543114c..c1626b0dc6 100644 --- a/primitives/chain-wococo/src/lib.rs +++ b/primitives/chain-wococo/src/lib.rs @@ -18,13 +18,16 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_messages::{LaneId, MessageDetails, MessageNonce}; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; use sp_runtime::FixedU128; use sp_std::prelude::*; pub use bp_polkadot_core::*; // Rococo runtime = Wococo runtime pub use bp_rococo::{WeightToFee, EXISTENTIAL_DEPOSIT, PAY_INBOUND_DISPATCH_FEE_WEIGHT, VERSION}; +use bp_runtime::decl_bridge_runtime_apis; /// Wococo Chain pub type Wococo = PolkadotLike; @@ -36,66 +39,9 @@ pub type Wococo = PolkadotLike; /// conditions. pub const SESSION_LENGTH: BlockNumber = time_units::MINUTES; -// We use this to get the account on Wococo (target) which is derived from Rococo's (source) -// account. -pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount) -> AccountId { - let encoded_id = bp_runtime::derive_account_id(bp_runtime::ROCOCO_CHAIN_ID, id); - AccountIdConverter::convert(encoded_id) -} - /// Name of the With-Wococo GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_WOCOCO_GRANDPA_PALLET_NAME: &str = "BridgeWococoGrandpa"; /// Name of the With-Wococo messages pallet instance that is deployed at bridged chains. pub const WITH_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; -/// Name of the `WococoFinalityApi::best_finalized` runtime method. -pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_finalized"; - -/// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToWococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToWococoOutboundLaneApi::message_details` runtime method. -pub const TO_WOCOCO_MESSAGE_DETAILS_METHOD: &str = "ToWococoOutboundLaneApi_message_details"; - -sp_api::decl_runtime_apis! { - /// API for querying information about the finalized Wococo headers. - /// - /// This API is implemented by runtimes that are bridging with the Wococo chain, not the - /// Wococo runtime itself. - pub trait WococoFinalityApi { - /// Returns number and hash of the best finalized header known to the bridge module. - fn best_finalized() -> (BlockNumber, Hash); - } - - /// Outbound message lane API for messages that are sent to Wococo chain. - /// - /// This API is implemented by runtimes that are sending messages to Wococo chain, not the - /// Wococo runtime itself. - pub trait ToWococoOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Wococo from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - wococo_to_this_conversion_rate: Option, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - } -} +decl_bridge_runtime_apis!(wococo); diff --git a/primitives/header-chain/Cargo.toml b/primitives/header-chain/Cargo.toml index 7cd688d0d8..be87cce460 100644 --- a/primitives/header-chain/Cargo.toml +++ b/primitives/header-chain/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -finality-grandpa = { version = "0.15.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +finality-grandpa = { version = "0.16.0", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true } # Bridge dependencies @@ -25,7 +25,6 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [dev-dependencies] -assert_matches = "1.5" bp-test-utils = { path = "../test-utils" } hex = "0.4" hex-literal = "0.3" diff --git a/primitives/header-chain/src/justification.rs b/primitives/header-chain/src/justification.rs index 9f8e9662ea..dadd48a485 100644 --- a/primitives/header-chain/src/justification.rs +++ b/primitives/header-chain/src/justification.rs @@ -53,7 +53,7 @@ impl crate::FinalityProof for GrandpaJustification { } /// Justification verification error. -#[derive(RuntimeDebug, PartialEq)] +#[derive(Eq, RuntimeDebug, PartialEq)] pub enum Error { /// Failed to decode justification. JustificationDecode, @@ -113,7 +113,7 @@ where // check if authority has already voted in the same round. // // there's a lot of code in `validate_commit` and `import_precommit` functions inside - // `finality-grandpa` crate (mostly related to reporing equivocations). But the only thing + // `finality-grandpa` crate (mostly related to reporting equivocations). But the only thing // that we care about is that only first vote from the authority is accepted if !votes.insert(signed.id.clone()) { continue @@ -121,11 +121,11 @@ where // everything below this line can't just `continue`, because state is already altered - // all precommits must be for block higher than the target + // precommits aren't allowed for block lower than the target if signed.precommit.target_number < justification.commit.target_number { return Err(Error::PrecommitIsNotCommitDescendant) } - // all precommits must be for target block descendents + // all precommits must be descendants of target block chain = chain .ensure_descendant(&justification.commit.target_hash, &signed.precommit.target_hash)?; // since we know now that the precommit target is the descendant of the justification @@ -193,8 +193,8 @@ impl AncestryChain
{ AncestryChain { parents, unvisited } } - /// Returns `Err(_)` if `precommit_target` is a descendant of the `commit_target` block and - /// `Ok(_)` otherwise. + /// Returns `Ok(_)` if `precommit_target` is a descendant of the `commit_target` block and + /// `Err(_)` otherwise. pub fn ensure_descendant( mut self, commit_target: &Header::Hash, @@ -213,7 +213,7 @@ impl AncestryChain
{ // `Some(parent_hash)` means that the `current_hash` is in the `parents` // container `is_visited_before` means that it has been visited before in // some of previous calls => since we assume that previous call has finished - // with `true`, this also will be finished with `true` + // with `true`, this also will be finished with `true` return Ok(self) } diff --git a/primitives/header-chain/src/lib.rs b/primitives/header-chain/src/lib.rs index 28949f28de..8ac7972621 100644 --- a/primitives/header-chain/src/lib.rs +++ b/primitives/header-chain/src/lib.rs @@ -19,6 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use bp_runtime::BasicOperatingMode; use codec::{Codec, Decode, Encode, EncodeLike}; use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug}; use scale_info::TypeInfo; @@ -38,7 +39,7 @@ pub trait Parameter: Codec + EncodeLike + Clone + Eq + Debug + TypeInfo {} impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + Debug + TypeInfo {} /// A GRANDPA Authority List and ID. -#[derive(Default, Encode, Decode, RuntimeDebug, PartialEq, Clone, TypeInfo)] +#[derive(Default, Encode, Eq, Decode, RuntimeDebug, PartialEq, Clone, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct AuthoritySet { /// List of GRANDPA authorities for the current round. @@ -66,8 +67,8 @@ pub struct InitializationData { pub authority_list: AuthorityList, /// The ID of the initial authority set. pub set_id: SetId, - /// Should the pallet block transaction immediately after initialization. - pub is_halted: bool, + /// Pallet operating mode. + pub operating_mode: BasicOperatingMode, } /// base trait for verifying transaction inclusion proofs. @@ -88,7 +89,7 @@ pub trait InclusionProofVerifier { /// A trait for pallets which want to keep track of finalized headers from a bridged chain. pub trait HeaderChain { /// Get the best finalized header known to the header chain. - fn best_finalized() -> H; + fn best_finalized() -> Option; /// Get the best authority set known to the header chain. fn authority_set() -> AuthoritySet; @@ -98,8 +99,8 @@ pub trait HeaderChain { } impl HeaderChain for () { - fn best_finalized() -> H { - H::default() + fn best_finalized() -> Option { + None } fn authority_set() -> AuthoritySet { diff --git a/primitives/header-chain/src/storage_keys.rs b/primitives/header-chain/src/storage_keys.rs index e123703eed..bb642b1817 100644 --- a/primitives/header-chain/src/storage_keys.rs +++ b/primitives/header-chain/src/storage_keys.rs @@ -17,25 +17,25 @@ //! Storage keys of bridge GRANDPA pallet. /// Name of the `IsHalted` storage value. -pub const IS_HALTED_VALUE_NAME: &str = "IsHalted"; +pub const PALLET_OPERATING_MODE_VALUE_NAME: &str = "PalletOperatingMode"; /// Name of the `BestFinalized` storage value. pub const BEST_FINALIZED_VALUE_NAME: &str = "BestFinalized"; use sp_core::storage::StorageKey; -/// Storage key of the `IsHalted` flag in the runtime storage. -pub fn is_halted_key(pallet_prefix: &str) -> StorageKey { +/// Storage key of the `PalletOperatingMode` variable in the runtime storage. +pub fn pallet_operating_mode_key(pallet_prefix: &str) -> StorageKey { StorageKey( bp_runtime::storage_value_final_key( pallet_prefix.as_bytes(), - IS_HALTED_VALUE_NAME.as_bytes(), + PALLET_OPERATING_MODE_VALUE_NAME.as_bytes(), ) .to_vec(), ) } -/// Storage key of the best finalized header hash value in the runtime storage. -pub fn best_finalized_hash_key(pallet_prefix: &str) -> StorageKey { +/// Storage key of the best finalized header number and hash value in the runtime storage. +pub fn best_finalized_key(pallet_prefix: &str) -> StorageKey { StorageKey( bp_runtime::storage_value_final_key( pallet_prefix.as_bytes(), @@ -51,23 +51,23 @@ mod tests { use hex_literal::hex; #[test] - fn is_halted_key_computed_properly() { + fn pallet_operating_mode_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // compatibility with previous pallet. - let storage_key = is_halted_key("BridgeGrandpa").0; + let storage_key = pallet_operating_mode_key("BridgeGrandpa").0; assert_eq!( storage_key, - hex!("0b06f475eddb98cf933a12262e0388de9611a984bbd04e2fd39f97bbc006115f").to_vec(), + hex!("0b06f475eddb98cf933a12262e0388de0f4cf0917788d791142ff6c1f216e7b3").to_vec(), "Unexpected storage key: {}", hex::encode(&storage_key), ); } #[test] - fn best_finalized_hash_key_computed_properly() { + fn best_finalized_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // compatibility with previous pallet. - let storage_key = best_finalized_hash_key("BridgeGrandpa").0; + let storage_key = best_finalized_key("BridgeGrandpa").0; assert_eq!( storage_key, hex!("0b06f475eddb98cf933a12262e0388dea4ebafdd473c549fdb24c5c991c5591c").to_vec(), diff --git a/primitives/header-chain/tests/implementation_match.rs b/primitives/header-chain/tests/implementation_match.rs index 51275bbd64..aaa19d4b91 100644 --- a/primitives/header-chain/tests/implementation_match.rs +++ b/primitives/header-chain/tests/implementation_match.rs @@ -20,7 +20,6 @@ //! Some of tests in this module may partially duplicate tests from `justification.rs`, //! but their purpose is different. -use assert_matches::assert_matches; use bp_header_chain::justification::{verify_justification, Error, GrandpaJustification}; use bp_test_utils::{ header_id, make_justification_for_header, signed_precommit, test_header, Account, @@ -106,7 +105,7 @@ pub fn make_default_justification(header: &TestHeader) -> GrandpaJustification( @@ -222,21 +233,26 @@ fn same_result_when_authority_equivocates_once_in_a_round() { ), Ok(()), ); - // original implementation returns non-empty GHOST - assert_matches!( - finality_grandpa::validate_commit( - &justification.commit, - &full_voter_set(), - &AncestryChain::new(&justification.votes_ancestries), - ) - .map(|result| result.ghost().cloned()), - Ok(Some(_)) - ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); } #[test] fn same_result_when_authority_equivocates_twice_in_a_round() { - let mut justification = make_default_justification(&test_header(1)); + let mut justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: minimal_accounts_set(), + ancestors: 0, + ..Default::default() + }); // there's some code in the original implementation that should return an error when // same authority submits more than two different votes in a single round: // https://github.com/paritytech/finality-grandpa/blob/6aeea2d1159d0f418f0b86e70739f2130629ca09/src/lib.rs#L473 @@ -266,16 +282,16 @@ fn same_result_when_authority_equivocates_twice_in_a_round() { ), Ok(()), ); - // original implementation returns non-empty GHOST - assert_matches!( - finality_grandpa::validate_commit( - &justification.commit, - &full_voter_set(), - &AncestryChain::new(&justification.votes_ancestries), - ) - .map(|result| result.ghost().cloned()), - Ok(Some(_)) - ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); } #[test] @@ -299,14 +315,14 @@ fn same_result_when_there_are_not_enough_cumulative_weight_to_finalize_commit_ta ), Err(Error::TooLowCumulativeWeight), ); - // original implementation returns empty GHOST - assert_matches!( - finality_grandpa::validate_commit( - &justification.commit, - &full_voter_set(), - &AncestryChain::new(&justification.votes_ancestries), - ) - .map(|result| result.ghost().cloned()), - Ok(None) - ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == false`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(!result.is_valid()); } diff --git a/primitives/message-dispatch/src/lib.rs b/primitives/message-dispatch/src/lib.rs deleted file mode 100644 index 07e448ee7a..0000000000 --- a/primitives/message-dispatch/src/lib.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! A common interface for all Bridge Message Dispatch modules. - -#![cfg_attr(not(feature = "std"), no_std)] -#![warn(missing_docs)] - -use bp_runtime::{ - messages::{DispatchFeePayment, MessageDispatchResult}, - ChainId, Size, -}; -use codec::{Decode, Encode}; -use frame_support::RuntimeDebug; -use scale_info::TypeInfo; -use sp_std::prelude::*; - -/// Message dispatch weight. -pub type Weight = u64; - -/// Spec version type. -pub type SpecVersion = u32; - -/// A generic trait to dispatch arbitrary messages delivered over the bridge. -pub trait MessageDispatch { - /// A type of the message to be dispatched. - type Message: codec::Decode; - - /// Estimate dispatch weight. - /// - /// This function must: (1) be instant and (2) return correct upper bound - /// of dispatch weight. - fn dispatch_weight(message: &Self::Message) -> Weight; - - /// Dispatches the message internally. - /// - /// `source_chain` indicates the chain where the message came from. - /// `target_chain` indicates the chain where message dispatch happens. - /// - /// `id` is a short unique identifier of the message. - /// - /// If message is `Ok`, then it should be dispatched. If it is `Err`, then it's just - /// a sign that some other component has rejected the message even before it has - /// reached `dispatch` method (right now this may only be caused if we fail to decode - /// the whole message). - /// - /// Returns unspent dispatch weight. - fn dispatch Result<(), ()>>( - source_chain: ChainId, - target_chain: ChainId, - id: BridgeMessageId, - message: Result, - pay_dispatch_fee: P, - ) -> MessageDispatchResult; -} - -/// Origin of a Call when it is dispatched on the target chain. -/// -/// The source chain can (and should) verify that the message can be dispatched on the target chain -/// with a particular origin given the source chain's origin. This can be done with the -/// `verify_message_origin()` function. -#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] -pub enum CallOrigin { - /// Call is sent by the Root origin on the source chain. On the target chain it is dispatched - /// from a derived account. - /// - /// The derived account represents the source Root account on the target chain. This is useful - /// if the target chain needs some way of knowing that a call came from a privileged origin on - /// the source chain (maybe to allow a configuration change for example). - SourceRoot, - - /// Call is sent by `SourceChainAccountId` on the source chain. On the target chain it is - /// dispatched from an account controlled by a private key on the target chain. - /// - /// The account can be identified by `TargetChainAccountPublic`. The proof that the - /// `SourceChainAccountId` controls `TargetChainAccountPublic` is the `TargetChainSignature` - /// over `(Call, SourceChainAccountId, TargetChainSpecVersion, SourceChainBridgeId).encode()`. - /// - /// NOTE sending messages using this origin (or any other) does not have replay protection! - /// The assumption is that both the source account and the target account is controlled by - /// the same entity, so source-chain replay protection is sufficient. - /// As a consequence, it's extremely important for the target chain user to never produce - /// a signature with their target-private key on something that could be sent over the bridge, - /// i.e. if the target user signs `(, Call::Transfer(X, 5))` - /// The owner of `some-source-account-id` can send that message multiple times, which would - /// result with multiple transfer calls being dispatched on the target chain. - /// So please, NEVER USE YOUR PRIVATE KEY TO SIGN SOMETHING YOU DON'T FULLY UNDERSTAND! - TargetAccount(SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature), - - /// Call is sent by the `SourceChainAccountId` on the source chain. On the target chain it is - /// dispatched from a derived account ID. - /// - /// The account ID on the target chain is derived from the source account ID. This is useful if - /// you need a way to represent foreign accounts on this chain for call dispatch purposes. - /// - /// Note that the derived account does not need to have a private key on the target chain. This - /// origin can therefore represent proxies, pallets, etc. as well as "regular" accounts. - SourceAccount(SourceChainAccountId), -} - -/// Message payload type used by dispatch module. -#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] -pub struct MessagePayload< - SourceChainAccountId, - TargetChainAccountPublic, - TargetChainSignature, - Call, -> { - /// Runtime specification version. We only dispatch messages that have the same - /// runtime version. Otherwise we risk to misinterpret encoded calls. - pub spec_version: SpecVersion, - /// Weight of the call, declared by the message sender. If it is less than actual - /// static weight, the call is not dispatched. - pub weight: Weight, - /// Call origin to be used during dispatch. - pub origin: CallOrigin, - /// Where the fee for dispatching message is paid? - pub dispatch_fee_payment: DispatchFeePayment, - /// The call itself. - pub call: Call, -} - -impl Size - for MessagePayload> -{ - fn size_hint(&self) -> u32 { - self.call.len() as _ - } -} diff --git a/primitives/messages/Cargo.toml b/primitives/messages/Cargo.toml index 2a84f74d22..6690a1bfbb 100644 --- a/primitives/messages/Cargo.toml +++ b/primitives/messages/Cargo.toml @@ -8,9 +8,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] bitvec = { version = "1", default-features = false, features = ["alloc"] } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "bit-vec"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "bit-vec"] } impl-trait-for-tuples = "0.2" -scale-info = { version = "2.0.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["bit-vec", "derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge dependencies diff --git a/primitives/messages/src/lib.rs b/primitives/messages/src/lib.rs index a4f204d238..d5b2b9c9db 100644 --- a/primitives/messages/src/lib.rs +++ b/primitives/messages/src/lib.rs @@ -19,12 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -// Generated by `DecodeLimit::decode_with_depth_limit` -#![allow(clippy::unnecessary_mut_passed)] use bitvec::prelude::*; -use bp_runtime::messages::DispatchFeePayment; -use codec::{Decode, Encode}; +use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, OperatingMode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; use sp_std::{collections::vec_deque::VecDeque, prelude::*}; @@ -37,12 +35,12 @@ pub mod target_chain; pub use frame_support::weights::Weight; /// Messages pallet operating mode. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -pub enum OperatingMode { - /// Normal mode, when all operations are allowed. - Normal, - /// The pallet is not accepting outbound messages. Inbound messages and receival proofs +pub enum MessagesOperatingMode { + /// Basic operating mode (Normal/Halted) + Basic(BasicOperatingMode), + /// The pallet is not accepting outbound messages. Inbound messages and receiving proofs /// are still accepted. /// /// This mode may be used e.g. when bridged chain expects upgrade. Then to avoid dispatch @@ -50,13 +48,20 @@ pub enum OperatingMode { /// queued messages to the bridged chain. Once upgrade is completed, the mode may be switched /// back to `Normal`. RejectingOutboundMessages, - /// The pallet is halted. All operations (except operating mode change) are prohibited. - Halted, } -impl Default for OperatingMode { +impl Default for MessagesOperatingMode { fn default() -> Self { - OperatingMode::Normal + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + } +} + +impl OperatingMode for MessagesOperatingMode { + fn is_halted(&self) -> bool { + match self { + Self::Basic(operating_mode) => operating_mode.is_halted(), + _ => false, + } } } @@ -83,7 +88,7 @@ pub type BridgeMessageId = (LaneId, MessageNonce); pub type MessagePayload = Vec; /// Message key (unique message identifier) as it is stored in the storage. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct MessageKey { /// ID of the message lane. pub lane_id: LaneId, @@ -152,13 +157,13 @@ impl InboundLaneData { /// Returns approximate size of the struct, given a number of entries in the `relayers` set and /// size of each entry. /// - /// Returns `None` if size overflows `u32` limits. - pub fn encoded_size_hint( - relayer_id_encoded_size: u32, - relayers_entries: u32, - messages_count: u32, - ) -> Option { - let message_nonce_size = 8; + /// Returns `None` if size overflows `usize` limits. + pub fn encoded_size_hint(relayers_entries: usize, messages_count: usize) -> Option + where + RelayerId: MaxEncodedLen, + { + let message_nonce_size = MessageNonce::max_encoded_len(); + let relayer_id_encoded_size = RelayerId::max_encoded_len(); let relayers_entry_size = relayer_id_encoded_size.checked_add(2 * message_nonce_size)?; let relayers_size = relayers_entries.checked_mul(relayers_entry_size)?; let dispatch_results_per_byte = 8; @@ -169,6 +174,19 @@ impl InboundLaneData { .and_then(|result| result.checked_add(dispatch_result_size)) } + /// Returns the approximate size of the struct as u32, given a number of entries in the + /// `relayers` set and the size of each entry. + /// + /// Returns `u32::MAX` if size overflows `u32` limits. + pub fn encoded_size_hint_u32(relayers_entries: usize, messages_count: usize) -> u32 + where + RelayerId: MaxEncodedLen, + { + Self::encoded_size_hint(relayers_entries, messages_count) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX) + } + /// Nonce of the last message that has been delivered to this (target) chain. pub fn last_delivered_nonce(&self) -> MessageNonce { self.relayers @@ -178,12 +196,15 @@ impl InboundLaneData { } } -/// Message details, returned by runtime APIs. +/// Outbound message details, returned by runtime APIs. #[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)] -pub struct MessageDetails { +pub struct OutboundMessageDetails { /// Nonce assigned to the message. pub nonce: MessageNonce, - /// Message dispatch weight, declared by the submitter. + /// Message dispatch weight. + /// + /// Depending on messages pallet configuration, it may be declared by the message submitter, + /// computed automatically or just be zero if dispatch fee is paid at the target chain. pub dispatch_weight: Weight, /// Size of the encoded message. pub size: u32, @@ -193,6 +214,18 @@ pub struct MessageDetails { pub dispatch_fee_payment: DispatchFeePayment, } +/// Inbound message details, returned by runtime APIs. +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)] +pub struct InboundMessageDetails { + /// Computed message dispatch weight. + /// + /// Runtime API guarantees that it will match the value, returned by + /// `target_chain::MessageDispatch::dispatch_weight`. This means that if the runtime + /// has failed to decode the message, it will be zero - that's because `undecodable` + /// message cannot be dispatched. + pub dispatch_weight: Weight, +} + /// Bit vector of message dispatch results. pub type DispatchResultsBitVec = BitVec; @@ -226,7 +259,7 @@ impl DeliveredMessages { /// dispatch result. pub fn new(nonce: MessageNonce, dispatch_result: bool) -> Self { let mut dispatch_results = BitVec::with_capacity(1); - dispatch_results.push(if dispatch_result { true } else { false }); + dispatch_results.push(dispatch_result); DeliveredMessages { begin: nonce, end: nonce, dispatch_results } } @@ -276,10 +309,15 @@ pub struct UnrewardedRelayersState { pub messages_in_oldest_entry: MessageNonce, /// Total number of messages in the relayers vector. pub total_messages: MessageNonce, + /// Nonce of the latest message that has been delivered to the target chain. + /// + /// This corresponds to the result of the `InboundLaneData::last_delivered_nonce` call + /// at the bridged chain. + pub last_delivered_nonce: MessageNonce, } /// Outbound lane data. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct OutboundLaneData { /// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated /// message if all sent messages are already pruned. @@ -353,11 +391,8 @@ mod tests { (13u8, 128u8), ]; for (relayer_entries, messages_count) in test_cases { - let expected_size = InboundLaneData::::encoded_size_hint( - 1, - relayer_entries as _, - messages_count as _, - ); + let expected_size = + InboundLaneData::::encoded_size_hint(relayer_entries as _, messages_count as _); let actual_size = InboundLaneData { relayers: (1u8..=relayer_entries) .map(|i| { diff --git a/primitives/messages/src/source_chain.rs b/primitives/messages/src/source_chain.rs index fa7b3bb85e..be56ffe87f 100644 --- a/primitives/messages/src/source_chain.rs +++ b/primitives/messages/src/source_chain.rs @@ -133,7 +133,6 @@ pub trait MessageDeliveryAndDispatchPayment { fn pay_delivery_and_dispatch_fee( submitter: &SenderOrigin, fee: &Balance, - relayer_fund_account: &AccountId, ) -> Result<(), Self::Error>; /// Pay rewards for delivering messages to the given relayers. @@ -145,12 +144,32 @@ pub trait MessageDeliveryAndDispatchPayment { messages_relayers: VecDeque>, confirmation_relayer: &AccountId, received_range: &RangeInclusive, - relayer_fund_account: &AccountId, ); } +impl + MessageDeliveryAndDispatchPayment for () +{ + type Error = &'static str; + + fn pay_delivery_and_dispatch_fee( + _submitter: &SenderOrigin, + _fee: &Balance, + ) -> Result<(), Self::Error> { + Ok(()) + } + + fn pay_relayers_rewards( + _lane_id: LaneId, + _messages_relayers: VecDeque>, + _confirmation_relayer: &AccountId, + _received_range: &RangeInclusive, + ) { + } +} + /// Send message artifacts. -#[derive(RuntimeDebug, PartialEq)] +#[derive(Eq, RuntimeDebug, PartialEq)] pub struct SendMessageArtifacts { /// Nonce of the message. pub nonce: MessageNonce, @@ -175,7 +194,7 @@ pub trait MessagesBridge { } /// Bridge that does nothing when message is being sent. -#[derive(RuntimeDebug, PartialEq)] +#[derive(Eq, RuntimeDebug, PartialEq)] pub struct NoopMessagesBridge; impl @@ -283,7 +302,6 @@ impl fn pay_delivery_and_dispatch_fee( _submitter: &SenderOrigin, _fee: &Balance, - _relayer_fund_account: &AccountId, ) -> Result<(), Self::Error> { Err(ALL_OUTBOUND_MESSAGES_REJECTED) } @@ -293,7 +311,6 @@ impl _messages_relayers: VecDeque>, _confirmation_relayer: &AccountId, _received_range: &RangeInclusive, - _relayer_fund_account: &AccountId, ) { } } diff --git a/primitives/messages/src/storage_keys.rs b/primitives/messages/src/storage_keys.rs index 19494b8b85..4db11edec3 100644 --- a/primitives/messages/src/storage_keys.rs +++ b/primitives/messages/src/storage_keys.rs @@ -91,7 +91,7 @@ mod tests { fn storage_message_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted messages proofs. - let storage_key = message_key("BridgeMessages", &*b"test", 42).0; + let storage_key = message_key("BridgeMessages", b"test", 42).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), @@ -104,7 +104,7 @@ mod tests { fn outbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted outbound lane state proofs. - let storage_key = outbound_lane_data_key("BridgeMessages", &*b"test").0; + let storage_key = outbound_lane_data_key("BridgeMessages", b"test").0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), @@ -117,7 +117,7 @@ mod tests { fn inbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted inbound lane state proofs. - let storage_key = inbound_lane_data_key("BridgeMessages", &*b"test").0; + let storage_key = inbound_lane_data_key("BridgeMessages", b"test").0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), diff --git a/primitives/messages/src/target_chain.rs b/primitives/messages/src/target_chain.rs index a84ea7af90..a5686e4abe 100644 --- a/primitives/messages/src/target_chain.rs +++ b/primitives/messages/src/target_chain.rs @@ -93,9 +93,10 @@ pub trait MessageDispatch { /// Estimate dispatch weight. /// - /// This function must: (1) be instant and (2) return correct upper bound - /// of dispatch weight. - fn dispatch_weight(message: &DispatchMessage) -> Weight; + /// This function must return correct upper bound of dispatch weight. The return value + /// of this function is expected to match return value of the corresponding + /// `FromInboundLaneApi::message_details().dispatch_weight` call. + fn dispatch_weight(message: &mut DispatchMessage) -> Weight; /// Called when inbound message is received. /// @@ -156,7 +157,7 @@ impl SourceHeaderChain for ForbidInboundMessages { impl MessageDispatch for ForbidInboundMessages { type DispatchPayload = (); - fn dispatch_weight(_message: &DispatchMessage) -> Weight { + fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { Weight::MAX } diff --git a/primitives/parachains/Cargo.toml b/primitives/parachains/Cargo.toml new file mode 100644 index 0000000000..f6327c772c --- /dev/null +++ b/primitives/parachains/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "bp-parachains" +description = "Primitives of parachains module." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } + +# Bridge dependencies + +bp-polkadot-core = { path = "../polkadot-core", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-polkadot-core/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "scale-info/std", + "serde", + "sp-core/std", +] diff --git a/primitives/parachains/src/lib.rs b/primitives/parachains/src/lib.rs new file mode 100644 index 0000000000..52b4954897 --- /dev/null +++ b/primitives/parachains/src/lib.rs @@ -0,0 +1,90 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Primitives of parachains module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use bp_polkadot_core::{ + parachains::{ParaHash, ParaHead, ParaId}, + BlockNumber as RelayBlockNumber, +}; +use bp_runtime::{StorageDoubleMapKeyProvider, StorageMapKeyProvider}; +use codec::{Decode, Encode}; +use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat}; +use scale_info::TypeInfo; +use sp_core::storage::StorageKey; + +/// Best known parachain head hash. +#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)] +pub struct BestParaHeadHash { + /// Number of relay block where this head has been read. + /// + /// Parachain head is opaque to relay chain. So we can't simply decode it as a header of + /// parachains and call `block_number()` on it. Instead, we're using the fact that parachain + /// head is always built on top of previous head (because it is blockchain) and relay chain + /// always imports parachain heads in order. What it means for us is that at any given + /// **finalized** relay block `B`, head of parachain will be ancestor (or the same) of all + /// parachain heads available at descendants of `B`. + pub at_relay_block_number: RelayBlockNumber, + /// Hash of parachain head. + pub head_hash: ParaHash, +} + +/// Best known parachain head as it is stored in the runtime storage. +#[derive(Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)] +pub struct ParaInfo { + /// Best known parachain head hash. + pub best_head_hash: BestParaHeadHash, + /// Current ring buffer position for this parachain. + pub next_imported_hash_position: u32, +} + +/// Returns runtime storage key of given parachain head at the source chain. +/// +/// The head is stored by the `paras` pallet in the `Heads` map. +pub fn parachain_head_storage_key_at_source( + paras_pallet_name: &str, + para_id: ParaId, +) -> StorageKey { + bp_runtime::storage_map_final_key::(paras_pallet_name, "Heads", ¶_id.encode()) +} + +/// Can be use to access the runtime storage key of the parachains info at the target chain. +/// +/// The info is stored by the `pallet-bridge-parachains` pallet in the `ParasInfo` map. +pub struct ParasInfoKeyProvider; +impl StorageMapKeyProvider for ParasInfoKeyProvider { + const MAP_NAME: &'static str = "ParasInfo"; + + type Hasher = Blake2_128Concat; + type Key = ParaId; + type Value = ParaInfo; +} + +/// Can be use to access the runtime storage key of the parachain head at the target chain. +/// +/// The head is stored by the `pallet-bridge-parachains` pallet in the `ImportedParaHeads` map. +pub struct ImportedParaHeadsKeyProvider; +impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider { + const MAP_NAME: &'static str = "ImportedParaHeads"; + + type Hasher1 = Blake2_128Concat; + type Key1 = ParaId; + type Hasher2 = Blake2_128Concat; + type Key2 = ParaHash; + type Value = ParaHead; +} diff --git a/primitives/polkadot-core/Cargo.toml b/primitives/polkadot-core/Cargo.toml index 1542a784ef..4448e75f11 100644 --- a/primitives/polkadot-core/Cargo.toml +++ b/primitives/polkadot-core/Cargo.toml @@ -7,8 +7,10 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +parity-util-mem = { version = "0.11.0", optional = true } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge Dependencies @@ -35,8 +37,10 @@ std = [ "bp-runtime/std", "frame-support/std", "frame-system/std", - "parity-scale-codec/std", + "codec/std", + "parity-util-mem", "scale-info/std", + "serde", "sp-api/std", "sp-core/std", "sp-runtime/std", diff --git a/primitives/polkadot-core/src/lib.rs b/primitives/polkadot-core/src/lib.rs index 79db07b82c..476b1f2f23 100644 --- a/primitives/polkadot-core/src/lib.rs +++ b/primitives/polkadot-core/src/lib.rs @@ -18,6 +18,7 @@ use bp_messages::MessageNonce; use bp_runtime::{Chain, EncodedOrDecodedCall}; +use codec::Compact; use frame_support::{ dispatch::Dispatchable, parameter_types, @@ -28,7 +29,6 @@ use frame_support::{ Blake2_128Concat, RuntimeDebug, StorageHasher, Twox128, }; use frame_system::limits; -use parity_scale_codec::Compact; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_core::Hasher as HasherT; use sp_runtime::{ @@ -43,6 +43,8 @@ use sp_std::prelude::Vec; pub use frame_support::{weights::constants::ExtrinsicBaseWeight, Parameter}; pub use sp_runtime::{traits::Convert, Perbill}; +pub mod parachains; + /// Number of extra bytes (excluding size of storage value itself) of storage proof, built at /// Polkadot-like chain. This mostly depends on number of entries in the storage trie. /// Some reserve is reserved to account future chain growth. @@ -63,11 +65,6 @@ pub use sp_runtime::{traits::Convert, Perbill}; /// at next runtime upgrade. pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -/// -/// All polkadot-like chains are using same crypto. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// All Polkadot-like chains allow normal extrinsics to fill block up to 75 percent. /// /// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. @@ -259,16 +256,14 @@ pub struct SignedExtensions { _data: sp_std::marker::PhantomData, } -impl parity_scale_codec::Encode for SignedExtensions { +impl codec::Encode for SignedExtensions { fn using_encoded R>(&self, f: F) -> R { self.encode_payload.using_encoded(f) } } -impl parity_scale_codec::Decode for SignedExtensions { - fn decode( - input: &mut I, - ) -> Result { +impl codec::Decode for SignedExtensions { + fn decode(input: &mut I) -> Result { SignedExtra::decode(input).map(|encode_payload| SignedExtensions { encode_payload, additional_signed: None, @@ -326,14 +321,7 @@ impl SignedExtensions { impl sp_runtime::traits::SignedExtension for SignedExtensions where - Call: parity_scale_codec::Codec - + sp_std::fmt::Debug - + Sync - + Send - + Clone - + Eq - + PartialEq - + StaticTypeInfo, + Call: codec::Codec + sp_std::fmt::Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo, Call: Dispatchable, { const IDENTIFIER: &'static str = "Not needed."; @@ -393,15 +381,6 @@ impl Chain for PolkadotLike { } } -/// Convert a 256-bit hash into an AccountId. -pub struct AccountIdConverter; - -impl Convert for AccountIdConverter { - fn convert(hash: sp_core::H256) -> AccountId { - hash.to_fixed_bytes().into() - } -} - /// Return a storage key for account data. /// /// This is based on FRAME storage-generation code from Substrate: @@ -411,7 +390,7 @@ impl Convert for AccountIdConverter { pub fn account_info_storage_key(id: &AccountId) -> Vec { let module_prefix_hashed = Twox128::hash(b"System"); let storage_prefix_hashed = Twox128::hash(b"Account"); - let key_hashed = parity_scale_codec::Encode::using_encoded(id, Blake2_128Concat::hash); + let key_hashed = codec::Encode::using_encoded(id, Blake2_128Concat::hash); let mut final_key = Vec::with_capacity( module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(), @@ -427,18 +406,6 @@ pub fn account_info_storage_key(id: &AccountId) -> Vec { #[cfg(test)] mod tests { use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_encoded_account_id_size_is_correct() { - let actual_size = AccountId::from([0u8; 32]).encode().len(); - assert!( - actual_size <= MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize, - "Actual size of encoded account id for Polkadot-like chains ({}) is larger than expected {}", - actual_size, - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } #[test] fn should_generate_storage_key() { diff --git a/primitives/polkadot-core/src/parachains.rs b/primitives/polkadot-core/src/parachains.rs new file mode 100644 index 0000000000..51fcd59cae --- /dev/null +++ b/primitives/polkadot-core/src/parachains.rs @@ -0,0 +1,100 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Primitives of polkadot-like chains, that are related to parachains functionality. +//! +//! Even though this (bridges) repository references polkadot repository, we can't +//! reference polkadot crates from pallets. That's because bridges repository is +//! included in the polkadot repository and included pallets are used by polkadot +//! chains. Having pallets that are referencing polkadot, would mean that there may +//! be two versions of polkadot crates included in the runtime. Which is bad. + +use bp_runtime::Size; +use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; +use frame_support::RuntimeDebug; +use scale_info::TypeInfo; +use sp_core::Hasher; +use sp_std::vec::Vec; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "std")] +use parity_util_mem::MallocSizeOf; + +/// Parachain id. +/// +/// This is an equivalent of the `polkadot_parachain::Id`, which is a compact-encoded `u32`. +#[derive( + Clone, + CompactAs, + Copy, + Decode, + Default, + Encode, + Eq, + Hash, + MaxEncodedLen, + Ord, + PartialEq, + PartialOrd, + RuntimeDebug, + TypeInfo, +)] +pub struct ParaId(pub u32); + +impl From for ParaId { + fn from(id: u32) -> Self { + ParaId(id) + } +} + +/// Parachain head. +/// +/// This is an equivalent of the `polkadot_parachain::HeadData`. +/// +/// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header. Keep in mind +/// that in Polkadot it is twice-encoded (so `header.encode().encode()`). We'll also do it to keep +/// it binary-compatible (implies hash-compatibility) with other parachain pallets. +#[derive( + PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, MallocSizeOf))] +pub struct ParaHead(pub Vec); + +impl ParaHead { + /// Returns the hash of this head data. + pub fn hash(&self) -> crate::Hash { + sp_runtime::traits::BlakeTwo256::hash(&self.0) + } +} + +/// Parachain head hash. +pub type ParaHash = crate::Hash; + +/// Parachain head hasher. +pub type ParaHasher = crate::Hasher; + +/// Raw storage proof of parachain heads, stored in polkadot-like chain runtime. +#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct ParaHeadsProof(pub Vec>); + +impl Size for ParaHeadsProof { + fn size(&self) -> u32 { + u32::try_from(self.0.iter().fold(0usize, |sum, node| sum.saturating_add(node.len()))) + .unwrap_or(u32::MAX) + } +} diff --git a/primitives/message-dispatch/Cargo.toml b/primitives/relayers/Cargo.toml similarity index 54% rename from primitives/message-dispatch/Cargo.toml rename to primitives/relayers/Cargo.toml index 39b2d00111..908412477c 100644 --- a/primitives/message-dispatch/Cargo.toml +++ b/primitives/relayers/Cargo.toml @@ -1,27 +1,27 @@ [package] -name = "bp-message-dispatch" -description = "Primitives of bridge messages dispatch modules." +name = "bp-relayers" +description = "Primitives of relayers module." version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -bp-runtime = { path = "../runtime", default-features = false } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +[dev-dependencies] +hex = "0.4" +hex-literal = "0.3" + [features] default = ["std"] std = [ - "bp-runtime/std", - "codec/std", "frame-support/std", - "scale-info/std", - "sp-std/std", + "sp-runtime/std", + "sp-std/std", ] diff --git a/primitives/relayers/src/lib.rs b/primitives/relayers/src/lib.rs new file mode 100644 index 0000000000..d1c82d612e --- /dev/null +++ b/primitives/relayers/src/lib.rs @@ -0,0 +1,45 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Primitives of messages module. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_std::{fmt::Debug, marker::PhantomData}; + +/// Reward payment procedure. +pub trait PaymentProcedure { + /// Error that may be returned by the procedure. + type Error: Debug; + + /// Pay reward to the relayer. + fn pay_reward(relayer: &Relayer, reward: Reward) -> Result<(), Self::Error>; +} + +/// Reward payment procedure that is simply minting given amount of tokens. +pub struct MintReward(PhantomData<(T, Relayer)>); + +impl PaymentProcedure for MintReward +where + T: frame_support::traits::fungible::Mutate, +{ + type Error = sp_runtime::DispatchError; + + fn pay_reward(relayer: &Relayer, reward: T::Balance) -> Result<(), Self::Error> { + T::mint_into(relayer, reward) + } +} diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 085cfb9dbc..79f2b9fe03 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -7,20 +7,23 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } hash-db = { version = "0.15.2", default-features = false } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +trie-db = { version = "0.24.0", default-features = false } [dev-dependencies] hex-literal = "0.3" @@ -30,13 +33,16 @@ default = ["std"] std = [ "codec/std", "frame-support/std", + "frame-system/std", "hash-db/std", "num-traits/std", "scale-info/std", + "serde", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", "sp-state-machine/std", "sp-trie/std", + "trie-db/std", ] diff --git a/primitives/runtime/src/chain.rs b/primitives/runtime/src/chain.rs index 5a7fafe9f6..7cb0ad976f 100644 --- a/primitives/runtime/src/chain.rs +++ b/primitives/runtime/src/chain.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +use crate::HeaderIdProvider; use codec::{Decode, Encode}; use frame_support::{weights::Weight, Parameter}; use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero}; @@ -143,6 +144,7 @@ pub trait Chain: Send + Sync + 'static { // https://crates.parity.io/sp_runtime/traits/trait.Header.html type Header: Parameter + HeaderT + + HeaderIdProvider + MaybeSerializeDeserialize; /// The user account identifier type for the runtime. @@ -154,7 +156,6 @@ pub trait Chain: Send + Sync + 'static { type Balance: AtLeast32BitUnsigned + FixedPointOperand + Parameter - + Parameter + Member + MaybeSerializeDeserialize + Clone @@ -213,3 +214,132 @@ pub type AccountPublicOf = as Verify>::Signer; /// Transaction era used by the chain. pub type TransactionEraOf = crate::TransactionEra, HashOf>; + +/// Convenience macro that declares bridge finality runtime apis and related constants for a chain. +/// This includes: +/// - chain-specific bridge runtime APIs: +/// - `FinalityApi` +/// - constants that are stringified names of runtime API methods: +/// - `BEST_FINALIZED__HEADER_METHOD` +/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +#[macro_export] +macro_rules! decl_bridge_finality_runtime_apis { + ($chain: ident) => { + bp_runtime::paste::item! { + mod [<$chain _finality_api>] { + use super::*; + + /// Name of the `FinalityApi::best_finalized` runtime method. + pub const []: &str = + stringify!([<$chain:camel FinalityApi_best_finalized>]); + + sp_api::decl_runtime_apis! { + /// API for querying information about the finalized chain headers. + /// + /// This API is implemented by runtimes that are receiving messages from this chain, not by this + /// chain's runtime itself. + pub trait [<$chain:camel FinalityApi>] { + /// Returns number and hash of the best finalized header known to the bridge module. + fn best_finalized() -> Option>; + } + } + } + + pub use [<$chain _finality_api>]::*; + } + }; +} + +/// Convenience macro that declares bridge messages runtime apis and related constants for a chain. +/// This includes: +/// - chain-specific bridge runtime APIs: +/// - `ToOutboundLaneApi` +/// - `FromInboundLaneApi` +/// - constants that are stringified names of runtime API methods: +/// - `TO__ESTIMATE_MESSAGE_FEE_METHOD` +/// - `TO__MESSAGE_DETAILS_METHOD` +/// - `FROM__MESSAGE_DETAILS_METHOD`, +/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +#[macro_export] +macro_rules! decl_bridge_messages_runtime_apis { + ($chain: ident) => { + bp_runtime::paste::item! { + mod [<$chain _messages_api>] { + use super::*; + + /// Name of the `ToOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime + /// method. + pub const []: &str = + stringify!([]); + /// Name of the `ToOutboundLaneApi::message_details` runtime method. + pub const []: &str = + stringify!([]); + + /// Name of the `FromInboundLaneApi::message_details` runtime method. + pub const []: &str = + stringify!([]); + + sp_api::decl_runtime_apis! { + /// Outbound message lane API for messages that are sent to this chain. + /// + /// This API is implemented by runtimes that are receiving messages from this chain, not by this + /// chain's runtime itself. + pub trait [] { + /// Estimate message delivery and dispatch fee that needs to be paid by the sender on + /// this chain. + /// + /// Returns `None` if message is too expensive to be sent to this chain from the bridged chain. + /// + /// Please keep in mind that this method returns the lowest message fee required for message + /// to be accepted to the lane. It may be a good idea to pay a bit over this price to account + /// for future exchange rate changes and guarantee that relayer would deliver your message + /// to the target chain. + fn estimate_message_delivery_and_dispatch_fee( + lane_id: LaneId, + payload: OutboundPayload, + [<$chain:lower _to_this_conversion_rate>]: Option, + ) -> Option; + /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all + /// messages in given inclusive range. + /// + /// If some (or all) messages are missing from the storage, they'll also will + /// be missing from the resulting vector. The vector is ordered by the nonce. + fn message_details( + lane: LaneId, + begin: MessageNonce, + end: MessageNonce, + ) -> Vec>; + } + + /// Inbound message lane API for messages sent by this chain. + /// + /// This API is implemented by runtimes that are receiving messages from this chain, not by this + /// chain's runtime itself. + /// + /// Entries of the resulting vector are matching entries of the `messages` vector. Entries of the + /// `messages` vector may (and need to) be read using `ToOutboundLaneApi::message_details`. + pub trait [] { + /// Return details of given inbound messages. + fn message_details( + lane: LaneId, + messages: Vec<(MessagePayload, OutboundMessageDetails)>, + ) -> Vec; + } + } + } + + pub use [<$chain _messages_api>]::*; + } + } +} + +/// Convenience macro that declares bridge finality runtime apis, bridge messages runtime apis +/// and related constants for a chain. +/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +#[macro_export] +macro_rules! decl_bridge_runtime_apis { + ($chain: ident) => { + bp_runtime::decl_bridge_finality_runtime_apis!($chain); + bp_runtime::decl_bridge_messages_runtime_apis!($chain); + }; +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 1d8a40339a..d775e09c47 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -18,18 +18,28 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::Encode; -use frame_support::{RuntimeDebug, StorageHasher}; +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use frame_support::{ + log, pallet_prelude::DispatchResult, PalletError, RuntimeDebug, StorageHasher, StorageValue, +}; +use frame_system::RawOrigin; +use scale_info::TypeInfo; use sp_core::{hash::H256, storage::StorageKey}; use sp_io::hashing::blake2_256; -use sp_std::{convert::TryFrom, vec, vec::Vec}; +use sp_runtime::traits::{BadOrigin, Header as HeaderT}; +use sp_std::{convert::TryFrom, fmt::Debug, vec, vec::Vec}; pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf, HasherOf, HeaderOf, IndexOf, SignatureOf, TransactionEraOf, }; pub use frame_support::storage::storage_prefix as storage_value_final_key; -pub use storage_proof::{Error as StorageProofError, StorageProofChecker}; +use num_traits::{CheckedSub, One}; +use sp_runtime::transaction_validity::TransactionValidity; +pub use storage_proof::{ + record_all_keys as record_all_trie_keys, Error as StorageProofError, + ProofSize as StorageProofSize, StorageProofChecker, +}; #[cfg(feature = "std")] pub use storage_proof::craft_valid_storage_proof; @@ -39,12 +49,18 @@ pub mod messages; mod chain; mod storage_proof; +// Re-export macro to aviod include paste dependency everywhere +pub use sp_runtime::paste; + /// Use this when something must be shared among all instances. pub const NO_INSTANCE_ID: ChainId = [0, 0, 0, 0]; /// Bridge-with-Rialto instance id. pub const RIALTO_CHAIN_ID: ChainId = *b"rlto"; +/// Bridge-with-RialtoParachain instance id. +pub const RIALTO_PARACHAIN_CHAIN_ID: ChainId = *b"rlpa"; + /// Bridge-with-Millau instance id. pub const MILLAU_CHAIN_ID: ChainId = *b"mlau"; @@ -70,9 +86,32 @@ pub const ACCOUNT_DERIVATION_PREFIX: &[u8] = b"pallet-bridge/account-derivation/ pub const ROOT_ACCOUNT_DERIVATION_PREFIX: &[u8] = b"pallet-bridge/account-derivation/root"; /// Generic header Id. -#[derive(RuntimeDebug, Default, Clone, Copy, Eq, Hash, PartialEq)] +#[derive( + RuntimeDebug, Default, Clone, Encode, Decode, Copy, Eq, Hash, PartialEq, PartialOrd, Ord, +)] pub struct HeaderId(pub Number, pub Hash); +/// Generic header id provider. +pub trait HeaderIdProvider { + // Get the header id. + fn id(&self) -> HeaderId; + + // Get the header id for the parent block. + fn parent_id(&self) -> Option>; +} + +impl HeaderIdProvider
for Header { + fn id(&self) -> HeaderId { + HeaderId(*self.number(), self.hash()) + } + + fn parent_id(&self) -> Option> { + self.number() + .checked_sub(&One::one()) + .map(|parent_number| HeaderId(parent_number, *self.parent_hash())) + } +} + /// Unique identifier of the chain. /// /// In addition to its main function (identifying the chain), this type may also be used to @@ -117,34 +156,21 @@ where .into() } -/// Derive the account ID of the shared relayer fund account. -/// -/// This account is used to collect fees for relayers that are passing messages across the bridge. -/// -/// The account ID can be the same across different instances of `pallet-bridge-messages` if the -/// same `bridge_id` is used. -pub fn derive_relayer_fund_account_id(bridge_id: ChainId) -> H256 { - ("relayer-fund-account", bridge_id).using_encoded(blake2_256).into() -} - /// Anything that has size. pub trait Size { - /// Return approximate size of this object (in bytes). - /// - /// This function should be lightweight. The result should not necessary be absolutely - /// accurate. - fn size_hint(&self) -> u32; + /// Return size of this object (in bytes). + fn size(&self) -> u32; } -impl Size for &[u8] { - fn size_hint(&self) -> u32 { - self.len() as _ +impl Size for () { + fn size(&self) -> u32 { + 0 } } -impl Size for () { - fn size_hint(&self) -> u32 { - 0 +impl Size for Vec { + fn size(&self) -> u32 { + self.len() as _ } } @@ -152,13 +178,13 @@ impl Size for () { pub struct PreComputedSize(pub usize); impl Size for PreComputedSize { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from(self.0).unwrap_or(u32::MAX) } } /// Era of specific transaction. -#[derive(RuntimeDebug, Clone, Copy)] +#[derive(RuntimeDebug, Clone, Copy, PartialEq)] pub enum TransactionEra { /// Transaction is immortal. Immortal, @@ -182,6 +208,14 @@ impl, BlockHash: Copy> TransactionEra Option { + match *self { + TransactionEra::Immortal => None, + TransactionEra::Mortal(_, period) => Some(period), + } + } + /// Returns era that is used by FRAME-based runtimes. pub fn frame_era(&self) -> sp_runtime::generic::Era { match *self { @@ -252,6 +286,174 @@ pub fn storage_value_key(pallet_prefix: &str, value_name: &str) -> StorageKey { StorageKey(final_key) } +/// Can be use to access the runtime storage key of a `StorageMap`. +pub trait StorageMapKeyProvider { + /// The name of the variable that holds the `StorageMap`. + const MAP_NAME: &'static str; + + /// The same as `StorageMap::Hasher1`. + type Hasher: StorageHasher; + /// The same as `StorageMap::Key1`. + type Key: FullCodec; + /// The same as `StorageMap::Value`. + type Value: FullCodec; + + /// This is a copy of the + /// `frame_support::storage::generator::StorageMap::storage_map_final_key`. + /// + /// We're using it because to call `storage_map_final_key` directly, we need access + /// to the runtime and pallet instance, which (sometimes) is impossible. + fn final_key(pallet_prefix: &str, key: &Self::Key) -> StorageKey { + storage_map_final_key::(pallet_prefix, Self::MAP_NAME, &key.encode()) + } +} + +/// Can be use to access the runtime storage key of a `StorageDoubleMap`. +pub trait StorageDoubleMapKeyProvider { + /// The name of the variable that holds the `StorageDoubleMap`. + const MAP_NAME: &'static str; + + /// The same as `StorageDoubleMap::Hasher1`. + type Hasher1: StorageHasher; + /// The same as `StorageDoubleMap::Key1`. + type Key1: FullCodec; + /// The same as `StorageDoubleMap::Hasher2`. + type Hasher2: StorageHasher; + /// The same as `StorageDoubleMap::Key2`. + type Key2: FullCodec; + /// The same as `StorageDoubleMap::Value`. + type Value: FullCodec; + + /// This is a copy of the + /// `frame_support::storage::generator::StorageDoubleMap::storage_double_map_final_key`. + /// + /// We're using it because to call `storage_double_map_final_key` directly, we need access + /// to the runtime and pallet instance, which (sometimes) is impossible. + fn final_key(pallet_prefix: &str, key1: &Self::Key1, key2: &Self::Key2) -> StorageKey { + let key1_hashed = Self::Hasher1::hash(&key1.encode()); + let key2_hashed = Self::Hasher2::hash(&key2.encode()); + let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes()); + let storage_prefix_hashed = frame_support::Twox128::hash(Self::MAP_NAME.as_bytes()); + + let mut final_key = Vec::with_capacity( + pallet_prefix_hashed.len() + + storage_prefix_hashed.len() + + key1_hashed.as_ref().len() + + key2_hashed.as_ref().len(), + ); + + final_key.extend_from_slice(&pallet_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key1_hashed.as_ref()); + final_key.extend_from_slice(key2_hashed.as_ref()); + + StorageKey(final_key) + } +} + +/// Error generated by the `OwnedBridgeModule` trait. +#[derive(Encode, Decode, TypeInfo, PalletError)] +pub enum OwnedBridgeModuleError { + /// All pallet operations are halted. + Halted, +} + +/// Operating mode for a bridge module. +pub trait OperatingMode: Send + Copy + Debug + FullCodec { + // Returns true if the bridge module is halted. + fn is_halted(&self) -> bool; +} + +/// Basic operating modes for a bridges module (Normal/Halted). +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub enum BasicOperatingMode { + /// Normal mode, when all operations are allowed. + Normal, + /// The pallet is halted. All operations (except operating mode change) are prohibited. + Halted, +} + +impl Default for BasicOperatingMode { + fn default() -> Self { + Self::Normal + } +} + +impl OperatingMode for BasicOperatingMode { + fn is_halted(&self) -> bool { + *self == BasicOperatingMode::Halted + } +} + +/// Bridge module that has owner and operating mode +pub trait OwnedBridgeModule { + /// The target that will be used when publishing logs related to this module. + const LOG_TARGET: &'static str; + + type OwnerStorage: StorageValue>; + type OperatingMode: OperatingMode; + type OperatingModeStorage: StorageValue; + + /// Check if the module is halted. + fn is_halted() -> bool { + Self::OperatingModeStorage::get().is_halted() + } + + /// Ensure that the origin is either root, or `PalletOwner`. + fn ensure_owner_or_root(origin: T::Origin) -> Result<(), BadOrigin> { + match origin.into() { + Ok(RawOrigin::Root) => Ok(()), + Ok(RawOrigin::Signed(ref signer)) + if Self::OwnerStorage::get().as_ref() == Some(signer) => + Ok(()), + _ => Err(BadOrigin), + } + } + + /// Ensure that the module is not halted. + fn ensure_not_halted() -> Result<(), OwnedBridgeModuleError> { + match Self::is_halted() { + true => Err(OwnedBridgeModuleError::Halted), + false => Ok(()), + } + } + + /// Change the owner of the module. + fn set_owner(origin: T::Origin, maybe_owner: Option) -> DispatchResult { + Self::ensure_owner_or_root(origin)?; + match maybe_owner { + Some(owner) => { + Self::OwnerStorage::put(&owner); + log::info!(target: Self::LOG_TARGET, "Setting pallet Owner to: {:?}", owner); + }, + None => { + Self::OwnerStorage::kill(); + log::info!(target: Self::LOG_TARGET, "Removed Owner of pallet."); + }, + } + + Ok(()) + } + + /// Halt or resume all/some module operations. + fn set_operating_mode( + origin: T::Origin, + operating_mode: Self::OperatingMode, + ) -> DispatchResult { + Self::ensure_owner_or_root(origin)?; + Self::OperatingModeStorage::put(operating_mode); + log::info!(target: Self::LOG_TARGET, "Setting operating mode to {:?}.", operating_mode); + Ok(()) + } +} + +/// A trait for querying whether a runtime call is valid. +pub trait FilterCall { + /// Checks if a runtime call is valid. + fn validate(call: &Call) -> TransactionValidity; +} + #[cfg(test)] mod tests { use super::*; diff --git a/primitives/runtime/src/storage_proof.rs b/primitives/runtime/src/storage_proof.rs index 4a99ab6210..277456709f 100644 --- a/primitives/runtime/src/storage_proof.rs +++ b/primitives/runtime/src/storage_proof.rs @@ -16,10 +16,30 @@ //! Logic for checking Substrate storage proofs. +use codec::Decode; use hash_db::{HashDB, Hasher, EMPTY_PREFIX}; use sp_runtime::RuntimeDebug; -use sp_std::vec::Vec; -use sp_trie::{read_trie_value, LayoutV1, MemoryDB, StorageProof}; +use sp_std::{boxed::Box, vec::Vec}; +use sp_trie::{ + read_trie_value, LayoutV1, MemoryDB, Recorder, StorageProof, Trie, TrieConfiguration, + TrieDBBuilder, TrieError, TrieHash, +}; + +/// Storage proof size requirements. +/// +/// This is currently used by benchmarks when generating storage proofs. +#[derive(Clone, Copy, Debug)] +pub enum ProofSize { + /// The proof is expected to be minimal. If value size may be changed, then it is expected to + /// have given size. + Minimal(u32), + /// The proof is expected to have at least given size and grow by increasing number of trie + /// nodes included in the proof. + HasExtraNodes(u32), + /// The proof is expected to have at least given size and grow by increasing value that is + /// stored in the trie. + HasLargeLeaf(u32), +} /// This struct is used to read storage values from a subset of a Merklized database. The "proof" /// is a subset of the nodes in the Merkle structure of the database, so that it provides @@ -50,18 +70,29 @@ where } /// Reads a value from the available subset of storage. If the value cannot be read due to an - /// incomplete or otherwise invalid proof, this returns an error. + /// incomplete or otherwise invalid proof, this function returns an error. pub fn read_value(&self, key: &[u8]) -> Result>, Error> { // LayoutV1 or LayoutV0 is identical for proof that only read values. - read_trie_value::, _>(&self.db, &self.root, key) + read_trie_value::, _>(&self.db, &self.root, key, None, None) .map_err(|_| Error::StorageValueUnavailable) } + + /// Reads and decodes a value from the available subset of storage. If the value cannot be read + /// due to an incomplete or otherwise invalid proof, this function returns an error. If value is + /// read, but decoding fails, this function returns an error. + pub fn read_and_decode_value(&self, key: &[u8]) -> Result, Error> { + self.read_value(key).and_then(|v| { + v.map(|v| T::decode(&mut &v[..]).map_err(Error::StorageValueDecodeFailed)) + .transpose() + }) + } } -#[derive(RuntimeDebug, PartialEq)] +#[derive(Eq, RuntimeDebug, PartialEq)] pub enum Error { StorageRootMismatch, StorageValueUnavailable, + StorageValueDecodeFailed(codec::Error), } /// Return valid storage proof and state root. @@ -69,6 +100,7 @@ pub enum Error { /// NOTE: This should only be used for **testing**. #[cfg(feature = "std")] pub fn craft_valid_storage_proof() -> (sp_core::H256, StorageProof) { + use codec::Encode; use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; let state_version = sp_runtime::StateVersion::default(); @@ -79,6 +111,7 @@ pub fn craft_valid_storage_proof() -> (sp_core::H256, StorageProof) { (None, vec![(b"key1".to_vec(), Some(b"value1".to_vec()))]), (None, vec![(b"key2".to_vec(), Some(b"value2".to_vec()))]), (None, vec![(b"key3".to_vec(), Some(b"value3".to_vec()))]), + (None, vec![(b"key4".to_vec(), Some((42u64, 42u32, 42u16, 42u8).encode()))]), // Value is too big to fit in a branch node (None, vec![(b"key11".to_vec(), Some(vec![0u8; 32]))]), ], @@ -86,7 +119,7 @@ pub fn craft_valid_storage_proof() -> (sp_core::H256, StorageProof) { )); let root = backend.storage_root(std::iter::empty(), state_version).0; let proof = StorageProof::new( - prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key22"[..]]) + prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key4"[..], &b"key22"[..]]) .unwrap() .iter_nodes(), ); @@ -94,9 +127,28 @@ pub fn craft_valid_storage_proof() -> (sp_core::H256, StorageProof) { (root, proof) } +/// Record all keys for a given root. +pub fn record_all_keys( + db: &DB, + root: &TrieHash, + recorder: &mut Recorder, +) -> Result<(), Box>> +where + DB: hash_db::HashDBRef, +{ + let trie = TrieDBBuilder::::new(db, root).with_recorder(recorder).build(); + for x in trie.iter()? { + let (key, _) = x?; + trie.get(&key)?; + } + + Ok(()) +} + #[cfg(test)] pub mod tests { use super::*; + use codec::Encode; #[test] fn storage_proof_check() { @@ -107,8 +159,14 @@ pub mod tests { >::new(root, proof.clone()).unwrap(); assert_eq!(checker.read_value(b"key1"), Ok(Some(b"value1".to_vec()))); assert_eq!(checker.read_value(b"key2"), Ok(Some(b"value2".to_vec()))); + assert_eq!(checker.read_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8).encode()))); assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable)); assert_eq!(checker.read_value(b"key22"), Ok(None)); + assert_eq!(checker.read_and_decode_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8))),); + assert!(matches!( + checker.read_and_decode_value::<[u8; 64]>(b"key4"), + Err(Error::StorageValueDecodeFailed(_)), + )); // checking proof against invalid commitment fails assert_eq!( diff --git a/primitives/test-utils/Cargo.toml b/primitives/test-utils/Cargo.toml index 6da5c7c0f4..0a59133457 100644 --- a/primitives/test-utils/Cargo.toml +++ b/primitives/test-utils/Cargo.toml @@ -7,9 +7,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] bp-header-chain = { path = "../header-chain", default-features = false } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } ed25519-dalek = { version = "1.0", default-features = false, features = ["u64_backend"] } -finality-grandpa = { version = "0.15.0", default-features = false } +finality-grandpa = { version = "0.16.0", default-features = false } sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } diff --git a/primitives/test-utils/src/keyring.rs b/primitives/test-utils/src/keyring.rs index 2436d79339..f827c72943 100644 --- a/primitives/test-utils/src/keyring.rs +++ b/primitives/test-utils/src/keyring.rs @@ -43,7 +43,7 @@ impl Account { pub fn secret(&self) -> SecretKey { let data = self.0.encode(); let mut bytes = [0_u8; 32]; - bytes[0..data.len()].copy_from_slice(&*data); + bytes[0..data.len()].copy_from_slice(&data); SecretKey::from_bytes(&bytes) .expect("A static array of the correct length is a known good.") } diff --git a/primitives/test-utils/src/lib.rs b/primitives/test-utils/src/lib.rs index 9e044ed472..66dbe9e738 100644 --- a/primitives/test-utils/src/lib.rs +++ b/primitives/test-utils/src/lib.rs @@ -20,7 +20,6 @@ use bp_header_chain::justification::GrandpaJustification; use codec::Encode; -use sp_application_crypto::TryFrom; use sp_finality_grandpa::{AuthorityId, AuthoritySignature, AuthorityWeight, SetId}; use sp_runtime::traits::{Header as HeaderT, One, Zero}; use sp_std::prelude::*; @@ -211,3 +210,92 @@ pub fn test_header(number: H::Number) -> H { pub fn header_id(index: u8) -> (H::Hash, H::Number) { (test_header::(index.into()).hash(), index.into()) } + +#[macro_export] +/// Adds methods for testing the `set_owner()` and `set_operating_mode()` for a pallet. +/// Some values are hardcoded like: +/// - `run_test()` +/// - `Pallet::` +/// - `PalletOwner::` +/// - `PalletOperatingMode::` +/// While this is not ideal, all the pallets use the same names, so it works for the moment. +/// We can revisit this in the future if anything changes. +macro_rules! generate_owned_bridge_module_tests { + ($normal_operating_mode: expr, $halted_operating_mode: expr) => { + #[test] + fn test_set_owner() { + run_test(|| { + PalletOwner::::put(1); + + // The root should be able to change the owner. + assert_ok!(Pallet::::set_owner(Origin::root(), Some(2))); + assert_eq!(PalletOwner::::get(), Some(2)); + + // The owner should be able to change the owner. + assert_ok!(Pallet::::set_owner(Origin::signed(2), Some(3))); + assert_eq!(PalletOwner::::get(), Some(3)); + + // Other users shouldn't be able to change the owner. + assert_noop!( + Pallet::::set_owner(Origin::signed(1), Some(4)), + DispatchError::BadOrigin + ); + assert_eq!(PalletOwner::::get(), Some(3)); + }); + } + + #[test] + fn test_set_operating_mode() { + run_test(|| { + PalletOwner::::put(1); + PalletOperatingMode::::put($normal_operating_mode); + + // The root should be able to halt the pallet. + assert_ok!(Pallet::::set_operating_mode( + Origin::root(), + $halted_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $halted_operating_mode); + // The root should be able to resume the pallet. + assert_ok!(Pallet::::set_operating_mode( + Origin::root(), + $normal_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $normal_operating_mode); + + // The owner should be able to halt the pallet. + assert_ok!(Pallet::::set_operating_mode( + Origin::signed(1), + $halted_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $halted_operating_mode); + // The owner should be able to resume the pallet. + assert_ok!(Pallet::::set_operating_mode( + Origin::signed(1), + $normal_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $normal_operating_mode); + + // Other users shouldn't be able to halt the pallet. + assert_noop!( + Pallet::::set_operating_mode( + Origin::signed(2), + $halted_operating_mode + ), + DispatchError::BadOrigin + ); + assert_eq!(PalletOperatingMode::::get(), $normal_operating_mode); + // Other users shouldn't be able to resume the pallet. + PalletOperatingMode::::put($halted_operating_mode); + assert_noop!( + Pallet::::set_operating_mode( + Origin::signed(2), + $normal_operating_mode + ), + DispatchError::BadOrigin + ); + assert_eq!(PalletOperatingMode::::get(), $halted_operating_mode); + }); + } + }; +} diff --git a/primitives/token-swap/Cargo.toml b/primitives/token-swap/Cargo.toml deleted file mode 100644 index 9097856f85..0000000000 --- a/primitives/token-swap/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "bp-token-swap" -description = "Primitives of the pallet-bridge-token-swap pallet" -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2021" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } - -# Bridge Dependencies - -bp-runtime = { path = "../runtime", default-features = false } - -# Substrate Dependencies - -frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } - -[dev-dependencies] -hex = "0.4" -hex-literal = "0.3" - -[features] -default = ["std"] -std = [ - "bp-runtime/std", - "codec/std", - "frame-support/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-std/std", -] diff --git a/primitives/token-swap/src/lib.rs b/primitives/token-swap/src/lib.rs deleted file mode 100644 index 79363e5477..0000000000 --- a/primitives/token-swap/src/lib.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] - -pub mod storage_keys; - -use codec::{Decode, Encode}; -use frame_support::{weights::Weight, RuntimeDebug}; -use scale_info::TypeInfo; -use sp_core::{H256, U256}; -use sp_io::hashing::blake2_256; -use sp_std::vec::Vec; - -/// Pending token swap state. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] -pub enum TokenSwapState { - /// The swap has been started using the `start_claim` call, but we have no proof that it has - /// happened at the Bridged chain. - Started, - /// The swap has happened at the Bridged chain and may be claimed by the Bridged chain party - /// using the `claim_swap` call. - Confirmed, - /// The swap has failed at the Bridged chain and This chain party may cancel it using the - /// `cancel_swap` call. - Failed, -} - -/// Token swap type. -/// -/// Different swap types give a different guarantees regarding possible swap -/// replay protection. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] -pub enum TokenSwapType { - /// The `target_account_at_bridged_chain` is temporary and only have funds for single swap. - /// - /// ***WARNING**: if `target_account_at_bridged_chain` still exists after the swap has been - /// completed (either by claiming or canceling), the `source_account_at_this_chain` will be - /// able to restart the swap again and repeat the swap until `target_account_at_bridged_chain` - /// depletes. - TemporaryTargetAccountAtBridgedChain, - /// This swap type prevents `source_account_at_this_chain` from restarting the swap after it - /// has been completed. There are two consequences: - /// - /// 1) the `source_account_at_this_chain` won't be able to call `start_swap` after given - /// ; 2) the `target_account_at_bridged_chain` won't be able to call - /// `claim_swap` (over the bridge) before block ``. - /// - /// The second element is the nonce of the swap. You must care about its uniqueness if you're - /// planning to perform another swap with exactly the same parameters (i.e. same amount, same - /// accounts, same `ThisBlockNumber`) to avoid collisions. - LockClaimUntilBlock(ThisBlockNumber, U256), -} - -/// An intention to swap `source_balance_at_this_chain` owned by `source_account_at_this_chain` -/// to `target_balance_at_bridged_chain` owned by `target_account_at_bridged_chain`. -/// -/// **IMPORTANT NOTE**: this structure is always the same during single token swap. So even -/// when chain changes, the meaning of This and Bridged are still used to point to the same chains. -/// This chain is always the chain where swap has been started. And the Bridged chain is the other -/// chain. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] -pub struct TokenSwap -{ - /// The type of the swap. - pub swap_type: TokenSwapType, - /// This chain balance to be swapped with `target_balance_at_bridged_chain`. - pub source_balance_at_this_chain: ThisBalance, - /// Account id of the party acting at This chain and owning the `source_account_at_this_chain`. - pub source_account_at_this_chain: ThisAccountId, - /// Bridged chain balance to be swapped with `source_balance_at_this_chain`. - pub target_balance_at_bridged_chain: BridgedBalance, - /// Account id of the party acting at the Bridged chain and owning the - /// `target_balance_at_bridged_chain`. - pub target_account_at_bridged_chain: BridgedAccountId, -} - -impl - TokenSwap -where - TokenSwap: - Encode, -{ - /// Returns hash, used to identify this token swap. - pub fn hash(&self) -> H256 { - self.using_encoded(blake2_256).into() - } -} - -/// SCALE-encoded `Currency::transfer` call on the bridged chain. -pub type RawBridgedTransferCall = Vec; - -/// Token swap creation parameters. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] -pub struct TokenSwapCreation { - /// Public key of the `target_account_at_bridged_chain` account used to verify - /// `bridged_currency_transfer_signature`. - pub target_public_at_bridged_chain: BridgedAccountPublic, - /// Fee that the `source_account_at_this_chain` is ready to pay for the tokens - /// transfer message delivery and dispatch. - pub swap_delivery_and_dispatch_fee: ThisChainBalance, - /// Specification version of the Bridged chain. - pub bridged_chain_spec_version: u32, - /// SCALE-encoded tokens transfer call at the Bridged chain. - pub bridged_currency_transfer: RawBridgedTransferCall, - /// Dispatch weight of the tokens transfer call at the Bridged chain. - pub bridged_currency_transfer_weight: Weight, - /// The signature of the `target_account_at_bridged_chain` for the message - /// returned by the `pallet_bridge_dispatch::account_ownership_digest()` function call. - pub bridged_currency_transfer_signature: BridgedAccountSignature, -} diff --git a/primitives/token-swap/src/storage_keys.rs b/primitives/token-swap/src/storage_keys.rs deleted file mode 100644 index d0aafc0d5c..0000000000 --- a/primitives/token-swap/src/storage_keys.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Storage keys of bridge token swap pallet. - -use frame_support::Identity; -use sp_core::{storage::StorageKey, H256}; - -/// Name of the `PendingSwaps` storage map. -pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps"; - -/// Storage key of `PendingSwaps` value with given token swap hash. -pub fn pending_swaps_key(pallet_prefix: &str, token_swap_hash: H256) -> StorageKey { - bp_runtime::storage_map_final_key::( - pallet_prefix, - PENDING_SWAPS_MAP_NAME, - token_swap_hash.as_ref(), - ) -} - -#[cfg(test)] -mod tests { - use super::*; - use hex_literal::hex; - - #[test] - fn pending_swaps_key_computed_properly() { - // If this test fails, then something has been changed in module storage that may break - // all previous swaps. - let storage_key = pending_swaps_key("BridgeTokenSwap", [42u8; 32].into()).0; - assert_eq!( - storage_key, - hex!("76276da64e7a4f454760eedeb4bad11adca2227fef56ad07cc424f1f5d128b9a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a").to_vec(), - "Unexpected storage key: {}", - hex::encode(&storage_key), - ); - } -} diff --git a/relays/bin-substrate/Cargo.toml b/relays/bin-substrate/Cargo.toml index fb8ff467d0..2a463fff60 100644 --- a/relays/bin-substrate/Cargo.toml +++ b/relays/bin-substrate/Cargo.toml @@ -8,14 +8,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] anyhow = "1.0" async-std = "1.9.0" -async-trait = "0.1.42" -codec = { package = "parity-scale-codec", version = "3.0.0" } +async-trait = "0.1" +codec = { package = "parity-scale-codec", version = "3.1.5" } futures = "0.3.12" hex = "0.4" -log = "0.4.14" +log = "0.4.17" num-format = "0.4" num-traits = "0.2" -paste = "1.0" rand = "0.8" structopt = "0.3" strum = { version = "0.21.0", features = ["derive"] } @@ -23,33 +22,24 @@ strum = { version = "0.21.0", features = ["derive"] } # Bridge dependencies bp-header-chain = { path = "../../primitives/header-chain" } -bp-kusama = { path = "../../primitives/chain-kusama" } bp-messages = { path = "../../primitives/messages" } -bp-message-dispatch = { path = "../../primitives/message-dispatch" } bp-millau = { path = "../../primitives/chain-millau" } -bp-polkadot = { path = "../../primitives/chain-polkadot" } +bp-parachains = { path = "../../primitives/parachains" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } bp-rialto = { path = "../../primitives/chain-rialto" } bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" } -bp-rococo = { path = "../../primitives/chain-rococo" } bp-runtime = { path = "../../primitives/runtime" } -bp-token-swap = { path = "../../primitives/token-swap" } bp-westend = { path = "../../primitives/chain-westend" } -bp-wococo = { path = "../../primitives/chain-wococo" } bridge-runtime-common = { path = "../../bin/runtime-common" } finality-relay = { path = "../finality" } messages-relay = { path = "../messages" } millau-runtime = { path = "../../bin/millau/runtime" } -pallet-bridge-dispatch = { path = "../../modules/dispatch" } -pallet-bridge-grandpa = { path = "../../modules/grandpa" } pallet-bridge-messages = { path = "../../modules/messages" } -pallet-bridge-token-swap = { path = "../../modules/token-swap" } -relay-kusama-client = { path = "../client-kusama" } +pallet-bridge-parachains = { path = "../../modules/parachains" } +parachains-relay = { path = "../parachains" } relay-millau-client = { path = "../client-millau" } -relay-polkadot-client = { path = "../client-polkadot" } relay-rialto-client = { path = "../client-rialto" } relay-rialto-parachain-client = { path = "../client-rialto-parachain" } -relay-rococo-client = { path = "../client-rococo" } -relay-wococo-client = { path = "../client-wococo" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } relay-westend-client = { path = "../client-westend" } @@ -68,15 +58,16 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master # Polkadot Dependencies -polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3" } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "gav-xcm-v3", default-features = false } + [dev-dependencies] bp-test-utils = { path = "../../primitives/test-utils" } hex-literal = "0.3" -pallet-bridge-grandpa = { path = "../../modules/grandpa" } sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } tempfile = "3.2" -finality-grandpa = { version = "0.15.0" } +finality-grandpa = { version = "0.16.0" } diff --git a/relays/bin-substrate/src/chains/kusama.rs b/relays/bin-substrate/src/chains/kusama.rs deleted file mode 100644 index 9cdc6cd125..0000000000 --- a/relays/bin-substrate/src/chains/kusama.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use anyhow::anyhow; -use bp_message_dispatch::{CallOrigin, MessagePayload}; -use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; -use relay_kusama_client::Kusama; -use sp_version::RuntimeVersion; - -use crate::cli::{ - bridge, - encode_call::{self, Call, CliEncodeCall}, - encode_message, - send_message::{self, DispatchFeePayment}, - CliChain, -}; - -/// Weight of the `system::remark` call at Kusama. -/// -/// This weight is larger (x2) than actual weight at current Kusama runtime to avoid unsuccessful -/// calls in the future. But since it is used only in tests (and on test chains), this is ok. -pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000; - -impl CliEncodeCall for Kusama { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()), - Call::Remark { remark_payload, .. } => relay_kusama_client::runtime::Call::System( - relay_kusama_client::runtime::SystemCall::remark( - remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - ), - ) - .into(), - Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } => - match *bridge_instance_index { - bridge::KUSAMA_TO_POLKADOT_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - relay_kusama_client::runtime::Call::BridgePolkadotMessages( - relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message( - lane.0, payload, fee.0, - ), - ) - .into() - }, - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, - _ => anyhow::bail!("Unsupported Kusama call: {:?}", call), - }) - } - - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - match *call { - EncodedOrDecodedCall::Decoded(relay_kusama_client::runtime::Call::System( - relay_kusama_client::runtime::SystemCall::remark(_), - )) => Ok(DispatchInfo { - weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT, - class: DispatchClass::Normal, - pays_fee: Pays::Yes, - }), - _ => anyhow::bail!("Unsupported Kusama call: {:?}", call), - } - } -} - -impl CliChain for Kusama { - const RUNTIME_VERSION: RuntimeVersion = bp_kusama::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_kusama::AccountId, - bp_polkadot::AccountPublic, - bp_polkadot::Signature, - Vec, - >; - - fn ss58_format() -> u16 { - sp_core::crypto::Ss58AddressFormat::from( - sp_core::crypto::Ss58AddressFormatRegistry::KusamaAccount, - ) - .into() - } - - fn encode_message( - message: encode_message::MessagePayload, - ) -> anyhow::Result { - match message { - encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| anyhow!("Failed to decode Kusama's MessagePayload: {:?}", e)), - encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => { - type Source = Kusama; - type Target = relay_polkadot_client::Polkadot; - - sender.enforce_chain::(); - let spec_version = Target::RUNTIME_VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::( - &mut call, - bridge::KUSAMA_TO_POLKADOT_INDEX, - ); - let call = Target::encode_call(&call)?; - let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| { - Err(anyhow::format_err!( - "Please specify dispatch weight of the encoded Polkadot call" - )) - })?; - - Ok(send_message::message_payload( - spec_version, - dispatch_weight, - origin, - &call, - DispatchFeePayment::AtSourceChain, - )) - }, - } - } -} diff --git a/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs b/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs deleted file mode 100644 index 0c0ba2272c..0000000000 --- a/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Kusama-to-Polkadot headers sync entrypoint. - -use async_trait::async_trait; -use relay_polkadot_client::Polkadot; -use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; - -/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat -/// relay as gone wild. -/// -/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 21 -/// DOT, and initial value of this constant was rounded up to 30 DOT. But for actual Kusama <> -/// Polkadot deployment we'll be using the same account for delivering finality (free for mandatory -/// headers) and messages. It means that we can't predict maximal loss. But to protect funds against -/// relay/deployment issues, let's limit it so something that is much larger than this estimation - -/// e.g. to 100 DOT. -// TODO: https://github.com/paritytech/parity-bridges-common/issues/1307 -pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 100 * 10_000_000_000; - -/// Description of Kusama -> Polkadot finalized headers bridge. -#[derive(Clone, Debug)] -pub struct KusamaFinalityToPolkadot; -substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( - KusamaFinalityToPolkadot, - KusamaFinalityToPolkadotCallBuilder, - relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa, - relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof -); - -#[async_trait] -impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot { - type SourceChain = relay_kusama_client::Kusama; - type TargetChain = Polkadot; - - type SubmitFinalityProofCallBuilder = KusamaFinalityToPolkadotCallBuilder; - type TransactionSignScheme = Polkadot; - - async fn start_relay_guards( - target_client: &relay_substrate_client::Client, - transaction_params: &TransactionParams, - enable_version_guard: bool, - ) -> relay_substrate_client::Result<()> { - substrate_relay_helper::finality_guards::start::( - target_client, - transaction_params, - enable_version_guard, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ) - .await - } -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use frame_support::weights::WeightToFeePolynomial; - use pallet_bridge_grandpa::weights::WeightInfo; - - pub fn compute_maximal_balance_decrease_per_day(expected_source_headers_per_day: u32) -> B - where - B: From + std::ops::Mul, - W: WeightToFeePolynomial, - { - // we assume that the GRANDPA is not lagging here => ancestry length will be near to 0 - // (let's round up to 2) - const AVG_VOTES_ANCESTRIES_LEN: u32 = 2; - // let's assume number of validators is 1024 (more than on any existing well-known chain - // atm) => number of precommits is *2/3 + 1 - const AVG_PRECOMMITS_LEN: u32 = 1024 * 2 / 3 + 1; - - // GRANDPA pallet weights. We're now using Rialto weights everywhere. - // - // Using Rialto runtime is slightly incorrect, because `DbWeight` of other runtimes may - // differ from the `DbWeight` of Rialto runtime. But now (and most probably forever) it is - // the same. - type GrandpaPalletWeights = - pallet_bridge_grandpa::weights::MillauWeight; - - // The following formula shall not be treated as super-accurate - guard is to protect from - // mad relays, not to protect from over-average loses. - - // increase number of headers a bit - let expected_source_headers_per_day = expected_source_headers_per_day * 110 / 100; - let single_source_header_submit_call_weight = GrandpaPalletWeights::submit_finality_proof( - AVG_VOTES_ANCESTRIES_LEN, - AVG_PRECOMMITS_LEN, - ); - // for simplicity - add extra weight for base tx fee + fee that is paid for the tx size + - // adjusted fee - let single_source_header_submit_tx_weight = single_source_header_submit_call_weight * 3 / 2; - let single_source_header_tx_cost = W::calc(&single_source_header_submit_tx_weight); - single_source_header_tx_cost * B::from(expected_source_headers_per_day) - } - - #[test] - fn maximal_balance_decrease_per_day_is_sane() { - // we expect Kusama -> Polkadot relay to be running in mandatory-headers-only mode - // => we expect single header for every Kusama session - let maximal_balance_decrease = compute_maximal_balance_decrease_per_day::< - bp_polkadot::Balance, - bp_polkadot::WeightToFee, - >(bp_kusama::DAYS / bp_kusama::SESSION_LENGTH + 1); - assert!( - MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_balance_decrease, - "Maximal expected loss per day {} is larger than hardcoded {}", - maximal_balance_decrease, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ); - } -} diff --git a/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs b/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs deleted file mode 100644 index 9a71fbe3c6..0000000000 --- a/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Kusama-to-Polkadot messages sync entrypoint. - -use frame_support::weights::Weight; - -use messages_relay::relay_strategy::MixStrategy; -use relay_kusama_client::Kusama; -use relay_polkadot_client::Polkadot; -use substrate_relay_helper::messages_lane::SubstrateMessageLane; - -/// Description of Kusama -> Polkadot messages bridge. -#[derive(Clone, Debug)] -pub struct KusamaMessagesToPolkadot; -substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( - KusamaMessagesToPolkadot, - KusamaMessagesToPolkadotReceiveMessagesProofCallBuilder, - relay_polkadot_client::runtime::Call::BridgeKusamaMessages, - relay_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_proof -); -substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( - KusamaMessagesToPolkadot, - KusamaMessagesToPolkadotReceiveMessagesDeliveryProofCallBuilder, - relay_kusama_client::runtime::Call::BridgePolkadotMessages, - relay_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_delivery_proof -); -substrate_relay_helper::generate_mocked_update_conversion_rate_call_builder!( - Kusama, - KusamaMessagesToPolkadotUpdateConversionRateCallBuilder, - relay_kusama_client::runtime::Call::BridgePolkadotMessages, - relay_kusama_client::runtime::BridgePolkadotMessagesCall::update_pallet_parameter, - relay_kusama_client::runtime::BridgePolkadotMessagesParameter::PolkadotToKusamaConversionRate -); - -impl SubstrateMessageLane for KusamaMessagesToPolkadot { - const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = - Some(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME); - const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = - Some(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME); - - const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = - Some(bp_polkadot::KUSAMA_FEE_MULTIPLIER_PARAMETER_NAME); - const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = - Some(bp_kusama::POLKADOT_FEE_MULTIPLIER_PARAMETER_NAME); - - const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = - Some(bp_kusama::TRANSACTION_PAYMENT_PALLET_NAME); - const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = - Some(bp_polkadot::TRANSACTION_PAYMENT_PALLET_NAME); - - type SourceChain = Kusama; - type TargetChain = Polkadot; - - type SourceTransactionSignScheme = Kusama; - type TargetTransactionSignScheme = Polkadot; - - type ReceiveMessagesProofCallBuilder = KusamaMessagesToPolkadotReceiveMessagesProofCallBuilder; - type ReceiveMessagesDeliveryProofCallBuilder = - KusamaMessagesToPolkadotReceiveMessagesDeliveryProofCallBuilder; - - type TargetToSourceChainConversionRateUpdateBuilder = - KusamaMessagesToPolkadotUpdateConversionRateCallBuilder; - - type RelayStrategy = MixStrategy; -} diff --git a/relays/bin-substrate/src/chains/millau.rs b/relays/bin-substrate/src/chains/millau.rs index 1fc1e8308e..b71ecb288e 100644 --- a/relays/bin-substrate/src/chains/millau.rs +++ b/relays/bin-substrate/src/chains/millau.rs @@ -18,57 +18,74 @@ use crate::cli::{ bridge, - encode_call::{self, Call, CliEncodeCall}, - encode_message, - send_message::{self, DispatchFeePayment}, + encode_message::{CliEncodeMessage, RawMessage}, CliChain, }; -use anyhow::anyhow; -use bp_message_dispatch::{CallOrigin, MessagePayload}; +use bp_messages::LaneId; +use bp_rialto_parachain::RIALTO_PARACHAIN_ID; use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchInfo, GetDispatchInfo}; use relay_millau_client::Millau; +use relay_substrate_client::BalanceOf; use sp_version::RuntimeVersion; +use xcm::latest::prelude::*; -impl CliEncodeCall for Millau { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(), - Call::Remark { remark_payload, .. } => - millau_runtime::Call::System(millau_runtime::SystemCall::remark { - remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - }) - .into(), - Call::Transfer { recipient, amount } => - millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer { - dest: recipient.raw_id(), - value: amount.cast(), - }) - .into(), - Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } => - match *bridge_instance_index { - bridge::MILLAU_TO_RIALTO_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - millau_runtime::Call::BridgeRialtoMessages( - millau_runtime::MessagesCall::send_message { - lane_id: lane.0, - payload, - delivery_and_dispatch_fee: fee.cast(), - }, - ) - .into() - }, - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, +impl CliEncodeMessage for Millau { + fn encode_send_xcm( + message: xcm::VersionedXcm<()>, + bridge_instance_index: u8, + ) -> anyhow::Result> { + let dest = match bridge_instance_index { + bridge::MILLAU_TO_RIALTO_INDEX => + (Parent, X1(GlobalConsensus(millau_runtime::xcm_config::RialtoNetwork::get()))), + bridge::MILLAU_TO_RIALTO_PARACHAIN_INDEX => ( + Parent, + X2( + GlobalConsensus(millau_runtime::xcm_config::RialtoNetwork::get()), + Parachain(RIALTO_PARACHAIN_ID), + ), + ), + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }; + + Ok(millau_runtime::Call::XcmPallet(millau_runtime::XcmCall::send { + dest: Box::new(dest.into()), + message: Box::new(message), }) + .into()) } - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - Ok(call.to_decoded()?.get_dispatch_info()) + fn encode_send_message_call( + lane: LaneId, + payload: RawMessage, + fee: BalanceOf, + bridge_instance_index: u8, + ) -> anyhow::Result> { + Ok(match bridge_instance_index { + bridge::MILLAU_TO_RIALTO_INDEX => millau_runtime::Call::BridgeRialtoMessages( + millau_runtime::MessagesCall::send_message { + lane_id: lane, + payload, + delivery_and_dispatch_fee: fee, + }, + ) + .into(), + bridge::MILLAU_TO_RIALTO_PARACHAIN_INDEX => + millau_runtime::Call::BridgeRialtoParachainMessages( + millau_runtime::MessagesCall::send_message { + lane_id: lane, + payload, + delivery_and_dispatch_fee: fee, + }, + ) + .into(), + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }) } } @@ -76,48 +93,9 @@ impl CliChain for Millau { const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION; type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_millau::AccountId, - bp_rialto::AccountSigner, - bp_rialto::Signature, - Vec, - >; + type MessagePayload = Vec; fn ss58_format() -> u16 { millau_runtime::SS58Prefix::get() as u16 } - - // TODO [#854|#843] support multiple bridges? - fn encode_message( - message: encode_message::MessagePayload, - ) -> anyhow::Result { - match message { - encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| anyhow!("Failed to decode Millau's MessagePayload: {:?}", e)), - encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => { - type Source = Millau; - type Target = relay_rialto_client::Rialto; - - sender.enforce_chain::(); - let spec_version = Target::RUNTIME_VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::( - &mut call, - bridge::MILLAU_TO_RIALTO_INDEX, - ); - let call = Target::encode_call(&call)?; - let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| { - call.to_decoded().map(|call| call.get_dispatch_info().weight) - })?; - - Ok(send_message::message_payload( - spec_version, - dispatch_weight, - origin, - &call, - DispatchFeePayment::AtSourceChain, - )) - }, - } - } } diff --git a/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs b/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs index 584f0a9bb1..0aa49bdada 100644 --- a/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs +++ b/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs @@ -16,8 +16,10 @@ //! Millau-to-Rialto headers sync entrypoint. -use substrate_relay_helper::finality_pipeline::{ - DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, }; /// Description of Millau -> Rialto finalized headers bridge. @@ -28,10 +30,29 @@ impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { type SourceChain = relay_millau_client::Millau; type TargetChain = relay_rialto_client::Rialto; - type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< Self, rialto_runtime::Runtime, rialto_runtime::MillauGrandpaInstance, >; type TransactionSignScheme = relay_rialto_client::Rialto; } + +//// `Millau` to `Rialto` bridge definition. +pub struct MillauToRialtoCliBridge {} + +impl CliBridgeBase for MillauToRialtoCliBridge { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_client::Rialto; +} + +impl RelayToRelayHeadersCliBridge for MillauToRialtoCliBridge { + type Finality = MillauFinalityToRialto; +} + +impl MessagesCliBridge for MillauToRialtoCliBridge { + const ESTIMATE_MESSAGE_FEE_METHOD: &'static str = + bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; + type MessagesLane = crate::chains::millau_messages_to_rialto::MillauMessagesToRialto; +} diff --git a/relays/bin-substrate/src/chains/millau_headers_to_rialto_parachain.rs b/relays/bin-substrate/src/chains/millau_headers_to_rialto_parachain.rs new file mode 100644 index 0000000000..4eaf3f6f75 --- /dev/null +++ b/relays/bin-substrate/src/chains/millau_headers_to_rialto_parachain.rs @@ -0,0 +1,77 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Millau-to-RialtoParachain headers sync entrypoint. + +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Millau-to-RialtoParachain headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, +}; + +/// Description of Millau -> Rialto finalized headers bridge. +#[derive(Clone, Debug)] +pub struct MillauFinalityToRialtoParachain; + +impl SubstrateFinalitySyncPipeline for MillauFinalityToRialtoParachain { + type SourceChain = relay_millau_client::Millau; + type TargetChain = relay_rialto_parachain_client::RialtoParachain; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< + Self, + rialto_parachain_runtime::Runtime, + rialto_parachain_runtime::MillauGrandpaInstance, + >; + type TransactionSignScheme = relay_rialto_parachain_client::RialtoParachain; +} + +//// `Millau` to `RialtoParachain` bridge definition. +pub struct MillauToRialtoParachainCliBridge {} + +impl CliBridgeBase for MillauToRialtoParachainCliBridge { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_parachain_client::RialtoParachain; +} + +impl RelayToRelayHeadersCliBridge for MillauToRialtoParachainCliBridge { + type Finality = MillauFinalityToRialtoParachain; +} + +impl MessagesCliBridge for MillauToRialtoParachainCliBridge { + const ESTIMATE_MESSAGE_FEE_METHOD: &'static str = + bp_rialto_parachain::TO_RIALTO_PARACHAIN_ESTIMATE_MESSAGE_FEE_METHOD; + type MessagesLane = + crate::chains::millau_messages_to_rialto_parachain::MillauMessagesToRialtoParachain; +} diff --git a/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs b/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs new file mode 100644 index 0000000000..d5b42798dd --- /dev/null +++ b/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Millau-to-RialtoParachain messages sync entrypoint. + +use messages_relay::relay_strategy::MixStrategy; +use relay_millau_client::Millau; +use relay_rialto_parachain_client::RialtoParachain; +use substrate_relay_helper::messages_lane::{ + DirectReceiveMessagesDeliveryProofCallBuilder, DirectReceiveMessagesProofCallBuilder, + SubstrateMessageLane, +}; + +/// Description of Millau -> RialtoParachain messages bridge. +#[derive(Clone, Debug)] +pub struct MillauMessagesToRialtoParachain; +substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!( + Millau, + MillauMessagesToRialtoParachainUpdateConversionRateCallBuilder, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainMessagesInstance, + millau_runtime::rialto_parachain_messages::MillauToRialtoParachainMessagesParameter::RialtoParachainToMillauConversionRate +); + +impl SubstrateMessageLane for MillauMessagesToRialtoParachain { + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_rialto_parachain::MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME); + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_millau::RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME); + + const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_rialto_parachain::MILLAU_FEE_MULTIPLIER_PARAMETER_NAME); + const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_millau::RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME); + + const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_millau::TRANSACTION_PAYMENT_PALLET_NAME); + const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_rialto_parachain::TRANSACTION_PAYMENT_PALLET_NAME); + + type SourceChain = Millau; + type TargetChain = RialtoParachain; + + type SourceTransactionSignScheme = Millau; + type TargetTransactionSignScheme = RialtoParachain; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + rialto_parachain_runtime::Runtime, + rialto_parachain_runtime::WithMillauMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainMessagesInstance, + >; + + type TargetToSourceChainConversionRateUpdateBuilder = + MillauMessagesToRialtoParachainUpdateConversionRateCallBuilder; + + type RelayStrategy = MixStrategy; +} diff --git a/relays/bin-substrate/src/chains/mod.rs b/relays/bin-substrate/src/chains/mod.rs index 16901143e1..c1e963a63e 100644 --- a/relays/bin-substrate/src/chains/mod.rs +++ b/relays/bin-substrate/src/chains/mod.rs @@ -16,120 +16,46 @@ //! Chain-specific relayer configuration. -pub mod kusama_headers_to_polkadot; -pub mod kusama_messages_to_polkadot; pub mod millau_headers_to_rialto; +pub mod millau_headers_to_rialto_parachain; pub mod millau_messages_to_rialto; -pub mod polkadot_headers_to_kusama; -pub mod polkadot_messages_to_kusama; +pub mod millau_messages_to_rialto_parachain; pub mod rialto_headers_to_millau; pub mod rialto_messages_to_millau; -pub mod rococo_headers_to_wococo; -pub mod rococo_messages_to_wococo; +pub mod rialto_parachain_messages_to_millau; +pub mod rialto_parachains_to_millau; pub mod westend_headers_to_millau; -pub mod wococo_headers_to_rococo; -pub mod wococo_messages_to_rococo; +pub mod westend_parachains_to_millau; -mod kusama; mod millau; -mod polkadot; mod rialto; mod rialto_parachain; -mod rococo; mod westend; -mod wococo; #[cfg(test)] mod tests { - use crate::cli::{encode_call, send_message}; + use crate::cli::encode_message; use bp_messages::source_chain::TargetHeaderChain; use bp_runtime::Chain as _; use codec::Encode; - use frame_support::dispatch::GetDispatchInfo; use relay_millau_client::Millau; use relay_rialto_client::Rialto; use relay_substrate_client::{SignParam, TransactionSignScheme, UnsignedTransaction}; - use sp_core::Pair; - use sp_runtime::traits::{IdentifyAccount, Verify}; #[test] - fn millau_signature_is_valid_on_rialto() { - let millau_sign = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap(); - - let call = - rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { remark: vec![] }); - - let millau_public: bp_millau::AccountSigner = millau_sign.public().into(); - let millau_account_id: bp_millau::AccountId = millau_public.into_account(); - - let digest = millau_runtime::millau_to_rialto_account_ownership_digest( - &call, - millau_account_id, - rialto_runtime::VERSION.spec_version, - ); - - let rialto_signer = - relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap(); - let signature = rialto_signer.sign(&digest); - - assert!(signature.verify(&digest[..], &rialto_signer.public())); - } - - #[test] - fn rialto_signature_is_valid_on_millau() { - let rialto_sign = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap(); - - let call = - millau_runtime::Call::System(millau_runtime::SystemCall::remark { remark: vec![] }); - - let rialto_public: bp_rialto::AccountSigner = rialto_sign.public().into(); - let rialto_account_id: bp_rialto::AccountId = rialto_public.into_account(); - - let digest = rialto_runtime::rialto_to_millau_account_ownership_digest( - &call, - rialto_account_id, - millau_runtime::VERSION.spec_version, - ); - - let millau_signer = - relay_millau_client::SigningParams::from_string("//Dave", None).unwrap(); - let signature = millau_signer.sign(&digest); - - assert!(signature.verify(&digest[..], &millau_signer.public())); - } - - #[test] - fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() { + fn maximal_rialto_to_millau_message_size_is_computed_correctly() { use rialto_runtime::millau_messages::Millau; - let maximal_remark_size = encode_call::compute_maximal_message_arguments_size( + let maximal_message_size = encode_message::compute_maximal_message_size( bp_rialto::Rialto::max_extrinsic_size(), bp_millau::Millau::max_extrinsic_size(), ); - let call: millau_runtime::Call = - millau_runtime::SystemCall::remark { remark: vec![42; maximal_remark_size as _] } - .into(); - let payload = send_message::message_payload( - Default::default(), - call.get_dispatch_info().weight, - bp_message_dispatch::CallOrigin::SourceRoot, - &call, - send_message::DispatchFeePayment::AtSourceChain, - ); - assert_eq!(Millau::verify_message(&payload), Ok(())); + let message = vec![42; maximal_message_size as _]; + assert_eq!(Millau::verify_message(&message), Ok(())); - let call: millau_runtime::Call = - millau_runtime::SystemCall::remark { remark: vec![42; (maximal_remark_size + 1) as _] } - .into(); - let payload = send_message::message_payload( - Default::default(), - call.get_dispatch_info().weight, - bp_message_dispatch::CallOrigin::SourceRoot, - &call, - send_message::DispatchFeePayment::AtSourceChain, - ); - assert!(Millau::verify_message(&payload).is_err()); + let message = vec![42; (maximal_message_size + 1) as _]; + assert!(Millau::verify_message(&message).is_err()); } #[test] @@ -141,77 +67,19 @@ mod tests { "We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large", ) } - - #[test] - fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() { - use rialto_runtime::millau_messages::Millau; - - let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight( - bp_millau::Millau::max_extrinsic_weight(), - ); - let call: millau_runtime::Call = - rialto_runtime::SystemCall::remark { remark: vec![] }.into(); - - let payload = send_message::message_payload( - Default::default(), - maximal_dispatch_weight, - bp_message_dispatch::CallOrigin::SourceRoot, - &call, - send_message::DispatchFeePayment::AtSourceChain, - ); - assert_eq!(Millau::verify_message(&payload), Ok(())); - - let payload = send_message::message_payload( - Default::default(), - maximal_dispatch_weight + 1, - bp_message_dispatch::CallOrigin::SourceRoot, - &call, - send_message::DispatchFeePayment::AtSourceChain, - ); - assert!(Millau::verify_message(&payload).is_err()); - } - - #[test] - fn maximal_weight_fill_block_to_rialto_is_generated_correctly() { - use millau_runtime::rialto_messages::Rialto; - - let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight( - bp_rialto::Rialto::max_extrinsic_weight(), - ); - let call: rialto_runtime::Call = - millau_runtime::SystemCall::remark { remark: vec![] }.into(); - - let payload = send_message::message_payload( - Default::default(), - maximal_dispatch_weight, - bp_message_dispatch::CallOrigin::SourceRoot, - &call, - send_message::DispatchFeePayment::AtSourceChain, - ); - assert_eq!(Rialto::verify_message(&payload), Ok(())); - - let payload = send_message::message_payload( - Default::default(), - maximal_dispatch_weight + 1, - bp_message_dispatch::CallOrigin::SourceRoot, - &call, - send_message::DispatchFeePayment::AtSourceChain, - ); - assert!(Rialto::verify_message(&payload).is_err()); - } - #[test] fn rialto_tx_extra_bytes_constant_is_correct() { let rialto_call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { remark: vec![] }); - let rialto_tx = Rialto::sign_transaction(SignParam { - spec_version: 1, - transaction_version: 1, - genesis_hash: Default::default(), - signer: sp_keyring::AccountKeyring::Alice.pair(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(rialto_call.clone().into(), 0), - }) + let rialto_tx = Rialto::sign_transaction( + SignParam { + spec_version: 1, + transaction_version: 1, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + }, + UnsignedTransaction::new(rialto_call.clone().into(), 0), + ) .unwrap(); let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); assert!( @@ -226,14 +94,15 @@ mod tests { fn millau_tx_extra_bytes_constant_is_correct() { let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark { remark: vec![] }); - let millau_tx = Millau::sign_transaction(SignParam { - spec_version: 0, - transaction_version: 0, - genesis_hash: Default::default(), - signer: sp_keyring::AccountKeyring::Alice.pair(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(millau_call.clone().into(), 0), - }) + let millau_tx = Millau::sign_transaction( + SignParam { + spec_version: 0, + transaction_version: 0, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + }, + UnsignedTransaction::new(millau_call.clone().into(), 0), + ) .unwrap(); let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); assert!( @@ -244,101 +113,3 @@ mod tests { ); } } - -#[cfg(test)] -mod rococo_tests { - use bp_header_chain::justification::GrandpaJustification; - use codec::Encode; - - #[test] - fn scale_compatibility_of_bridges_call() { - // given - let header = sp_runtime::generic::Header { - parent_hash: Default::default(), - number: Default::default(), - state_root: Default::default(), - extrinsics_root: Default::default(), - digest: sp_runtime::generic::Digest { logs: vec![] }, - }; - - let justification = GrandpaJustification { - round: 0, - commit: finality_grandpa::Commit { - target_hash: Default::default(), - target_number: Default::default(), - precommits: vec![], - }, - votes_ancestries: vec![], - }; - - let actual = relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof( - Box::new(header.clone()), - justification.clone(), - ); - let expected = - millau_runtime::BridgeGrandpaCall::::submit_finality_proof { - finality_target: Box::new(header), - justification, - }; - - // when - let actual_encoded = actual.encode(); - let expected_encoded = expected.encode(); - - // then - assert_eq!( - actual_encoded, expected_encoded, - "\n\nEncoding difference.\nGot {:#?} \nExpected: {:#?}", - actual, expected - ); - } -} - -#[cfg(test)] -mod westend_tests { - use bp_header_chain::justification::GrandpaJustification; - use codec::Encode; - - #[test] - fn scale_compatibility_of_bridges_call() { - // given - let header = sp_runtime::generic::Header { - parent_hash: Default::default(), - number: Default::default(), - state_root: Default::default(), - extrinsics_root: Default::default(), - digest: sp_runtime::generic::Digest { logs: vec![] }, - }; - - let justification = GrandpaJustification { - round: 0, - commit: finality_grandpa::Commit { - target_hash: Default::default(), - target_number: Default::default(), - precommits: vec![], - }, - votes_ancestries: vec![], - }; - - let actual = relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof( - Box::new(header.clone()), - justification.clone(), - ); - let expected = - millau_runtime::BridgeGrandpaCall::::submit_finality_proof { - finality_target: Box::new(header), - justification, - }; - - // when - let actual_encoded = actual.encode(); - let expected_encoded = expected.encode(); - - // then - assert_eq!( - actual_encoded, expected_encoded, - "\n\nEncoding difference.\nGot {:#?} \nExpected: {:#?}", - actual, expected - ); - } -} diff --git a/relays/bin-substrate/src/chains/polkadot.rs b/relays/bin-substrate/src/chains/polkadot.rs deleted file mode 100644 index 7ae1cbc477..0000000000 --- a/relays/bin-substrate/src/chains/polkadot.rs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use anyhow::anyhow; -use bp_message_dispatch::{CallOrigin, MessagePayload}; -use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; -use relay_polkadot_client::Polkadot; -use sp_version::RuntimeVersion; - -use crate::cli::{ - bridge, - encode_call::{self, Call, CliEncodeCall}, - encode_message, - send_message::{self, DispatchFeePayment}, - CliChain, -}; - -/// Weight of the `system::remark` call at Polkadot. -/// -/// This weight is larger (x2) than actual weight at current Polkadot runtime to avoid unsuccessful -/// calls in the future. But since it is used only in tests (and on test chains), this is ok. -pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000; - -impl CliEncodeCall for Polkadot { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()), - Call::Remark { remark_payload, .. } => relay_polkadot_client::runtime::Call::System( - relay_polkadot_client::runtime::SystemCall::remark( - remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - ), - ) - .into(), - Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } => - match *bridge_instance_index { - bridge::POLKADOT_TO_KUSAMA_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - relay_polkadot_client::runtime::Call::BridgeKusamaMessages( - relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message( - lane.0, payload, fee.0, - ), - ) - .into() - }, - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, - _ => anyhow::bail!("Unsupported Polkadot call: {:?}", call), - }) - } - - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - match *call { - EncodedOrDecodedCall::Decoded(relay_polkadot_client::runtime::Call::System( - relay_polkadot_client::runtime::SystemCall::remark(_), - )) => Ok(DispatchInfo { - weight: crate::chains::polkadot::SYSTEM_REMARK_CALL_WEIGHT, - class: DispatchClass::Normal, - pays_fee: Pays::Yes, - }), - _ => anyhow::bail!("Unsupported Polkadot call: {:?}", call), - } - } -} - -impl CliChain for Polkadot { - const RUNTIME_VERSION: RuntimeVersion = bp_polkadot::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_polkadot::AccountId, - bp_kusama::AccountPublic, - bp_kusama::Signature, - Vec, - >; - - fn ss58_format() -> u16 { - sp_core::crypto::Ss58AddressFormat::from( - sp_core::crypto::Ss58AddressFormatRegistry::PolkadotAccount, - ) - .into() - } - - fn encode_message( - message: encode_message::MessagePayload, - ) -> anyhow::Result { - match message { - encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| anyhow!("Failed to decode Polkadot's MessagePayload: {:?}", e)), - encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => { - type Source = Polkadot; - type Target = relay_kusama_client::Kusama; - - sender.enforce_chain::(); - let spec_version = Target::RUNTIME_VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::( - &mut call, - bridge::POLKADOT_TO_KUSAMA_INDEX, - ); - let call = Target::encode_call(&call)?; - let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| { - Err(anyhow::format_err!( - "Please specify dispatch weight of the encoded Kusama call" - )) - })?; - - Ok(send_message::message_payload( - spec_version, - dispatch_weight, - origin, - &call, - DispatchFeePayment::AtSourceChain, - )) - }, - } - } -} diff --git a/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs b/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs deleted file mode 100644 index 6d118b07ca..0000000000 --- a/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Polkadot-to-Kusama headers sync entrypoint. - -use async_trait::async_trait; -use relay_kusama_client::Kusama; -use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; - -/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat -/// relay as gone wild. -/// -/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 0.001 -/// KSM, and initial value of this constant was rounded up to 0.1 KSM. But for actual Kusama <> -/// Polkadot deployment we'll be using the same account for delivering finality (free for mandatory -/// headers) and messages. It means that we can't predict maximal loss. But to protect funds against -/// relay/deployment issues, let's limit it so something that is much larger than this estimation - -/// e.g. to 2 KSM. -// TODO: https://github.com/paritytech/parity-bridges-common/issues/1307 -pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_kusama::Balance = 2 * 1_000_000_000_000; - -/// Description of Polkadot -> Kusama finalized headers bridge. -#[derive(Clone, Debug)] -pub struct PolkadotFinalityToKusama; -substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( - PolkadotFinalityToKusama, - PolkadotFinalityToKusamaCallBuilder, - relay_kusama_client::runtime::Call::BridgePolkadotGrandpa, - relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof -); - -#[async_trait] -impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama { - type SourceChain = relay_polkadot_client::Polkadot; - type TargetChain = Kusama; - - type SubmitFinalityProofCallBuilder = PolkadotFinalityToKusamaCallBuilder; - type TransactionSignScheme = Kusama; - - async fn start_relay_guards( - target_client: &relay_substrate_client::Client, - transaction_params: &TransactionParams, - enable_version_guard: bool, - ) -> relay_substrate_client::Result<()> { - substrate_relay_helper::finality_guards::start::( - target_client, - transaction_params, - enable_version_guard, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ) - .await - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::chains::kusama_headers_to_polkadot::tests::compute_maximal_balance_decrease_per_day; - - #[test] - fn maximal_balance_decrease_per_day_is_sane() { - // we expect Polkadot -> Kusama relay to be running in mandatory-headers-only mode - // => we expect single header for every Polkadot session - let maximal_balance_decrease = compute_maximal_balance_decrease_per_day::< - bp_kusama::Balance, - bp_kusama::WeightToFee, - >(bp_polkadot::DAYS / bp_polkadot::SESSION_LENGTH + 1); - assert!( - MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_balance_decrease, - "Maximal expected loss per day {} is larger than hardcoded {}", - maximal_balance_decrease, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ); - } -} diff --git a/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs b/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs deleted file mode 100644 index 9c4a4640eb..0000000000 --- a/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Polkadot-to-Kusama messages sync entrypoint. - -use frame_support::weights::Weight; -use messages_relay::relay_strategy::MixStrategy; -use relay_kusama_client::Kusama; -use relay_polkadot_client::Polkadot; -use substrate_relay_helper::messages_lane::SubstrateMessageLane; - -/// Description of Polkadot -> Kusama messages bridge. -#[derive(Clone, Debug)] -pub struct PolkadotMessagesToKusama; -substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( - PolkadotMessagesToKusama, - PolkadotMessagesToKusamaReceiveMessagesProofCallBuilder, - relay_kusama_client::runtime::Call::BridgePolkadotMessages, - relay_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_proof -); -substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( - PolkadotMessagesToKusama, - PolkadotMessagesToKusamaReceiveMessagesDeliveryProofCallBuilder, - relay_polkadot_client::runtime::Call::BridgeKusamaMessages, - relay_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_delivery_proof -); -substrate_relay_helper::generate_mocked_update_conversion_rate_call_builder!( - Polkadot, - PolkadotMessagesToKusamaUpdateConversionRateCallBuilder, - relay_polkadot_client::runtime::Call::BridgeKusamaMessages, - relay_polkadot_client::runtime::BridgeKusamaMessagesCall::update_pallet_parameter, - relay_polkadot_client::runtime::BridgeKusamaMessagesParameter::KusamaToPolkadotConversionRate -); - -impl SubstrateMessageLane for PolkadotMessagesToKusama { - const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = - Some(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME); - const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = - Some(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME); - - const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = - Some(bp_kusama::POLKADOT_FEE_MULTIPLIER_PARAMETER_NAME); - const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = - Some(bp_polkadot::KUSAMA_FEE_MULTIPLIER_PARAMETER_NAME); - - const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = - Some(bp_polkadot::TRANSACTION_PAYMENT_PALLET_NAME); - const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = - Some(bp_kusama::TRANSACTION_PAYMENT_PALLET_NAME); - - type SourceChain = Polkadot; - type TargetChain = Kusama; - - type SourceTransactionSignScheme = Polkadot; - type TargetTransactionSignScheme = Kusama; - - type ReceiveMessagesProofCallBuilder = PolkadotMessagesToKusamaReceiveMessagesProofCallBuilder; - type ReceiveMessagesDeliveryProofCallBuilder = - PolkadotMessagesToKusamaReceiveMessagesDeliveryProofCallBuilder; - - type TargetToSourceChainConversionRateUpdateBuilder = - PolkadotMessagesToKusamaUpdateConversionRateCallBuilder; - - type RelayStrategy = MixStrategy; -} diff --git a/relays/bin-substrate/src/chains/rialto.rs b/relays/bin-substrate/src/chains/rialto.rs index 8f26a64a4e..9dd86c9d95 100644 --- a/relays/bin-substrate/src/chains/rialto.rs +++ b/relays/bin-substrate/src/chains/rialto.rs @@ -18,57 +18,57 @@ use crate::cli::{ bridge, - encode_call::{self, Call, CliEncodeCall}, - encode_message, - send_message::{self, DispatchFeePayment}, + encode_message::{CliEncodeMessage, RawMessage}, CliChain, }; -use anyhow::anyhow; -use bp_message_dispatch::{CallOrigin, MessagePayload}; +use bp_messages::LaneId; use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchInfo, GetDispatchInfo}; use relay_rialto_client::Rialto; +use relay_substrate_client::BalanceOf; use sp_version::RuntimeVersion; +use xcm::latest::prelude::*; -impl CliEncodeCall for Rialto { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(), - Call::Remark { remark_payload, .. } => - rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { - remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - }) - .into(), - Call::Transfer { recipient, amount } => - rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer { - dest: recipient.raw_id().into(), - value: amount.0, - }) - .into(), - Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } => - match *bridge_instance_index { - bridge::RIALTO_TO_MILLAU_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - rialto_runtime::Call::BridgeMillauMessages( - rialto_runtime::MessagesCall::send_message { - lane_id: lane.0, - payload, - delivery_and_dispatch_fee: fee.0, - }, - ) - .into() - }, - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, +impl CliEncodeMessage for Rialto { + fn encode_send_xcm( + message: xcm::VersionedXcm<()>, + bridge_instance_index: u8, + ) -> anyhow::Result> { + let dest = match bridge_instance_index { + bridge::RIALTO_TO_MILLAU_INDEX => + (Parent, X1(GlobalConsensus(rialto_runtime::xcm_config::MillauNetwork::get()))), + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }; + + Ok(rialto_runtime::Call::XcmPallet(rialto_runtime::XcmCall::send { + dest: Box::new(dest.into()), + message: Box::new(message), }) + .into()) } - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - Ok(call.to_decoded()?.get_dispatch_info()) + fn encode_send_message_call( + lane: LaneId, + payload: RawMessage, + fee: BalanceOf, + bridge_instance_index: u8, + ) -> anyhow::Result> { + Ok(match bridge_instance_index { + bridge::RIALTO_TO_MILLAU_INDEX => rialto_runtime::Call::BridgeMillauMessages( + rialto_runtime::MessagesCall::send_message { + lane_id: lane, + payload, + delivery_and_dispatch_fee: fee, + }, + ) + .into(), + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }) } } @@ -76,47 +76,9 @@ impl CliChain for Rialto { const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION; type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_rialto::AccountId, - bp_millau::AccountSigner, - bp_millau::Signature, - Vec, - >; + type MessagePayload = Vec; fn ss58_format() -> u16 { rialto_runtime::SS58Prefix::get() as u16 } - - fn encode_message( - message: encode_message::MessagePayload, - ) -> anyhow::Result { - match message { - encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| anyhow!("Failed to decode Rialto's MessagePayload: {:?}", e)), - encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => { - type Source = Rialto; - type Target = relay_millau_client::Millau; - - sender.enforce_chain::(); - let spec_version = Target::RUNTIME_VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::( - &mut call, - bridge::RIALTO_TO_MILLAU_INDEX, - ); - let call = Target::encode_call(&call)?; - let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| { - call.to_decoded().map(|call| call.get_dispatch_info().weight) - })?; - - Ok(send_message::message_payload( - spec_version, - dispatch_weight, - origin, - &call, - DispatchFeePayment::AtSourceChain, - )) - }, - } - } } diff --git a/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs b/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs index a433f3562a..65c5cba1ae 100644 --- a/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs +++ b/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs @@ -16,8 +16,10 @@ //! Rialto-to-Millau headers sync entrypoint. -use substrate_relay_helper::finality_pipeline::{ - DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, }; /// Description of Millau -> Rialto finalized headers bridge. @@ -28,10 +30,29 @@ impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { type SourceChain = relay_rialto_client::Rialto; type TargetChain = relay_millau_client::Millau; - type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< Self, millau_runtime::Runtime, millau_runtime::RialtoGrandpaInstance, >; type TransactionSignScheme = relay_millau_client::Millau; } + +//// `Rialto` to `Millau` bridge definition. +pub struct RialtoToMillauCliBridge {} + +impl CliBridgeBase for RialtoToMillauCliBridge { + type Source = relay_rialto_client::Rialto; + type Target = relay_millau_client::Millau; +} + +impl RelayToRelayHeadersCliBridge for RialtoToMillauCliBridge { + type Finality = RialtoFinalityToMillau; +} + +impl MessagesCliBridge for RialtoToMillauCliBridge { + const ESTIMATE_MESSAGE_FEE_METHOD: &'static str = + bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; + type MessagesLane = crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau; +} diff --git a/relays/bin-substrate/src/chains/rialto_parachain.rs b/relays/bin-substrate/src/chains/rialto_parachain.rs index 0ed39faa54..8cd7135c27 100644 --- a/relays/bin-substrate/src/chains/rialto_parachain.rs +++ b/relays/bin-substrate/src/chains/rialto_parachain.rs @@ -17,41 +17,59 @@ //! Rialto parachain specification for CLI. use crate::cli::{ - encode_call::{Call, CliEncodeCall}, - encode_message, CliChain, + bridge, + encode_message::{CliEncodeMessage, RawMessage}, + CliChain, }; -use bp_message_dispatch::MessagePayload; +use bp_messages::LaneId; use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchInfo, GetDispatchInfo}; use relay_rialto_parachain_client::RialtoParachain; +use relay_substrate_client::BalanceOf; use sp_version::RuntimeVersion; +use xcm::latest::prelude::*; -impl CliEncodeCall for RialtoParachain { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(), - Call::Remark { remark_payload, .. } => rialto_parachain_runtime::Call::System( - rialto_parachain_runtime::SystemCall::remark { - remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - }, - ) - .into(), - Call::Transfer { recipient, amount } => rialto_parachain_runtime::Call::Balances( - rialto_parachain_runtime::BalancesCall::transfer { - dest: recipient.raw_id().into(), - value: amount.0, - }, - ) - .into(), - Call::BridgeSendMessage { .. } => { - anyhow::bail!("Bridge messages are not (yet) supported here",) - }, +impl CliEncodeMessage for RialtoParachain { + fn encode_send_xcm( + message: xcm::VersionedXcm<()>, + bridge_instance_index: u8, + ) -> anyhow::Result> { + let dest = match bridge_instance_index { + bridge::RIALTO_PARACHAIN_TO_MILLAU_INDEX => + (Parent, X1(GlobalConsensus(rialto_parachain_runtime::MillauNetwork::get()))), + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }; + + Ok(rialto_parachain_runtime::Call::PolkadotXcm(rialto_parachain_runtime::XcmCall::send { + dest: Box::new(dest.into()), + message: Box::new(message), }) + .into()) } - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - Ok(call.to_decoded()?.get_dispatch_info()) + fn encode_send_message_call( + lane: LaneId, + payload: RawMessage, + fee: BalanceOf, + bridge_instance_index: u8, + ) -> anyhow::Result> { + Ok(match bridge_instance_index { + bridge::RIALTO_PARACHAIN_TO_MILLAU_INDEX => + rialto_parachain_runtime::Call::BridgeMillauMessages( + rialto_parachain_runtime::MessagesCall::send_message { + lane_id: lane, + payload, + delivery_and_dispatch_fee: fee, + }, + ) + .into(), + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }) } } @@ -59,20 +77,9 @@ impl CliChain for RialtoParachain { const RUNTIME_VERSION: RuntimeVersion = rialto_parachain_runtime::VERSION; type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_rialto_parachain::AccountId, - bp_millau::AccountSigner, - bp_millau::Signature, - Vec, - >; + type MessagePayload = Vec; fn ss58_format() -> u16 { rialto_parachain_runtime::SS58Prefix::get() as u16 } - - fn encode_message( - _message: encode_message::MessagePayload, - ) -> anyhow::Result { - anyhow::bail!("Not supported") - } } diff --git a/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs b/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs new file mode 100644 index 0000000000..b8ff0af10f --- /dev/null +++ b/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! RialtoParachain-to-Millau messages sync entrypoint. + +use messages_relay::relay_strategy::MixStrategy; +use relay_millau_client::Millau; +use relay_rialto_parachain_client::RialtoParachain; +use substrate_relay_helper::messages_lane::{ + DirectReceiveMessagesDeliveryProofCallBuilder, DirectReceiveMessagesProofCallBuilder, + SubstrateMessageLane, +}; + +/// Description of RialtoParachain -> Millau messages bridge. +#[derive(Clone, Debug)] +pub struct RialtoParachainMessagesToMillau; +substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!( + RialtoParachain, + RialtoParachainMessagesToMillauUpdateConversionRateCallBuilder, + rialto_parachain_runtime::Runtime, + rialto_parachain_runtime::WithMillauMessagesInstance, + rialto_parachain_runtime::millau_messages::RialtoParachainToMillauMessagesParameter::MillauToRialtoParachainConversionRate +); + +impl SubstrateMessageLane for RialtoParachainMessagesToMillau { + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_millau::RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME); + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_rialto_parachain::MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME); + + const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_millau::RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME); + const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = + Some(bp_rialto_parachain::MILLAU_FEE_MULTIPLIER_PARAMETER_NAME); + + const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_rialto_parachain::TRANSACTION_PAYMENT_PALLET_NAME); + const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = + Some(bp_millau::TRANSACTION_PAYMENT_PALLET_NAME); + + type SourceChain = RialtoParachain; + type TargetChain = Millau; + + type SourceTransactionSignScheme = RialtoParachain; + type TargetTransactionSignScheme = Millau; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + rialto_parachain_runtime::Runtime, + rialto_parachain_runtime::WithMillauMessagesInstance, + >; + + type TargetToSourceChainConversionRateUpdateBuilder = + RialtoParachainMessagesToMillauUpdateConversionRateCallBuilder; + + type RelayStrategy = MixStrategy; +} diff --git a/relays/bin-substrate/src/chains/rialto_parachains_to_millau.rs b/relays/bin-substrate/src/chains/rialto_parachains_to_millau.rs new file mode 100644 index 0000000000..800d5a3e79 --- /dev/null +++ b/relays/bin-substrate/src/chains/rialto_parachains_to_millau.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Rialto-to-Millau parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; +use parachains_relay::ParachainsPipeline; +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; +use relay_rialto_parachain_client::RialtoParachain; +use substrate_relay_helper::parachains::{ + DirectSubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// Rialto-to-Millau parachains sync description. +#[derive(Clone, Debug)] +pub struct RialtoParachainsToMillau; + +impl ParachainsPipeline for RialtoParachainsToMillau { + type SourceChain = Rialto; + type TargetChain = Millau; +} + +impl SubstrateParachainsPipeline for RialtoParachainsToMillau { + type SourceParachain = RialtoParachain; + type SourceRelayChain = Rialto; + type TargetChain = Millau; + + type SubmitParachainHeadsCallBuilder = RialtoParachainsToMillauSubmitParachainHeadsCallBuilder; + type TransactionSignScheme = Millau; + + const SOURCE_PARACHAIN_PARA_ID: u32 = bp_rialto_parachain::RIALTO_PARACHAIN_ID; +} + +/// `submit_parachain_heads` call builder for Rialto-to-Millau parachains sync pipeline. +pub type RialtoParachainsToMillauSubmitParachainHeadsCallBuilder = + DirectSubmitParachainHeadsCallBuilder< + RialtoParachainsToMillau, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainsInstance, + >; + +//// `RialtoParachain` to `Millau` bridge definition. +pub struct RialtoParachainToMillauCliBridge {} + +impl CliBridgeBase for RialtoParachainToMillauCliBridge { + type Source = RialtoParachain; + type Target = Millau; +} + +impl ParachainToRelayHeadersCliBridge for RialtoParachainToMillauCliBridge { + type SourceRelay = Rialto; + type ParachainFinality = RialtoParachainsToMillau; + type RelayFinality = crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau; +} + +impl MessagesCliBridge for RialtoParachainToMillauCliBridge { + const ESTIMATE_MESSAGE_FEE_METHOD: &'static str = + bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; + type MessagesLane = + crate::chains::rialto_parachain_messages_to_millau::RialtoParachainMessagesToMillau; +} diff --git a/relays/bin-substrate/src/chains/rococo.rs b/relays/bin-substrate/src/chains/rococo.rs deleted file mode 100644 index ceef4c1f53..0000000000 --- a/relays/bin-substrate/src/chains/rococo.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use anyhow::anyhow; -use bp_message_dispatch::{CallOrigin, MessagePayload}; -use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; -use relay_rococo_client::Rococo; -use sp_version::RuntimeVersion; - -use crate::cli::{ - bridge, - encode_call::{self, Call, CliEncodeCall}, - encode_message, - send_message::{self, DispatchFeePayment}, - CliChain, -}; - -/// Weight of the `system::remark` call at Rococo. -/// -/// This weight is larger (x2) than actual weight at current Rococo runtime to avoid unsuccessful -/// calls in the future. But since it is used only in tests (and on test chains), this is ok. -pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000; - -impl CliEncodeCall for Rococo { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()), - Call::Remark { remark_payload, .. } => relay_rococo_client::runtime::Call::System( - relay_rococo_client::runtime::SystemCall::remark( - remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - ), - ) - .into(), - Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } => - match *bridge_instance_index { - bridge::ROCOCO_TO_WOCOCO_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - relay_rococo_client::runtime::Call::BridgeWococoMessages( - relay_rococo_client::runtime::BridgeWococoMessagesCall::send_message( - lane.0, payload, fee.0, - ), - ) - .into() - }, - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, - _ => anyhow::bail!("The call is not supported"), - }) - } - - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - match *call { - EncodedOrDecodedCall::Decoded(relay_rococo_client::runtime::Call::System( - relay_rococo_client::runtime::SystemCall::remark(_), - )) => Ok(DispatchInfo { - weight: SYSTEM_REMARK_CALL_WEIGHT, - class: DispatchClass::Normal, - pays_fee: Pays::Yes, - }), - _ => anyhow::bail!("Unsupported Rococo call: {:?}", call), - } - } -} - -impl CliChain for Rococo { - const RUNTIME_VERSION: RuntimeVersion = bp_rococo::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_rococo::AccountId, - bp_wococo::AccountPublic, - bp_wococo::Signature, - Vec, - >; - - fn ss58_format() -> u16 { - 42 - } - - fn encode_message( - message: encode_message::MessagePayload, - ) -> anyhow::Result { - match message { - encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| anyhow!("Failed to decode Rococo's MessagePayload: {:?}", e)), - encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => { - type Source = Rococo; - type Target = relay_wococo_client::Wococo; - - sender.enforce_chain::(); - let spec_version = Target::RUNTIME_VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::( - &mut call, - bridge::ROCOCO_TO_WOCOCO_INDEX, - ); - let call = Target::encode_call(&call)?; - let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| { - Err(anyhow::format_err!( - "Please specify dispatch weight of the encoded Wococo call" - )) - })?; - - Ok(send_message::message_payload( - spec_version, - dispatch_weight, - origin, - &call, - DispatchFeePayment::AtSourceChain, - )) - }, - } - } -} diff --git a/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs b/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs deleted file mode 100644 index bb66a7422d..0000000000 --- a/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Rococo-to-Wococo headers sync entrypoint. - -use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY; - -use async_trait::async_trait; -use relay_wococo_client::Wococo; -use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; - -/// Description of Rococo -> Wococo finalized headers bridge. -#[derive(Clone, Debug)] -pub struct RococoFinalityToWococo; -substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( - RococoFinalityToWococo, - RococoFinalityToWococoCallBuilder, - relay_wococo_client::runtime::Call::BridgeGrandpaRococo, - relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof -); - -#[async_trait] -impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo { - type SourceChain = relay_rococo_client::Rococo; - type TargetChain = Wococo; - - type SubmitFinalityProofCallBuilder = RococoFinalityToWococoCallBuilder; - type TransactionSignScheme = Wococo; - - async fn start_relay_guards( - target_client: &relay_substrate_client::Client, - transaction_params: &TransactionParams, - enable_version_guard: bool, - ) -> relay_substrate_client::Result<()> { - substrate_relay_helper::finality_guards::start::( - target_client, - transaction_params, - enable_version_guard, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ) - .await - } -} diff --git a/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs b/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs deleted file mode 100644 index 4e67c87fa8..0000000000 --- a/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Rococo-to-Wococo messages sync entrypoint. - -use frame_support::weights::Weight; -use messages_relay::relay_strategy::MixStrategy; -use relay_rococo_client::Rococo; -use relay_wococo_client::Wococo; -use substrate_relay_helper::messages_lane::SubstrateMessageLane; - -/// Description of Rococo -> Wococo messages bridge. -#[derive(Clone, Debug)] -pub struct RococoMessagesToWococo; -substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( - RococoMessagesToWococo, - RococoMessagesToWococoReceiveMessagesProofCallBuilder, - relay_wococo_client::runtime::Call::BridgeRococoMessages, - relay_wococo_client::runtime::BridgeRococoMessagesCall::receive_messages_proof -); -substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( - RococoMessagesToWococo, - RococoMessagesToWococoReceiveMessagesDeliveryProofCallBuilder, - relay_rococo_client::runtime::Call::BridgeWococoMessages, - relay_rococo_client::runtime::BridgeWococoMessagesCall::receive_messages_delivery_proof -); - -impl SubstrateMessageLane for RococoMessagesToWococo { - const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; - const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; - - const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None; - const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None; - const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None; - const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None; - - type SourceChain = Rococo; - type TargetChain = Wococo; - - type SourceTransactionSignScheme = Rococo; - type TargetTransactionSignScheme = Wococo; - - type ReceiveMessagesProofCallBuilder = RococoMessagesToWococoReceiveMessagesProofCallBuilder; - type ReceiveMessagesDeliveryProofCallBuilder = - RococoMessagesToWococoReceiveMessagesDeliveryProofCallBuilder; - - type TargetToSourceChainConversionRateUpdateBuilder = (); - - type RelayStrategy = MixStrategy; -} diff --git a/relays/bin-substrate/src/chains/westend.rs b/relays/bin-substrate/src/chains/westend.rs index 8d3b5db9ab..ae52944707 100644 --- a/relays/bin-substrate/src/chains/westend.rs +++ b/relays/bin-substrate/src/chains/westend.rs @@ -16,16 +16,15 @@ //! Westend chain specification for CLI. -use crate::cli::{encode_message, CliChain}; -use anyhow::anyhow; -use relay_westend_client::Westend; +use crate::cli::CliChain; +use relay_westend_client::{Westend, Westmint}; use sp_version::RuntimeVersion; impl CliChain for Westend { const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION; type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = (); + type MessagePayload = Vec; fn ss58_format() -> u16 { sp_core::crypto::Ss58AddressFormat::from( @@ -33,10 +32,18 @@ impl CliChain for Westend { ) .into() } +} + +impl CliChain for Westmint { + const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = Vec; - fn encode_message( - _message: encode_message::MessagePayload, - ) -> anyhow::Result { - Err(anyhow!("Sending messages from Westend is not yet supported.")) + fn ss58_format() -> u16 { + sp_core::crypto::Ss58AddressFormat::from( + sp_core::crypto::Ss58AddressFormatRegistry::SubstrateAccount, + ) + .into() } } diff --git a/relays/bin-substrate/src/chains/westend_headers_to_millau.rs b/relays/bin-substrate/src/chains/westend_headers_to_millau.rs index 2ec20a027f..8339464589 100644 --- a/relays/bin-substrate/src/chains/westend_headers_to_millau.rs +++ b/relays/bin-substrate/src/chains/westend_headers_to_millau.rs @@ -16,8 +16,10 @@ //! Westend-to-Millau headers sync entrypoint. -use substrate_relay_helper::finality_pipeline::{ - DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, +use crate::cli::bridge::{CliBridgeBase, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, }; /// Description of Westend -> Millau finalized headers bridge. @@ -28,10 +30,23 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { type SourceChain = relay_westend_client::Westend; type TargetChain = relay_millau_client::Millau; - type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< Self, millau_runtime::Runtime, millau_runtime::WestendGrandpaInstance, >; type TransactionSignScheme = relay_millau_client::Millau; } + +//// `Westend` to `Millau` bridge definition. +pub struct WestendToMillauCliBridge {} + +impl CliBridgeBase for WestendToMillauCliBridge { + type Source = relay_westend_client::Westend; + type Target = relay_millau_client::Millau; +} + +impl RelayToRelayHeadersCliBridge for WestendToMillauCliBridge { + type Finality = WestendFinalityToMillau; +} diff --git a/relays/bin-substrate/src/chains/westend_parachains_to_millau.rs b/relays/bin-substrate/src/chains/westend_parachains_to_millau.rs new file mode 100644 index 0000000000..586d391d24 --- /dev/null +++ b/relays/bin-substrate/src/chains/westend_parachains_to_millau.rs @@ -0,0 +1,67 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Westend-to-Millau parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, ParachainToRelayHeadersCliBridge}; +use parachains_relay::ParachainsPipeline; +use relay_millau_client::Millau; +use relay_westend_client::{Westend, Westmint}; +use substrate_relay_helper::parachains::{ + DirectSubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// Westend-to-Millau parachains sync description. +#[derive(Clone, Debug)] +pub struct WestendParachainsToMillau; + +impl ParachainsPipeline for WestendParachainsToMillau { + type SourceChain = Westend; + type TargetChain = Millau; +} + +impl SubstrateParachainsPipeline for WestendParachainsToMillau { + type SourceParachain = Westmint; + type SourceRelayChain = Westend; + type TargetChain = Millau; + + type SubmitParachainHeadsCallBuilder = WestendParachainsToMillauSubmitParachainHeadsCallBuilder; + type TransactionSignScheme = Millau; + + const SOURCE_PARACHAIN_PARA_ID: u32 = bp_westend::WESTMINT_PARACHAIN_ID; +} + +/// `submit_parachain_heads` call builder for Rialto-to-Millau parachains sync pipeline. +pub type WestendParachainsToMillauSubmitParachainHeadsCallBuilder = + DirectSubmitParachainHeadsCallBuilder< + WestendParachainsToMillau, + millau_runtime::Runtime, + millau_runtime::WithWestendParachainsInstance, + >; + +//// `WestendParachain` to `Millau` bridge definition. +pub struct WestmintToMillauCliBridge {} + +impl ParachainToRelayHeadersCliBridge for WestmintToMillauCliBridge { + type SourceRelay = Westend; + type ParachainFinality = WestendParachainsToMillau; + type RelayFinality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau; +} + +impl CliBridgeBase for WestmintToMillauCliBridge { + type Source = Westmint; + type Target = Millau; +} diff --git a/relays/bin-substrate/src/chains/wococo.rs b/relays/bin-substrate/src/chains/wococo.rs deleted file mode 100644 index 46dec2a3c9..0000000000 --- a/relays/bin-substrate/src/chains/wococo.rs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use anyhow::anyhow; -use bp_message_dispatch::{CallOrigin, MessagePayload}; -use bp_runtime::EncodedOrDecodedCall; -use codec::Decode; -use frame_support::weights::{DispatchClass, DispatchInfo, Pays}; -use relay_wococo_client::Wococo; -use sp_version::RuntimeVersion; - -use crate::cli::{ - bridge, - encode_call::{self, Call, CliEncodeCall}, - encode_message, - send_message::{self, DispatchFeePayment}, - CliChain, -}; - -impl CliEncodeCall for Wococo { - fn encode_call(call: &Call) -> anyhow::Result> { - Ok(match call { - Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()), - Call::Remark { remark_payload, .. } => relay_wococo_client::runtime::Call::System( - relay_wococo_client::runtime::SystemCall::remark( - remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - ), - ) - .into(), - Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } => - match *bridge_instance_index { - bridge::WOCOCO_TO_ROCOCO_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - relay_wococo_client::runtime::Call::BridgeRococoMessages( - relay_wococo_client::runtime::BridgeRococoMessagesCall::send_message( - lane.0, payload, fee.0, - ), - ) - .into() - }, - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, - _ => anyhow::bail!("The call is not supported"), - }) - } - - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result { - match *call { - EncodedOrDecodedCall::Decoded(relay_wococo_client::runtime::Call::System( - relay_wococo_client::runtime::SystemCall::remark(_), - )) => Ok(DispatchInfo { - weight: crate::chains::rococo::SYSTEM_REMARK_CALL_WEIGHT, - class: DispatchClass::Normal, - pays_fee: Pays::Yes, - }), - _ => anyhow::bail!("Unsupported Wococo call: {:?}", call), - } - } -} - -impl CliChain for Wococo { - const RUNTIME_VERSION: RuntimeVersion = bp_wococo::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload< - bp_wococo::AccountId, - bp_rococo::AccountPublic, - bp_rococo::Signature, - Vec, - >; - - fn ss58_format() -> u16 { - 42 - } - - fn encode_message( - message: encode_message::MessagePayload, - ) -> anyhow::Result { - match message { - encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| anyhow!("Failed to decode Wococo's MessagePayload: {:?}", e)), - encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => { - type Source = Wococo; - type Target = relay_rococo_client::Rococo; - - sender.enforce_chain::(); - let spec_version = Target::RUNTIME_VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::( - &mut call, - bridge::WOCOCO_TO_ROCOCO_INDEX, - ); - let call = Target::encode_call(&call)?; - let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| { - Err(anyhow::format_err!( - "Please specify dispatch weight of the encoded Rococo call" - )) - })?; - - Ok(send_message::message_payload( - spec_version, - dispatch_weight, - origin, - &call, - DispatchFeePayment::AtSourceChain, - )) - }, - } - } -} diff --git a/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs b/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs deleted file mode 100644 index a7bff59518..0000000000 --- a/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Wococo-to-Rococo headers sync entrypoint. - -use async_trait::async_trait; -use relay_rococo_client::Rococo; -use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; - -/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat -/// relay as gone wild. -/// -/// See `maximal_balance_decrease_per_day_is_sane` test for details. -/// Note that this is in plancks, so this corresponds to `1500 UNITS`. -pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_rococo::Balance = 1_500_000_000_000_000; - -/// Description of Wococo -> Rococo finalized headers bridge. -#[derive(Clone, Debug)] -pub struct WococoFinalityToRococo; -substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( - WococoFinalityToRococo, - WococoFinalityToRococoCallBuilder, - relay_rococo_client::runtime::Call::BridgeGrandpaWococo, - relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof -); - -#[async_trait] -impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo { - type SourceChain = relay_wococo_client::Wococo; - type TargetChain = Rococo; - - type SubmitFinalityProofCallBuilder = WococoFinalityToRococoCallBuilder; - type TransactionSignScheme = Rococo; - - async fn start_relay_guards( - target_client: &relay_substrate_client::Client, - transaction_params: &TransactionParams, - enable_version_guard: bool, - ) -> relay_substrate_client::Result<()> { - substrate_relay_helper::finality_guards::start::( - target_client, - transaction_params, - enable_version_guard, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ) - .await - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::chains::kusama_headers_to_polkadot::tests::compute_maximal_balance_decrease_per_day; - - #[test] - fn maximal_balance_decrease_per_day_is_sane() { - // we expect Wococo -> Rococo relay to be running in all-headers mode - let maximal_balance_decrease = compute_maximal_balance_decrease_per_day::< - bp_kusama::Balance, - bp_kusama::WeightToFee, - >(bp_wococo::DAYS); - assert!( - MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_balance_decrease, - "Maximal expected loss per day {} is larger than hardcoded {}", - maximal_balance_decrease, - MAXIMAL_BALANCE_DECREASE_PER_DAY, - ); - } -} diff --git a/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs b/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs deleted file mode 100644 index 2c44803f2c..0000000000 --- a/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Wococo-to-Rococo messages sync entrypoint. - -use frame_support::weights::Weight; - -use messages_relay::relay_strategy::MixStrategy; -use relay_rococo_client::Rococo; -use relay_wococo_client::Wococo; -use substrate_relay_helper::messages_lane::SubstrateMessageLane; - -/// Description of Wococo -> Rococo messages bridge. -#[derive(Clone, Debug)] -pub struct WococoMessagesToRococo; -substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( - WococoMessagesToRococo, - WococoMessagesToRococoReceiveMessagesProofCallBuilder, - relay_rococo_client::runtime::Call::BridgeWococoMessages, - relay_rococo_client::runtime::BridgeWococoMessagesCall::receive_messages_proof -); -substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( - WococoMessagesToRococo, - WococoMessagesToRococoReceiveMessagesDeliveryProofCallBuilder, - relay_wococo_client::runtime::Call::BridgeRococoMessages, - relay_wococo_client::runtime::BridgeRococoMessagesCall::receive_messages_delivery_proof -); - -impl SubstrateMessageLane for WococoMessagesToRococo { - const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; - const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; - - const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None; - const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None; - const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None; - const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None; - - type SourceChain = Wococo; - type TargetChain = Rococo; - - type SourceTransactionSignScheme = Wococo; - type TargetTransactionSignScheme = Rococo; - - type ReceiveMessagesProofCallBuilder = WococoMessagesToRococoReceiveMessagesProofCallBuilder; - type ReceiveMessagesDeliveryProofCallBuilder = - WococoMessagesToRococoReceiveMessagesDeliveryProofCallBuilder; - - type TargetToSourceChainConversionRateUpdateBuilder = (); - - type RelayStrategy = MixStrategy; -} diff --git a/relays/bin-substrate/src/cli/bridge.rs b/relays/bin-substrate/src/cli/bridge.rs index 2eb836a84a..503e523c02 100644 --- a/relays/bin-substrate/src/cli/bridge.rs +++ b/relays/bin-substrate/src/cli/bridge.rs @@ -14,7 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +use crate::cli::CliChain; +use messages_relay::relay_strategy::MixStrategy; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use parachains_relay::ParachainsPipeline; +use relay_substrate_client::{AccountKeyPairOf, Chain, RelayChain, TransactionSignScheme}; use strum::{EnumString, EnumVariantNames}; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, messages_lane::SubstrateMessageLane, + parachains::SubstrateParachainsPipeline, +}; #[derive(Debug, PartialEq, Eq, EnumString, EnumVariantNames)] #[strum(serialize_all = "kebab_case")] @@ -22,10 +31,8 @@ use strum::{EnumString, EnumVariantNames}; pub enum FullBridge { MillauToRialto, RialtoToMillau, - RococoToWococo, - WococoToRococo, - KusamaToPolkadot, - PolkadotToKusama, + MillauToRialtoParachain, + RialtoParachainToMillau, } impl FullBridge { @@ -34,162 +41,73 @@ impl FullBridge { match self { Self::MillauToRialto => MILLAU_TO_RIALTO_INDEX, Self::RialtoToMillau => RIALTO_TO_MILLAU_INDEX, - Self::RococoToWococo => ROCOCO_TO_WOCOCO_INDEX, - Self::WococoToRococo => WOCOCO_TO_ROCOCO_INDEX, - Self::KusamaToPolkadot => KUSAMA_TO_POLKADOT_INDEX, - Self::PolkadotToKusama => POLKADOT_TO_KUSAMA_INDEX, + Self::MillauToRialtoParachain => MILLAU_TO_RIALTO_PARACHAIN_INDEX, + Self::RialtoParachainToMillau => RIALTO_PARACHAIN_TO_MILLAU_INDEX, } } } pub const RIALTO_TO_MILLAU_INDEX: u8 = 0; pub const MILLAU_TO_RIALTO_INDEX: u8 = 0; -pub const ROCOCO_TO_WOCOCO_INDEX: u8 = 0; -pub const WOCOCO_TO_ROCOCO_INDEX: u8 = 0; -pub const KUSAMA_TO_POLKADOT_INDEX: u8 = 0; -pub const POLKADOT_TO_KUSAMA_INDEX: u8 = 0; - -/// The macro allows executing bridge-specific code without going fully generic. -/// -/// It matches on the [`FullBridge`] enum, sets bridge-specific types or imports and injects -/// the `$generic` code at every variant. -#[macro_export] -macro_rules! select_full_bridge { - ($bridge: expr, $generic: tt) => { - match $bridge { - FullBridge::MillauToRialto => { - type Source = relay_millau_client::Millau; - #[allow(dead_code)] - type Target = relay_rialto_client::Rialto; - - // Derive-account - #[allow(unused_imports)] - use bp_rialto::derive_account_from_millau_id as derive_account; - - // Relay-messages - #[allow(unused_imports)] - use crate::chains::millau_messages_to_rialto::MillauMessagesToRialto as MessagesLane; - - // Send-message / Estimate-fee - #[allow(unused_imports)] - use bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; - // Send-message - #[allow(unused_imports)] - use millau_runtime::millau_to_rialto_account_ownership_digest as account_ownership_digest; - - $generic - } - FullBridge::RialtoToMillau => { - type Source = relay_rialto_client::Rialto; - #[allow(dead_code)] - type Target = relay_millau_client::Millau; - - // Derive-account - #[allow(unused_imports)] - use bp_millau::derive_account_from_rialto_id as derive_account; - - // Relay-messages - #[allow(unused_imports)] - use crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau as MessagesLane; - - // Send-message / Estimate-fee - #[allow(unused_imports)] - use bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; - - // Send-message - #[allow(unused_imports)] - use rialto_runtime::rialto_to_millau_account_ownership_digest as account_ownership_digest; - - $generic - } - FullBridge::RococoToWococo => { - type Source = relay_rococo_client::Rococo; - #[allow(dead_code)] - type Target = relay_wococo_client::Wococo; - - // Derive-account - #[allow(unused_imports)] - use bp_wococo::derive_account_from_rococo_id as derive_account; - - // Relay-messages - #[allow(unused_imports)] - use crate::chains::rococo_messages_to_wococo::RococoMessagesToWococo as MessagesLane; - - // Send-message / Estimate-fee - #[allow(unused_imports)] - use bp_wococo::TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; - // Send-message - #[allow(unused_imports)] - use relay_rococo_client::runtime::rococo_to_wococo_account_ownership_digest as account_ownership_digest; - - $generic - } - FullBridge::WococoToRococo => { - type Source = relay_wococo_client::Wococo; - #[allow(dead_code)] - type Target = relay_rococo_client::Rococo; - - // Derive-account - #[allow(unused_imports)] - use bp_rococo::derive_account_from_wococo_id as derive_account; - - // Relay-messages - #[allow(unused_imports)] - use crate::chains::wococo_messages_to_rococo::WococoMessagesToRococo as MessagesLane; - - // Send-message / Estimate-fee - #[allow(unused_imports)] - use bp_rococo::TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; - // Send-message - #[allow(unused_imports)] - use relay_wococo_client::runtime::wococo_to_rococo_account_ownership_digest as account_ownership_digest; - - $generic - } - FullBridge::KusamaToPolkadot => { - type Source = relay_kusama_client::Kusama; - #[allow(dead_code)] - type Target = relay_polkadot_client::Polkadot; - - // Derive-account - #[allow(unused_imports)] - use bp_polkadot::derive_account_from_kusama_id as derive_account; - - // Relay-messages - #[allow(unused_imports)] - use crate::chains::kusama_messages_to_polkadot::KusamaMessagesToPolkadot as MessagesLane; - - // Send-message / Estimate-fee - #[allow(unused_imports)] - use bp_polkadot::TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; - // Send-message - #[allow(unused_imports)] - use relay_kusama_client::runtime::kusama_to_polkadot_account_ownership_digest as account_ownership_digest; - - $generic - } - FullBridge::PolkadotToKusama => { - type Source = relay_polkadot_client::Polkadot; - #[allow(dead_code)] - type Target = relay_kusama_client::Kusama; - - // Derive-account - #[allow(unused_imports)] - use bp_kusama::derive_account_from_polkadot_id as derive_account; +pub const MILLAU_TO_RIALTO_PARACHAIN_INDEX: u8 = 1; +pub const RIALTO_PARACHAIN_TO_MILLAU_INDEX: u8 = 0; + +/// Minimal bridge representation that can be used from the CLI. +/// It connects a source chain to a target chain. +pub trait CliBridgeBase: Sized { + /// The source chain. + type Source: Chain + CliChain; + /// The target chain. + type Target: Chain + + TransactionSignScheme + + CliChain>; +} - // Relay-messages - #[allow(unused_imports)] - use crate::chains::polkadot_messages_to_kusama::PolkadotMessagesToKusama as MessagesLane; +/// Bridge representation that can be used from the CLI for relaying headers +/// from a relay chain to a relay chain. +pub trait RelayToRelayHeadersCliBridge: CliBridgeBase { + /// Finality proofs synchronization pipeline. + type Finality: SubstrateFinalitySyncPipeline< + SourceChain = Self::Source, + TargetChain = Self::Target, + TransactionSignScheme = Self::Target, + >; +} - // Send-message / Estimate-fee - #[allow(unused_imports)] - use bp_kusama::TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; - // Send-message - #[allow(unused_imports)] - use relay_polkadot_client::runtime::polkadot_to_kusama_account_ownership_digest as account_ownership_digest; +/// Bridge representation that can be used from the CLI for relaying headers +/// from a parachain to a relay chain. +pub trait ParachainToRelayHeadersCliBridge: CliBridgeBase { + // The `CliBridgeBase` type represents the parachain in this situation. + // We need to add an extra type for the relay chain. + type SourceRelay: Chain + + CliChain + + RelayChain; + /// Finality proofs synchronization pipeline (source parachain -> target). + type ParachainFinality: SubstrateParachainsPipeline< + SourceRelayChain = Self::SourceRelay, + SourceParachain = Self::Source, + TargetChain = Self::Target, + TransactionSignScheme = Self::Target, + > + ParachainsPipeline; + /// Finality proofs synchronization pipeline (source relay chain -> target). + type RelayFinality: SubstrateFinalitySyncPipeline< + SourceChain = Self::SourceRelay, + TargetChain = Self::Target, + TransactionSignScheme = Self::Target, + >; +} - $generic - } - } - }; +/// Bridge representation that can be used from the CLI for relaying messages. +pub trait MessagesCliBridge: CliBridgeBase { + /// Name of the runtime method used to estimate the message dispatch and delivery fee for the + /// defined bridge. + const ESTIMATE_MESSAGE_FEE_METHOD: &'static str; + /// The Source -> Destination messages synchronization pipeline. + type MessagesLane: SubstrateMessageLane< + SourceChain = Self::Source, + TargetChain = Self::Target, + SourceTransactionSignScheme = Self::Source, + TargetTransactionSignScheme = Self::Target, + RelayStrategy = MixStrategy, + >; } diff --git a/relays/bin-substrate/src/cli/chain_schema.rs b/relays/bin-substrate/src/cli/chain_schema.rs new file mode 100644 index 0000000000..0f108aed6d --- /dev/null +++ b/relays/bin-substrate/src/cli/chain_schema.rs @@ -0,0 +1,409 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use sp_core::Pair; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames}; + +use crate::cli::CliChain; +pub use relay_substrate_client::ChainRuntimeVersion; +use substrate_relay_helper::TransactionParams; + +#[doc = "Runtime version params."] +#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, EnumVariantNames)] +pub enum RuntimeVersionType { + /// Auto query version from chain + Auto, + /// Custom `spec_version` and `transaction_version` + Custom, + /// Read version from bundle dependencies directly. + Bundle, +} + +/// Create chain-specific set of runtime version parameters. +#[macro_export] +macro_rules! declare_chain_runtime_version_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = $chain " runtime version params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)] + pub struct [<$chain RuntimeVersionParams>] { + #[doc = "The type of runtime version for chain " $chain] + #[structopt(long, default_value = "Bundle")] + pub [<$chain_prefix _version_mode>]: RuntimeVersionType, + #[doc = "The custom sepc_version for chain " $chain] + #[structopt(long)] + pub [<$chain_prefix _spec_version>]: Option, + #[doc = "The custom transaction_version for chain " $chain] + #[structopt(long)] + pub [<$chain_prefix _transaction_version>]: Option, + } + + impl [<$chain RuntimeVersionParams>] { + /// Converts self into `ChainRuntimeVersion`. + pub fn into_runtime_version( + self, + bundle_runtime_version: Option, + ) -> anyhow::Result { + Ok(match self.[<$chain_prefix _version_mode>] { + RuntimeVersionType::Auto => ChainRuntimeVersion::Auto, + RuntimeVersionType::Custom => { + let except_spec_version = self.[<$chain_prefix _spec_version>] + .ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?; + let except_transaction_version = self.[<$chain_prefix _transaction_version>] + .ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?; + ChainRuntimeVersion::Custom( + except_spec_version, + except_transaction_version + ) + }, + RuntimeVersionType::Bundle => match bundle_runtime_version { + Some(runtime_version) => ChainRuntimeVersion::Custom( + runtime_version.spec_version, + runtime_version.transaction_version + ), + None => ChainRuntimeVersion::Auto + }, + }) + } + } + } + }; +} + +/// Create chain-specific set of runtime version parameters. +#[macro_export] +macro_rules! declare_chain_connection_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = $chain " connection params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] + pub struct [<$chain ConnectionParams>] { + #[doc = "Connect to " $chain " node at given host."] + #[structopt(long, default_value = "127.0.0.1")] + pub [<$chain_prefix _host>]: String, + #[doc = "Connect to " $chain " node websocket server at given port."] + #[structopt(long, default_value = "9944")] + pub [<$chain_prefix _port>]: u16, + #[doc = "Use secure websocket connection."] + #[structopt(long)] + pub [<$chain_prefix _secure>]: bool, + #[doc = "Custom runtime version"] + #[structopt(flatten)] + pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>], + } + + impl [<$chain ConnectionParams>] { + /// Convert connection params into Substrate client. + #[allow(dead_code)] + pub async fn into_client( + self, + ) -> anyhow::Result> { + let chain_runtime_version = self + .[<$chain_prefix _runtime_version>] + .into_runtime_version(Some(Chain::RUNTIME_VERSION))?; + Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { + host: self.[<$chain_prefix _host>], + port: self.[<$chain_prefix _port>], + secure: self.[<$chain_prefix _secure>], + chain_runtime_version, + }) + .await + ) + } + } + } + }; +} + +/// Helper trait to override transaction parameters differently. +pub trait TransactionParamsProvider { + /// Returns `true` if transaction parameters are defined by this provider. + fn is_defined(&self) -> bool; + /// Returns transaction parameters. + fn transaction_params( + &self, + ) -> anyhow::Result>; + + /// Returns transaction parameters, defined by `self` provider or, if they're not defined, + /// defined by `other` provider. + fn transaction_params_or( + &self, + other: &T, + ) -> anyhow::Result> { + if self.is_defined() { + self.transaction_params::() + } else { + other.transaction_params::() + } + } +} + +/// Create chain-specific set of signing parameters. +#[macro_export] +macro_rules! declare_chain_signing_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = $chain " signing params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] + pub struct [<$chain SigningParams>] { + #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."] + #[structopt(long)] + pub [<$chain_prefix _signer>]: Option, + #[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."] + #[structopt(long)] + pub [<$chain_prefix _signer_password>]: Option, + + #[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."] + #[structopt(long)] + pub [<$chain_prefix _signer_file>]: Option, + #[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."] + #[structopt(long)] + pub [<$chain_prefix _signer_password_file>]: Option, + + #[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."] + #[structopt(long)] + pub [<$chain_prefix _transactions_mortality>]: Option, + } + + impl [<$chain SigningParams>] { + /// Return transactions mortality. + #[allow(dead_code)] + pub fn transactions_mortality(&self) -> anyhow::Result> { + self.[<$chain_prefix _transactions_mortality>] + .map(|transactions_mortality| { + if !(4..=65536).contains(&transactions_mortality) + || !transactions_mortality.is_power_of_two() + { + Err(anyhow::format_err!( + "Transactions mortality {} is not a power of two in a [4; 65536] range", + transactions_mortality, + )) + } else { + Ok(transactions_mortality) + } + }) + .transpose() + } + + /// Parse signing params into chain-specific KeyPair. + #[allow(dead_code)] + pub fn to_keypair(&self) -> anyhow::Result { + let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) { + (Some(suri), _) => suri.to_owned(), + (None, Some(suri_file)) => std::fs::read_to_string(suri_file) + .map_err(|err| anyhow::format_err!( + "Failed to read SURI from file {:?}: {}", + suri_file, + err, + ))?, + (None, None) => return Err(anyhow::format_err!( + "One of options must be specified: '{}' or '{}'", + stringify!([<$chain_prefix _signer>]), + stringify!([<$chain_prefix _signer_file>]), + )), + }; + + let suri_password = match ( + self.[<$chain_prefix _signer_password>].as_ref(), + self.[<$chain_prefix _signer_password_file>].as_ref(), + ) { + (Some(suri_password), _) => Some(suri_password.to_owned()), + (None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file) + .map(Some) + .map_err(|err| anyhow::format_err!( + "Failed to read SURI password from file {:?}: {}", + suri_password_file, + err, + ))?, + _ => None, + }; + + use sp_core::crypto::Pair; + + Chain::KeyPair::from_string( + &suri, + suri_password.as_deref() + ).map_err(|e| anyhow::format_err!("{:?}", e)) + } + } + + #[allow(dead_code)] + impl TransactionParamsProvider for [<$chain SigningParams>] { + fn is_defined(&self) -> bool { + self.[<$chain_prefix _signer>].is_some() || self.[<$chain_prefix _signer_file>].is_some() + } + + fn transaction_params(&self) -> anyhow::Result> { + Ok(TransactionParams { + mortality: self.transactions_mortality()?, + signer: self.to_keypair::()?, + }) + } + } + } + }; +} + +/// Create chain-specific set of messages pallet owner signing parameters. +#[macro_export] +macro_rules! declare_chain_messages_pallet_owner_signing_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = "Parameters required to sign transaction on behalf of owner of the messages pallet at " $chain "."] + #[derive(StructOpt, Debug, PartialEq, Eq)] + pub struct [<$chain MessagesPalletOwnerSigningParams>] { + #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."] + #[structopt(long)] + pub [<$chain_prefix _messages_pallet_owner>]: Option, + #[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."] + #[structopt(long)] + pub [<$chain_prefix _messages_pallet_owner_password>]: Option, + } + + #[allow(dead_code)] + impl [<$chain MessagesPalletOwnerSigningParams>] { + /// Parse signing params into chain-specific KeyPair. + pub fn to_keypair(&self) -> anyhow::Result> { + let [<$chain_prefix _messages_pallet_owner>] = match self.[<$chain_prefix _messages_pallet_owner>] { + Some(ref messages_pallet_owner) => messages_pallet_owner, + None => return Ok(None), + }; + Chain::KeyPair::from_string( + [<$chain_prefix _messages_pallet_owner>], + self.[<$chain_prefix _messages_pallet_owner_password>].as_deref() + ).map_err(|e| anyhow::format_err!("{:?}", e)).map(Some) + } + } + } + }; +} + +/// Create chain-specific set of configuration objects: connection parameters, +/// signing parameters and bridge initialization parameters. +#[macro_export] +macro_rules! declare_chain_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + $crate::declare_chain_runtime_version_params_cli_schema!($chain, $chain_prefix); + $crate::declare_chain_connection_params_cli_schema!($chain, $chain_prefix); + $crate::declare_chain_signing_params_cli_schema!($chain, $chain_prefix); + $crate::declare_chain_messages_pallet_owner_signing_params_cli_schema!( + $chain, + $chain_prefix + ); + }; +} + +declare_chain_cli_schema!(Source, source); +declare_chain_cli_schema!(Target, target); +declare_chain_cli_schema!(Relaychain, relaychain); +declare_chain_cli_schema!(Parachain, parachain); + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::Pair; + + #[test] + fn reads_suri_from_file() { + const ALICE: &str = "//Alice"; + const BOB: &str = "//Bob"; + const ALICE_PASSWORD: &str = "alice_password"; + const BOB_PASSWORD: &str = "bob_password"; + + let alice: sp_core::sr25519::Pair = Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap(); + let bob: sp_core::sr25519::Pair = Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap(); + let bob_with_alice_password = + sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap(); + + let temp_dir = tempfile::tempdir().unwrap(); + let mut suri_file_path = temp_dir.path().to_path_buf(); + let mut password_file_path = temp_dir.path().to_path_buf(); + suri_file_path.push("suri"); + password_file_path.push("password"); + std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap(); + std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap(); + + // when both seed and password are read from file + assert_eq!( + TargetSigningParams { + target_signer: Some(ALICE.into()), + target_signer_password: Some(ALICE_PASSWORD.into()), + + target_signer_file: None, + target_signer_password_file: None, + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(alice.public()), + ); + + // when both seed and password are read from file + assert_eq!( + TargetSigningParams { + target_signer: None, + target_signer_password: None, + + target_signer_file: Some(suri_file_path.clone()), + target_signer_password_file: Some(password_file_path.clone()), + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(bob.public()), + ); + + // when password are is overriden by cli option + assert_eq!( + TargetSigningParams { + target_signer: None, + target_signer_password: Some(ALICE_PASSWORD.into()), + + target_signer_file: Some(suri_file_path.clone()), + target_signer_password_file: Some(password_file_path.clone()), + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(bob_with_alice_password.public()), + ); + + // when both seed and password are overriden by cli options + assert_eq!( + TargetSigningParams { + target_signer: Some(ALICE.into()), + target_signer_password: Some(ALICE_PASSWORD.into()), + + target_signer_file: Some(suri_file_path), + target_signer_password_file: Some(password_file_path), + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(alice.public()), + ); + } +} diff --git a/relays/bin-substrate/src/cli/derive_account.rs b/relays/bin-substrate/src/cli/derive_account.rs deleted file mode 100644 index 5b809eb69f..0000000000 --- a/relays/bin-substrate/src/cli/derive_account.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use crate::{ - cli::{bridge::FullBridge, AccountId}, - select_full_bridge, -}; -use relay_substrate_client::Chain; -use structopt::StructOpt; -use strum::VariantNames; - -/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain. -/// -/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call -/// that has been sent over the bridge. -/// This account can also be used to receive target-chain funds (or other form of ownership), -/// since messages sent over the bridge will be able to spend these. -#[derive(StructOpt)] -pub struct DeriveAccount { - /// A bridge instance to initialize. - #[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)] - bridge: FullBridge, - /// Source-chain address to derive Target-chain address from. - account: AccountId, -} - -impl DeriveAccount { - /// Parse CLI arguments and derive account. - /// - /// Returns both the Source account in correct SS58 format and the derived account. - fn derive_account(&self) -> (AccountId, AccountId) { - select_full_bridge!(self.bridge, { - let mut account = self.account.clone(); - account.enforce_chain::(); - let acc = bp_runtime::SourceAccount::Account(account.raw_id()); - let id = derive_account(acc); - let derived_account = AccountId::from_raw::(id); - (account, derived_account) - }) - } - - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - select_full_bridge!(self.bridge, { - let (account, derived_account) = self.derive_account(); - println!("Source address:\n{} ({})", account, Source::NAME); - println!("->Corresponding (derived) address:\n{} ({})", derived_account, Target::NAME,); - - Ok(()) - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn derive_account_cli(bridge: &str, account: &str) -> (AccountId, AccountId) { - DeriveAccount::from_iter(vec!["derive-account", bridge, account]).derive_account() - } - - #[test] - fn should_derive_accounts_correctly() { - // given - let rialto = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU"; - let millau = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9"; - - // when - let (rialto_parsed, rialto_derived) = derive_account_cli("rialto-to-millau", rialto); - let (millau_parsed, millau_derived) = derive_account_cli("millau-to-rialto", millau); - let (millau2_parsed, millau2_derived) = derive_account_cli("millau-to-rialto", rialto); - - // then - assert_eq!(format!("{}", rialto_parsed), rialto); - assert_eq!(format!("{}", millau_parsed), millau); - assert_eq!(format!("{}", millau2_parsed), millau); - - assert_eq!( - format!("{}", rialto_derived), - "74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5" - ); - assert_eq!( - format!("{}", millau_derived), - "5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2" - ); - assert_eq!(millau_derived, millau2_derived); - } -} diff --git a/relays/bin-substrate/src/cli/encode_call.rs b/relays/bin-substrate/src/cli/encode_call.rs deleted file mode 100644 index e288e2c13d..0000000000 --- a/relays/bin-substrate/src/cli/encode_call.rs +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use crate::{ - cli::{ - bridge::FullBridge, AccountId, Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, - }, - select_full_bridge, -}; -use bp_runtime::EncodedOrDecodedCall; -use frame_support::weights::DispatchInfo; -use relay_substrate_client::Chain; -use structopt::StructOpt; -use strum::VariantNames; - -/// Encode source chain runtime call. -#[derive(StructOpt, Debug)] -pub struct EncodeCall { - /// A bridge instance to encode call for. - #[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)] - bridge: FullBridge, - #[structopt(flatten)] - call: Call, -} - -/// All possible messages that may be delivered to generic Substrate chain. -/// -/// Note this enum may be used in the context of both Source (as part of `encode-call`) -/// and Target chain (as part of `encode-message/send-message`). -#[derive(StructOpt, Debug, PartialEq, Eq)] -pub enum Call { - /// Raw bytes for the message - Raw { - /// Raw, SCALE-encoded message - data: HexBytes, - }, - /// Make an on-chain remark (comment). - Remark { - /// Explicit remark payload. - #[structopt(long, conflicts_with("remark-size"))] - remark_payload: Option, - /// Remark size. If not passed, small UTF8-encoded string is generated by relay as remark. - #[structopt(long, conflicts_with("remark-payload"))] - remark_size: Option>, - }, - /// Transfer the specified `amount` of native tokens to a particular `recipient`. - Transfer { - /// Address of an account to receive the transfer. - #[structopt(long)] - recipient: AccountId, - /// Amount of target tokens to send in target chain base currency units. - #[structopt(long)] - amount: Balance, - }, - /// A call to the specific Bridge Messages pallet to queue message to be sent over a bridge. - BridgeSendMessage { - /// An index of the bridge instance which represents the expected target chain. - #[structopt(skip = 255)] - bridge_instance_index: u8, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// Raw SCALE-encoded Message Payload to submit to the messages pallet. - /// - /// This can be obtained by encoding call for the target chain. - #[structopt(long)] - payload: HexBytes, - /// Declared delivery and dispatch fee in base source-chain currency units. - #[structopt(long)] - fee: Balance, - }, -} - -pub trait CliEncodeCall: Chain { - /// Encode a CLI call. - fn encode_call(call: &Call) -> anyhow::Result>; - - /// Get dispatch info for the call. - fn get_dispatch_info(call: &EncodedOrDecodedCall) -> anyhow::Result; -} - -impl EncodeCall { - fn encode(&mut self) -> anyhow::Result { - select_full_bridge!(self.bridge, { - preprocess_call::(&mut self.call, self.bridge.bridge_instance_index()); - let call = Source::encode_call(&self.call)?; - - let encoded = HexBytes::encode(&call); - - log::info!(target: "bridge", "Generated {} call: {:#?}", Source::NAME, call); - log::info!(target: "bridge", "Weight of {} call: {}", Source::NAME, Source::get_dispatch_info(&call) - .map(|dispatch_info| format!("{}", dispatch_info.weight)) - .unwrap_or_else(|_| "".to_string()) - ); - log::info!(target: "bridge", "Encoded {} call: {:?}", Source::NAME, encoded); - - Ok(encoded) - }) - } - - /// Run the command. - pub async fn run(mut self) -> anyhow::Result<()> { - println!("{:?}", self.encode()?); - Ok(()) - } -} - -/// Prepare the call to be passed to [`CliEncodeCall::encode_call`]. -/// -/// This function will fill in all optional and missing pieces and will make sure that -/// values are converted to bridge-specific ones. -/// -/// Most importantly, the method will fill-in [`bridge_instance_index`] parameter for -/// target-chain specific calls. -pub(crate) fn preprocess_call( - call: &mut Call, - bridge_instance: u8, -) { - match *call { - Call::Raw { .. } => {}, - Call::Remark { ref remark_size, ref mut remark_payload } => - if remark_payload.is_none() { - *remark_payload = Some(HexBytes(generate_remark_payload( - remark_size, - compute_maximal_message_arguments_size( - Source::max_extrinsic_size(), - Target::max_extrinsic_size(), - ), - ))); - }, - Call::Transfer { ref mut recipient, .. } => { - recipient.enforce_chain::(); - }, - Call::BridgeSendMessage { ref mut bridge_instance_index, .. } => { - *bridge_instance_index = bridge_instance; - }, - }; -} - -fn generate_remark_payload( - remark_size: &Option>, - maximal_allowed_size: u32, -) -> Vec { - match remark_size { - Some(ExplicitOrMaximal::Explicit(remark_size)) => vec![0; *remark_size], - Some(ExplicitOrMaximal::Maximal) => vec![0; maximal_allowed_size as _], - None => format!( - "Unix time: {}", - std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_default() - .as_secs(), - ) - .as_bytes() - .to_vec(), - } -} - -pub(crate) fn compute_maximal_message_arguments_size( - maximal_source_extrinsic_size: u32, - maximal_target_extrinsic_size: u32, -) -> u32 { - // assume that both signed extensions and other arguments fit 1KB - let service_tx_bytes_on_source_chain = 1024; - let maximal_source_extrinsic_size = - maximal_source_extrinsic_size - service_tx_bytes_on_source_chain; - let maximal_call_size = bridge_runtime_common::messages::target::maximal_incoming_message_size( - maximal_target_extrinsic_size, - ); - let maximal_call_size = if maximal_call_size > maximal_source_extrinsic_size { - maximal_source_extrinsic_size - } else { - maximal_call_size - }; - - // bytes in Call encoding that are used to encode everything except arguments - let service_bytes = 1 + 1 + 4; - maximal_call_size - service_bytes -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cli::send_message::SendMessage; - - #[test] - fn should_encode_transfer_call() { - // given - let mut encode_call = EncodeCall::from_iter(vec![ - "encode-call", - "rialto-to-millau", - "transfer", - "--amount", - "12345", - "--recipient", - "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU", - ]); - - // when - let hex = encode_call.encode().unwrap(); - - // then - assert_eq!( - format!("{:?}", hex), - "0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0" - ); - } - - #[test] - fn should_encode_remark_with_default_payload() { - // given - let mut encode_call = - EncodeCall::from_iter(vec!["encode-call", "rialto-to-millau", "remark"]); - - // when - let hex = encode_call.encode().unwrap(); - - // then - assert!(format!("{:?}", hex).starts_with("0x000154556e69782074696d653a")); - } - - #[test] - fn should_encode_remark_with_explicit_payload() { - // given - let mut encode_call = EncodeCall::from_iter(vec![ - "encode-call", - "rialto-to-millau", - "remark", - "--remark-payload", - "1234", - ]); - - // when - let hex = encode_call.encode().unwrap(); - - // then - assert_eq!(format!("{:?}", hex), "0x0001081234"); - } - - #[test] - fn should_encode_remark_with_size() { - // given - let mut encode_call = EncodeCall::from_iter(vec![ - "encode-call", - "rialto-to-millau", - "remark", - "--remark-size", - "12", - ]); - - // when - let hex = encode_call.encode().unwrap(); - - // then - assert_eq!(format!("{:?}", hex), "0x000130000000000000000000000000"); - } - - #[test] - fn should_disallow_both_payload_and_size() { - // when - let err = EncodeCall::from_iter_safe(vec![ - "encode-call", - "rialto-to-millau", - "remark", - "--remark-payload", - "1234", - "--remark-size", - "12", - ]) - .unwrap_err(); - - // then - assert_eq!(err.kind, structopt::clap::ErrorKind::ArgumentConflict); - - let info = err.info.unwrap(); - assert!( - info.contains(&"remark-payload".to_string()) | - info.contains(&"remark-size".to_string()) - ) - } - - #[test] - fn should_encode_raw_call() { - // given - let mut encode_call = EncodeCall::from_iter(vec![ - "encode-call", - "rialto-to-millau", - "raw", - "040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0", - ]); - - // when - let hex = encode_call.encode().unwrap(); - - // then - assert_eq!( - format!("{:?}", hex), - "0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0" - ); - } - - #[async_std::test] - async fn should_encode_bridge_send_message_call() { - // given - let encode_message = SendMessage::from_iter(vec![ - "send-message", - "millau-to-rialto", - "--source-port", - "10946", - "--source-signer", - "//Alice", - "--target-signer", - "//Alice", - "--origin", - "Target", - "remark", - ]) - .encode_payload() - .await - .unwrap(); - - let mut encode_call = EncodeCall::from_iter(vec![ - "encode-call", - "rialto-to-millau", - "bridge-send-message", - "--fee", - "12345", - "--payload", - format!("{:}", &HexBytes::encode(&encode_message)).as_str(), - ]); - - // when - let call_hex = encode_call.encode().unwrap(); - - // then - assert!(format!("{:?}", call_hex).starts_with( - "0x0f030000000001000000000000000000000001d43593c715fdd31c61141abd04a99fd6822c8558854cc\ - de39a5684e7a56da27d01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01" - )) - } -} diff --git a/relays/bin-substrate/src/cli/encode_message.rs b/relays/bin-substrate/src/cli/encode_message.rs index 677fc29ef1..9f9ef37ff0 100644 --- a/relays/bin-substrate/src/cli/encode_message.rs +++ b/relays/bin-substrate/src/cli/encode_message.rs @@ -14,107 +14,84 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::{ - cli::{bridge::FullBridge, AccountId, CliChain, HexBytes}, - select_full_bridge, -}; -use frame_support::weights::Weight; +use crate::cli::{ExplicitOrMaximal, HexBytes}; +use bp_messages::LaneId; +use bp_runtime::EncodedOrDecodedCall; +use relay_substrate_client::Chain; use structopt::StructOpt; -use strum::VariantNames; -/// Generic message payload. +/// All possible messages that may be delivered to generic Substrate chain. +/// +/// Note this enum may be used in the context of both Source (as part of `encode-call`) +/// and Target chain (as part of `encode-message/send-message`). #[derive(StructOpt, Debug, PartialEq, Eq)] -pub enum MessagePayload { - /// Raw, SCALE-encoded `MessagePayload`. +pub enum Message { + /// Raw bytes for the message. Raw { - /// Hex-encoded SCALE data. + /// Raw message bytes. data: HexBytes, }, - /// Construct message to send over the bridge. - Call { - /// Message details. - #[structopt(flatten)] - call: crate::cli::encode_call::Call, - /// SS58 encoded Source account that will send the payload. - #[structopt(long)] - sender: AccountId, - /// Weight of the call. - /// - /// It must be specified if the chain runtime is not bundled with the relay, or if - /// you want to override bundled weight. - #[structopt(long)] - dispatch_weight: Option, + /// Message with given size. + Sized { + /// Sized of the message. + size: ExplicitOrMaximal, }, } -/// A `MessagePayload` to encode. -#[derive(StructOpt)] -pub struct EncodeMessage { - /// A bridge instance to initialize. - #[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)] - bridge: FullBridge, - #[structopt(flatten)] - payload: MessagePayload, -} +/// Raw, SCALE-encoded message payload used in expected deployment. +pub type RawMessage = Vec; -impl EncodeMessage { - /// Run the command. - pub fn encode(self) -> anyhow::Result { - select_full_bridge!(self.bridge, { - let payload = - Source::encode_message(self.payload).map_err(|e| anyhow::format_err!("{}", e))?; - Ok(HexBytes::encode(&payload)) - }) - } +pub trait CliEncodeMessage: Chain { + /// Encode a send XCM call of the XCM pallet. + fn encode_send_xcm( + message: xcm::VersionedXcm<()>, + bridge_instance_index: u8, + ) -> anyhow::Result>; - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - let payload = self.encode()?; - println!("{:?}", payload); - Ok(()) - } + /// Encode a send message call of the bridge-messages pallet. + fn encode_send_message_call( + lane: LaneId, + message: RawMessage, + fee: Self::Balance, + bridge_instance_index: u8, + ) -> anyhow::Result>; } -#[cfg(test)] -mod tests { - use super::*; - use sp_core::crypto::Ss58Codec; - - #[test] - fn should_encode_raw_message() { - // given - let msg = "01000000e88514000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d003c040130000000000000000000000000"; - let encode_message = - EncodeMessage::from_iter(vec!["encode-message", "rialto-to-millau", "raw", msg]); - - // when - let hex = encode_message.encode().unwrap(); - - // then - assert_eq!(format!("{:?}", hex), format!("0x{}", msg)); - } - - #[test] - fn should_encode_remark_with_size() { - // given - let sender = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check(); - let encode_message = EncodeMessage::from_iter(vec![ - "encode-message", - "rialto-to-millau", - "call", - "--sender", - &sender, - "--dispatch-weight", - "42", - "remark", - "--remark-size", - "12", - ]); - - // when - let hex = encode_message.encode().unwrap(); +/// Encode message payload passed through CLI flags. +pub(crate) fn encode_message( + message: &Message, +) -> anyhow::Result { + Ok(match message { + Message::Raw { ref data } => data.0.clone(), + Message::Sized { ref size } => match *size { + ExplicitOrMaximal::Explicit(size) => vec![42; size as usize], + ExplicitOrMaximal::Maximal => { + let maximal_size = compute_maximal_message_size( + Source::max_extrinsic_size(), + Target::max_extrinsic_size(), + ); + vec![42; maximal_size as usize] + }, + }, + }) +} - // then - assert_eq!(format!("{:?}", hex), "0x010000002a0000000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d003c000130000000000000000000000000"); +/// Compute maximal message size, given max extrinsic size at source and target chains. +pub(crate) fn compute_maximal_message_size( + maximal_source_extrinsic_size: u32, + maximal_target_extrinsic_size: u32, +) -> u32 { + // assume that both signed extensions and other arguments fit 1KB + let service_tx_bytes_on_source_chain = 1024; + let maximal_source_extrinsic_size = + maximal_source_extrinsic_size - service_tx_bytes_on_source_chain; + let maximal_message_size = + bridge_runtime_common::messages::target::maximal_incoming_message_size( + maximal_target_extrinsic_size, + ); + if maximal_message_size > maximal_source_extrinsic_size { + maximal_source_extrinsic_size + } else { + maximal_message_size } } diff --git a/relays/bin-substrate/src/cli/estimate_fee.rs b/relays/bin-substrate/src/cli/estimate_fee.rs index bab625314e..806df7f01f 100644 --- a/relays/bin-substrate/src/cli/estimate_fee.rs +++ b/relays/bin-substrate/src/cli/estimate_fee.rs @@ -15,16 +15,25 @@ // along with Parity Bridges Common. If not, see . use crate::{ + chains::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + }, cli::{ - bridge::FullBridge, relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO, - Balance, CliChain, HexBytes, HexLaneId, SourceConnectionParams, + bridge::{FullBridge, MessagesCliBridge}, + chain_schema::*, + relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO, + Balance, HexBytes, HexLaneId, }, - select_full_bridge, }; +use async_trait::async_trait; use bp_runtime::BalanceOf; use codec::{Decode, Encode}; -use relay_substrate_client::Chain; +use relay_substrate_client::{Chain, ChainBase}; use sp_runtime::FixedU128; +use std::fmt::Display; use structopt::StructOpt; use strum::VariantNames; use substrate_relay_helper::helpers::tokens_conversion_rate_from_metrics; @@ -48,7 +57,7 @@ pub struct EstimateFee { conversion_rate_override: Option, /// Payload to send over the bridge. #[structopt(flatten)] - payload: crate::cli::encode_message::MessagePayload, + payload: crate::cli::encode_message::Message, } /// A way to override conversion rate between bridge tokens. @@ -74,30 +83,50 @@ impl std::str::FromStr for ConversionRateOverride { } } -impl EstimateFee { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - let Self { source, bridge, lane, conversion_rate_override, payload } = self; +#[async_trait] +trait FeeEstimator: MessagesCliBridge +where + ::Balance: Display + Into, +{ + async fn estimate_fee(data: EstimateFee) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let lane = data.lane.into(); + let payload = + crate::cli::encode_message::encode_message::(&data.payload) + .map_err(|e| anyhow::format_err!("{:?}", e))?; + + let fee = estimate_message_delivery_and_dispatch_fee::( + &source_client, + data.conversion_rate_override, + Self::ESTIMATE_MESSAGE_FEE_METHOD, + lane, + &payload, + ) + .await?; - select_full_bridge!(bridge, { - let source_client = source.to_client::().await?; - let lane = lane.into(); - let payload = - Source::encode_message(payload).map_err(|e| anyhow::format_err!("{:?}", e))?; + log::info!(target: "bridge", "Fee: {:?}", Balance(fee.into())); + println!("{}", fee); + Ok(()) + } +} - let fee = estimate_message_delivery_and_dispatch_fee::( - &source_client, - conversion_rate_override, - ESTIMATE_MESSAGE_FEE_METHOD, - lane, - payload, - ) - .await?; +impl FeeEstimator for MillauToRialtoCliBridge {} +impl FeeEstimator for RialtoToMillauCliBridge {} +impl FeeEstimator for MillauToRialtoParachainCliBridge {} +impl FeeEstimator for RialtoParachainToMillauCliBridge {} - log::info!(target: "bridge", "Fee: {:?}", Balance(fee as _)); - println!("{}", fee); - Ok(()) - }) +impl EstimateFee { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + FullBridge::MillauToRialto => MillauToRialtoCliBridge::estimate_fee(self), + FullBridge::RialtoToMillau => RialtoToMillauCliBridge::estimate_fee(self), + FullBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::estimate_fee(self), + FullBridge::RialtoParachainToMillau => + RialtoParachainToMillauCliBridge::estimate_fee(self), + } + .await } } @@ -112,7 +141,7 @@ pub(crate) async fn estimate_message_delivery_and_dispatch_fee< conversion_rate_override: Option, estimate_fee_method: &str, lane: bp_messages::LaneId, - payload: P, + payload: &P, ) -> anyhow::Result> { // actual conversion rate CAN be lesser than the rate stored in the runtime. So we may try to // pay lesser fee for the message delivery. But in this case, message may be rejected by the @@ -167,7 +196,7 @@ pub(crate) async fn estimate_message_delivery_and_dispatch_fee< client, estimate_fee_method, lane, - payload.clone(), + payload, None, ) .await?; @@ -175,7 +204,7 @@ pub(crate) async fn estimate_message_delivery_and_dispatch_fee< client, estimate_fee_method, lane, - payload.clone(), + payload, conversion_rate_override, ) .await?; @@ -198,7 +227,7 @@ async fn do_estimate_message_delivery_and_dispatch_fee client: &relay_substrate_client::Client, estimate_fee_method: &str, lane: bp_messages::LaneId, - payload: P, + payload: &P, conversion_rate_override: Option, ) -> anyhow::Result> { let encoded_response = client @@ -219,14 +248,9 @@ async fn do_estimate_message_delivery_and_dispatch_fee #[cfg(test)] mod tests { use super::*; - use crate::cli::{encode_call, RuntimeVersionType, SourceRuntimeVersionParams}; - use sp_core::crypto::Ss58Codec; #[test] fn should_parse_cli_options() { - // given - let alice = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check(); - // when let res = EstimateFee::from_iter(vec![ "estimate_fee", @@ -235,13 +259,7 @@ mod tests { "1234", "--conversion-rate-override", "42.5", - "call", - "--sender", - &alice, - "--dispatch-weight", - "42", - "remark", - "--remark-payload", + "raw", "1234", ]); @@ -262,13 +280,8 @@ mod tests { source_transaction_version: None, } }, - payload: crate::cli::encode_message::MessagePayload::Call { - sender: alice.parse().unwrap(), - call: encode_call::Call::Remark { - remark_payload: Some(HexBytes(vec![0x12, 0x34])), - remark_size: None, - }, - dispatch_weight: Some(42), + payload: crate::cli::encode_message::Message::Raw { + data: HexBytes(vec![0x12, 0x34]) } } ); diff --git a/relays/bin-substrate/src/cli/init_bridge.rs b/relays/bin-substrate/src/cli/init_bridge.rs index a0129ce9ba..218130dbe5 100644 --- a/relays/bin-substrate/src/cli/init_bridge.rs +++ b/relays/bin-substrate/src/cli/init_bridge.rs @@ -14,14 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::cli::{SourceConnectionParams, TargetConnectionParams, TargetSigningParams}; -use bp_header_chain::InitializationData; +use async_trait::async_trait; + +use crate::{ + chains::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + westend_headers_to_millau::WestendToMillauCliBridge, + }, + cli::{bridge::CliBridgeBase, chain_schema::*}, +}; use bp_runtime::Chain as ChainBase; -use codec::Encode; -use relay_substrate_client::{Chain, SignParam, TransactionSignScheme, UnsignedTransaction}; -use sp_core::{Bytes, Pair}; +use relay_substrate_client::{AccountKeyPairOf, Chain, SignParam, UnsignedTransaction}; +use sp_core::Pair; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; +use substrate_relay_helper::finality::engine::{Engine, Grandpa as GrandpaFinalityEngine}; /// Initialize bridge pallet. #[derive(StructOpt)] @@ -44,175 +53,126 @@ pub enum InitBridgeName { MillauToRialto, RialtoToMillau, WestendToMillau, - RococoToWococo, - WococoToRococo, - KusamaToPolkadot, - PolkadotToKusama, + MillauToRialtoParachain, } -macro_rules! select_bridge { - ($bridge: expr, $generic: tt) => { - match $bridge { - InitBridgeName::MillauToRialto => { - type Source = relay_millau_client::Millau; - type Target = relay_rialto_client::Rialto; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - rialto_runtime::SudoCall::sudo { - call: Box::new( - rialto_runtime::BridgeGrandpaMillauCall::initialize { init_data } - .into(), - ), - } - .into() - } - - $generic +#[async_trait] +trait BridgeInitializer: CliBridgeBase +where + ::AccountId: From< as Pair>::Public>, +{ + type Engine: Engine; + + /// Get the encoded call to init the bridge. + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call; + + /// Initialize the bridge. + async fn init_bridge(data: InitBridge) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let target_client = data.target.into_client::().await?; + let target_sign = data.target_sign.to_keypair::()?; + + let (spec_version, transaction_version) = target_client.simple_runtime_version().await?; + substrate_relay_helper::finality::initialize::initialize::( + source_client, + target_client.clone(), + target_sign.public().into(), + SignParam { + spec_version, + transaction_version, + genesis_hash: *target_client.genesis_hash(), + signer: target_sign, }, - InitBridgeName::RialtoToMillau => { - type Source = relay_rialto_client::Rialto; - type Target = relay_millau_client::Millau; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - let initialize_call = millau_runtime::BridgeGrandpaCall::< - millau_runtime::Runtime, - millau_runtime::RialtoGrandpaInstance, - >::initialize { - init_data, - }; - millau_runtime::SudoCall::sudo { call: Box::new(initialize_call.into()) }.into() - } - - $generic - }, - InitBridgeName::WestendToMillau => { - type Source = relay_westend_client::Westend; - type Target = relay_millau_client::Millau; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - // at Westend -> Millau initialization we're not using sudo, because otherwise - // our deployments may fail, because we need to initialize both Rialto -> Millau - // and Westend -> Millau bridge. => since there's single possible sudo account, - // one of transaction may fail with duplicate nonce error - millau_runtime::BridgeGrandpaCall::< - millau_runtime::Runtime, - millau_runtime::WestendGrandpaInstance, - >::initialize { - init_data, - } - .into() - } - - $generic - }, - InitBridgeName::RococoToWococo => { - type Source = relay_rococo_client::Rococo; - type Target = relay_wococo_client::Wococo; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - relay_wococo_client::runtime::Call::BridgeGrandpaRococo( - relay_wococo_client::runtime::BridgeGrandpaRococoCall::initialize( - init_data, - ), - ) - } - - $generic - }, - InitBridgeName::WococoToRococo => { - type Source = relay_wococo_client::Wococo; - type Target = relay_rococo_client::Rococo; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - relay_rococo_client::runtime::Call::BridgeGrandpaWococo( - relay_rococo_client::runtime::BridgeGrandpaWococoCall::initialize( - init_data, - ), - ) - } - - $generic - }, - InitBridgeName::KusamaToPolkadot => { - type Source = relay_kusama_client::Kusama; - type Target = relay_polkadot_client::Polkadot; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa( - relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::initialize( - init_data, - ), - ) - } - - $generic - }, - InitBridgeName::PolkadotToKusama => { - type Source = relay_polkadot_client::Polkadot; - type Target = relay_kusama_client::Kusama; - - fn encode_init_bridge( - init_data: InitializationData<::Header>, - ) -> ::Call { - relay_kusama_client::runtime::Call::BridgePolkadotGrandpa( - relay_kusama_client::runtime::BridgePolkadotGrandpaCall::initialize( - init_data, - ), - ) - } - - $generic + move |transaction_nonce, initialization_data| { + Ok(UnsignedTransaction::new( + Self::encode_init_bridge(initialization_data).into(), + transaction_nonce, + )) }, + ) + .await; + + Ok(()) + } +} + +impl BridgeInitializer for MillauToRialtoCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + rialto_runtime::SudoCall::sudo { + call: Box::new(rialto_runtime::BridgeGrandpaCall::initialize { init_data }.into()), + } + .into() + } +} + +impl BridgeInitializer for MillauToRialtoParachainCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + let initialize_call = rialto_parachain_runtime::BridgeGrandpaCall::< + rialto_parachain_runtime::Runtime, + rialto_parachain_runtime::MillauGrandpaInstance, + >::initialize { + init_data, + }; + rialto_parachain_runtime::SudoCall::sudo { call: Box::new(initialize_call.into()) }.into() + } +} + +impl BridgeInitializer for RialtoToMillauCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + let initialize_call = millau_runtime::BridgeGrandpaCall::< + millau_runtime::Runtime, + millau_runtime::RialtoGrandpaInstance, + >::initialize { + init_data, + }; + millau_runtime::SudoCall::sudo { call: Box::new(initialize_call.into()) }.into() + } +} + +impl BridgeInitializer for WestendToMillauCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + // at Westend -> Millau initialization we're not using sudo, because otherwise + // our deployments may fail, because we need to initialize both Rialto -> Millau + // and Westend -> Millau bridge. => since there's single possible sudo account, + // one of transaction may fail with duplicate nonce error + millau_runtime::BridgeGrandpaCall::< + millau_runtime::Runtime, + millau_runtime::WestendGrandpaInstance, + >::initialize { + init_data, } - }; + .into() + } } impl InitBridge { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { - select_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; - let target_client = self.target.to_client::().await?; - let target_sign = self.target_sign.to_keypair::()?; - - let (spec_version, transaction_version) = - target_client.simple_runtime_version().await?; - substrate_relay_helper::headers_initialize::initialize( - source_client, - target_client.clone(), - target_sign.public().into(), - move |transaction_nonce, initialization_data| { - Ok(Bytes( - Target::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *target_client.genesis_hash(), - signer: target_sign, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - encode_init_bridge(initialization_data).into(), - transaction_nonce, - ), - })? - .encode(), - )) - }, - ) - .await; - - Ok(()) - }) + match self.bridge { + InitBridgeName::MillauToRialto => MillauToRialtoCliBridge::init_bridge(self), + InitBridgeName::RialtoToMillau => RialtoToMillauCliBridge::init_bridge(self), + InitBridgeName::WestendToMillau => WestendToMillauCliBridge::init_bridge(self), + InitBridgeName::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::init_bridge(self), + } + .await } } diff --git a/relays/bin-substrate/src/cli/mod.rs b/relays/bin-substrate/src/cli/mod.rs index df57537f58..44bfce9f38 100644 --- a/relays/bin-substrate/src/cli/mod.rs +++ b/relays/bin-substrate/src/cli/mod.rs @@ -19,28 +19,24 @@ use std::convert::TryInto; use codec::{Decode, Encode}; -use relay_substrate_client::ChainRuntimeVersion; -use sp_runtime::app_crypto::Ss58Codec; use structopt::{clap::arg_enum, StructOpt}; use strum::{EnumString, EnumVariantNames}; use bp_messages::LaneId; pub(crate) mod bridge; -pub(crate) mod encode_call; pub(crate) mod encode_message; pub(crate) mod estimate_fee; pub(crate) mod send_message; -mod derive_account; +mod chain_schema; mod init_bridge; mod register_parachain; -mod reinit_bridge; mod relay_headers; mod relay_headers_and_messages; mod relay_messages; +mod relay_parachains; mod resubmit_transactions; -mod swap_tokens; /// Parse relay CLI args. pub fn parse_args() -> Command { @@ -67,43 +63,25 @@ pub enum Command { /// and two `RelayMessages` relays. Headers are only relayed when they are required by /// the message relays - i.e. when there are messages or confirmations that needs to be /// relayed between chains. - RelayHeadersAndMessages(relay_headers_and_messages::RelayHeadersAndMessages), + RelayHeadersAndMessages(Box), /// Initialize on-chain bridge pallet with current header data. /// /// Sends initialization transaction to bootstrap the bridge with current finalized block data. InitBridge(init_bridge::InitBridge), - /// Reinitialize on-chain bridge pallet with current header data. - /// - /// Sends all missing mandatory headers to bootstrap the bridge with current finalized block - /// data. - ReinitBridge(reinit_bridge::ReinitBridge), /// Send custom message over the bridge. /// /// Allows interacting with the bridge by sending messages over `Messages` component. /// The message is being sent to the source chain, delivered to the target chain and dispatched /// there. SendMessage(send_message::SendMessage), - /// Generate SCALE-encoded `Call` for choosen network. - /// - /// The call can be used either as message payload or can be wrapped into a transaction - /// and executed on the chain directly. - EncodeCall(encode_call::EncodeCall), - /// Generate SCALE-encoded `MessagePayload` object that can be sent over selected bridge. - /// - /// The `MessagePayload` can be then fed to `Messages::send_message` function and sent over - /// the bridge. - EncodeMessage(encode_message::EncodeMessage), /// Estimate Delivery and Dispatch Fee required for message submission to messages pallet. EstimateFee(estimate_fee::EstimateFee), - /// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target - /// chain. - DeriveAccount(derive_account::DeriveAccount), /// Resubmit transactions with increased tip if they are stalled. ResubmitTransactions(resubmit_transactions::ResubmitTransactions), - /// Swap tokens using token-swap bridge. - SwapTokens(swap_tokens::SwapTokens), /// Register parachain. RegisterParachain(register_parachain::RegisterParachain), + /// + RelayParachains(relay_parachains::RelayParachains), } impl Command { @@ -132,15 +110,11 @@ impl Command { Self::RelayMessages(arg) => arg.run().await?, Self::RelayHeadersAndMessages(arg) => arg.run().await?, Self::InitBridge(arg) => arg.run().await?, - Self::ReinitBridge(arg) => arg.run().await?, Self::SendMessage(arg) => arg.run().await?, - Self::EncodeCall(arg) => arg.run().await?, - Self::EncodeMessage(arg) => arg.run().await?, Self::EstimateFee(arg) => arg.run().await?, - Self::DeriveAccount(arg) => arg.run().await?, Self::ResubmitTransactions(arg) => arg.run().await?, - Self::SwapTokens(arg) => arg.run().await?, Self::RegisterParachain(arg) => arg.run().await?, + Self::RelayParachains(arg) => arg.run().await?, } Ok(()) } @@ -184,66 +158,7 @@ impl Balance { } } -/// Generic account id with custom parser. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AccountId { - account: sp_runtime::AccountId32, - ss58_format: sp_core::crypto::Ss58AddressFormat, -} - -impl std::fmt::Display for AccountId { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "{}", self.account.to_ss58check_with_version(self.ss58_format)) - } -} - -impl std::str::FromStr for AccountId { - type Err = String; - - fn from_str(s: &str) -> Result { - let (account, ss58_format) = sp_runtime::AccountId32::from_ss58check_with_version(s) - .map_err(|err| format!("Unable to decode SS58 address: {:?}", err))?; - Ok(Self { account, ss58_format }) - } -} - -const SS58_FORMAT_PROOF: &str = "u16 -> Ss58Format is infallible; qed"; - -impl AccountId { - /// Create new SS58-formatted address from raw account id. - pub fn from_raw(account: sp_runtime::AccountId32) -> Self { - Self { account, ss58_format: T::ss58_format().try_into().expect(SS58_FORMAT_PROOF) } - } - - /// Enforces formatting account to be for given [`CliChain`] type. - /// - /// This will change the `ss58format` of the account to match the requested one. - /// Note that a warning will be produced in case the current format does not match - /// the requested one, but the conversion always succeeds. - pub fn enforce_chain(&mut self) { - let original = self.clone(); - self.ss58_format = T::ss58_format().try_into().expect(SS58_FORMAT_PROOF); - log::debug!("{} SS58 format: {} (RAW: {})", self, self.ss58_format, self.account); - if original.ss58_format != self.ss58_format { - log::warn!( - target: "bridge", - "Address {} does not seem to match {}'s SS58 format (got: {}, expected: {}).\nConverted to: {}", - original, - T::NAME, - original.ss58_format, - self.ss58_format, - self, - ) - } - } - - /// Returns the raw (no SS58-prefixed) account id. - pub fn raw_id(&self) -> sp_runtime::AccountId32 { - self.account.clone() - } -} - -/// Bridge-supported network definition. +// Bridge-supported network definition. /// /// Used to abstract away CLI commands. pub trait CliChain: relay_substrate_client::Chain { @@ -262,11 +177,6 @@ pub trait CliChain: relay_substrate_client::Chain { /// Numeric value of SS58 format. fn ss58_format() -> u16; - - /// Construct message payload to be sent over the bridge. - fn encode_message( - message: crate::cli::encode_message::MessagePayload, - ) -> anyhow::Result; } /// Lane id. @@ -313,15 +223,8 @@ impl std::fmt::Display for HexBytes { } } -impl HexBytes { - /// Encode given object and wrap into nicely formatted bytes. - pub fn encode(t: &T) -> Self { - Self(t.encode()) - } -} - /// Prometheus metrics params. -#[derive(StructOpt)] +#[derive(Clone, Debug, PartialEq, StructOpt)] pub struct PrometheusParams { /// Do not expose a Prometheus metric endpoint. #[structopt(long)] @@ -385,268 +288,10 @@ pub enum RuntimeVersionType { Bundle, } -/// Create chain-specific set of configuration objects: connection parameters, -/// signing parameters and bridge initialization parameters. -#[macro_export] -macro_rules! declare_chain_options { - ($chain:ident, $chain_prefix:ident) => { - paste::item! { - #[doc = $chain " connection params."] - #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] - pub struct [<$chain ConnectionParams>] { - #[doc = "Connect to " $chain " node at given host."] - #[structopt(long, default_value = "127.0.0.1")] - pub [<$chain_prefix _host>]: String, - #[doc = "Connect to " $chain " node websocket server at given port."] - #[structopt(long, default_value = "9944")] - pub [<$chain_prefix _port>]: u16, - #[doc = "Use secure websocket connection."] - #[structopt(long)] - pub [<$chain_prefix _secure>]: bool, - #[doc = "Custom runtime version"] - #[structopt(flatten)] - pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>], - } - - #[doc = $chain " runtime version params."] - #[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)] - pub struct [<$chain RuntimeVersionParams>] { - #[doc = "The type of runtime version for chain " $chain] - #[structopt(long, default_value = "Bundle")] - pub [<$chain_prefix _version_mode>]: RuntimeVersionType, - #[doc = "The custom sepc_version for chain " $chain] - #[structopt(long)] - pub [<$chain_prefix _spec_version>]: Option, - #[doc = "The custom transaction_version for chain " $chain] - #[structopt(long)] - pub [<$chain_prefix _transaction_version>]: Option, - } - - #[doc = $chain " signing params."] - #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] - pub struct [<$chain SigningParams>] { - #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."] - #[structopt(long)] - pub [<$chain_prefix _signer>]: Option, - #[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."] - #[structopt(long)] - pub [<$chain_prefix _signer_password>]: Option, - - #[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."] - #[structopt(long)] - pub [<$chain_prefix _signer_file>]: Option, - #[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."] - #[structopt(long)] - pub [<$chain_prefix _signer_password_file>]: Option, - - #[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."] - #[structopt(long)] - pub [<$chain_prefix _transactions_mortality>]: Option, - } - - #[doc = "Parameters required to sign transaction on behalf of owner of the messages pallet at " $chain "."] - #[derive(StructOpt, Debug, PartialEq, Eq)] - pub struct [<$chain MessagesPalletOwnerSigningParams>] { - #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."] - #[structopt(long)] - pub [<$chain_prefix _messages_pallet_owner>]: Option, - #[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."] - #[structopt(long)] - pub [<$chain_prefix _messages_pallet_owner_password>]: Option, - } - - impl [<$chain SigningParams>] { - /// Return transactions mortality. - #[allow(dead_code)] - pub fn transactions_mortality(&self) -> anyhow::Result> { - self.[<$chain_prefix _transactions_mortality>] - .map(|transactions_mortality| { - if !(4..=65536).contains(&transactions_mortality) - || !transactions_mortality.is_power_of_two() - { - Err(anyhow::format_err!( - "Transactions mortality {} is not a power of two in a [4; 65536] range", - transactions_mortality, - )) - } else { - Ok(transactions_mortality) - } - }) - .transpose() - } - - /// Parse signing params into chain-specific KeyPair. - #[allow(dead_code)] - pub fn to_keypair(&self) -> anyhow::Result { - let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) { - (Some(suri), _) => suri.to_owned(), - (None, Some(suri_file)) => std::fs::read_to_string(suri_file) - .map_err(|err| anyhow::format_err!( - "Failed to read SURI from file {:?}: {}", - suri_file, - err, - ))?, - (None, None) => return Err(anyhow::format_err!( - "One of options must be specified: '{}' or '{}'", - stringify!([<$chain_prefix _signer>]), - stringify!([<$chain_prefix _signer_file>]), - )), - }; - - let suri_password = match ( - self.[<$chain_prefix _signer_password>].as_ref(), - self.[<$chain_prefix _signer_password_file>].as_ref(), - ) { - (Some(suri_password), _) => Some(suri_password.to_owned()), - (None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file) - .map(Some) - .map_err(|err| anyhow::format_err!( - "Failed to read SURI password from file {:?}: {}", - suri_password_file, - err, - ))?, - _ => None, - }; - - use sp_core::crypto::Pair; - - Chain::KeyPair::from_string( - &suri, - suri_password.as_deref() - ).map_err(|e| anyhow::format_err!("{:?}", e)) - } - } - - #[allow(dead_code)] - impl [<$chain MessagesPalletOwnerSigningParams>] { - /// Parse signing params into chain-specific KeyPair. - pub fn to_keypair(&self) -> anyhow::Result> { - use sp_core::crypto::Pair; - - let [<$chain_prefix _messages_pallet_owner>] = match self.[<$chain_prefix _messages_pallet_owner>] { - Some(ref messages_pallet_owner) => messages_pallet_owner, - None => return Ok(None), - }; - Chain::KeyPair::from_string( - [<$chain_prefix _messages_pallet_owner>], - self.[<$chain_prefix _messages_pallet_owner_password>].as_deref() - ).map_err(|e| anyhow::format_err!("{:?}", e)).map(Some) - } - } - - impl [<$chain ConnectionParams>] { - /// Returns `true` if version guard can be started. - /// - /// There's no reason to run version guard when version mode is set to `Auto`. It can - /// lead to relay shutdown when chain is upgraded, even though we have explicitly - /// said that we don't want to shutdown. - #[allow(dead_code)] - pub fn can_start_version_guard(&self) -> bool { - self.[<$chain_prefix _runtime_version>].[<$chain_prefix _version_mode>] != RuntimeVersionType::Auto - } - - /// Convert connection params into Substrate client. - pub async fn to_client( - &self, - ) -> anyhow::Result> { - let chain_runtime_version = self - .[<$chain_prefix _runtime_version>] - .into_runtime_version(Some(Chain::RUNTIME_VERSION))?; - Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { - host: self.[<$chain_prefix _host>].clone(), - port: self.[<$chain_prefix _port>], - secure: self.[<$chain_prefix _secure>], - chain_runtime_version, - }) - .await - ) - } - - /// Return selected `chain_spec` version. - /// - /// This function only connects to the node if version mode is set to `Auto`. - #[allow(dead_code)] - pub async fn selected_chain_spec_version( - &self, - ) -> anyhow::Result { - let chain_runtime_version = self - .[<$chain_prefix _runtime_version>] - .into_runtime_version(Some(Chain::RUNTIME_VERSION))?; - Ok(match chain_runtime_version { - ChainRuntimeVersion::Auto => self - .to_client::() - .await? - .simple_runtime_version() - .await? - .0, - ChainRuntimeVersion::Custom(spec_version, _) => spec_version, - }) - } - } - - impl [<$chain RuntimeVersionParams>] { - /// Converts self into `ChainRuntimeVersion`. - pub fn into_runtime_version( - self, - bundle_runtime_version: Option, - ) -> anyhow::Result { - Ok(match self.[<$chain_prefix _version_mode>] { - RuntimeVersionType::Auto => ChainRuntimeVersion::Auto, - RuntimeVersionType::Custom => { - let except_spec_version = self.[<$chain_prefix _spec_version>] - .ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?; - let except_transaction_version = self.[<$chain_prefix _transaction_version>] - .ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?; - ChainRuntimeVersion::Custom( - except_spec_version, - except_transaction_version - ) - }, - RuntimeVersionType::Bundle => match bundle_runtime_version { - Some(runtime_version) => ChainRuntimeVersion::Custom( - runtime_version.spec_version, - runtime_version.transaction_version - ), - None => ChainRuntimeVersion::Auto - }, - }) - } - } - } - }; -} - -declare_chain_options!(Source, source); -declare_chain_options!(Target, target); -declare_chain_options!(Relaychain, relaychain); -declare_chain_options!(Parachain, parachain); - #[cfg(test)] mod tests { - use std::str::FromStr; - - use sp_core::Pair; - use super::*; - #[test] - fn should_format_addresses_with_ss58_format() { - // given - let rialto1 = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU"; - let rialto2 = "5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2"; - let millau1 = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9"; - let millau2 = "74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5"; - - let expected = vec![rialto1, rialto2, millau1, millau2]; - - // when - let parsed = expected.iter().map(|s| AccountId::from_str(s).unwrap()).collect::>(); - - let actual = parsed.iter().map(|a| format!("{}", a)).collect::>(); - - assert_eq!(actual, expected) - } - #[test] fn hex_bytes_display_matches_from_str_for_clap() { // given @@ -659,93 +304,4 @@ mod tests { // then assert_eq!(hex.0, hex2.0); } - - #[test] - fn reads_suri_from_file() { - const ALICE: &str = "//Alice"; - const BOB: &str = "//Bob"; - const ALICE_PASSWORD: &str = "alice_password"; - const BOB_PASSWORD: &str = "bob_password"; - - let alice = sp_core::sr25519::Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap(); - let bob = sp_core::sr25519::Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap(); - let bob_with_alice_password = - sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap(); - - let temp_dir = tempfile::tempdir().unwrap(); - let mut suri_file_path = temp_dir.path().to_path_buf(); - let mut password_file_path = temp_dir.path().to_path_buf(); - suri_file_path.push("suri"); - password_file_path.push("password"); - std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap(); - std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap(); - - // when both seed and password are read from file - assert_eq!( - TargetSigningParams { - target_signer: Some(ALICE.into()), - target_signer_password: Some(ALICE_PASSWORD.into()), - - target_signer_file: None, - target_signer_password_file: None, - - target_transactions_mortality: None, - } - .to_keypair::() - .map(|p| p.public()) - .map_err(drop), - Ok(alice.public()), - ); - - // when both seed and password are read from file - assert_eq!( - TargetSigningParams { - target_signer: None, - target_signer_password: None, - - target_signer_file: Some(suri_file_path.clone()), - target_signer_password_file: Some(password_file_path.clone()), - - target_transactions_mortality: None, - } - .to_keypair::() - .map(|p| p.public()) - .map_err(drop), - Ok(bob.public()), - ); - - // when password are is overriden by cli option - assert_eq!( - TargetSigningParams { - target_signer: None, - target_signer_password: Some(ALICE_PASSWORD.into()), - - target_signer_file: Some(suri_file_path.clone()), - target_signer_password_file: Some(password_file_path.clone()), - - target_transactions_mortality: None, - } - .to_keypair::() - .map(|p| p.public()) - .map_err(drop), - Ok(bob_with_alice_password.public()), - ); - - // when both seed and password are overriden by cli options - assert_eq!( - TargetSigningParams { - target_signer: Some(ALICE.into()), - target_signer_password: Some(ALICE_PASSWORD.into()), - - target_signer_file: Some(suri_file_path), - target_signer_password_file: Some(password_file_path), - - target_transactions_mortality: None, - } - .to_keypair::() - .map(|p| p.public()) - .map_err(drop), - Ok(alice.public()), - ); - } } diff --git a/relays/bin-substrate/src/cli/register_parachain.rs b/relays/bin-substrate/src/cli/register_parachain.rs index c761a5dd1a..8904365377 100644 --- a/relays/bin-substrate/src/cli/register_parachain.rs +++ b/relays/bin-substrate/src/cli/register_parachain.rs @@ -14,10 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::cli::{ - swap_tokens::wait_until_transaction_is_finalized, Balance, ParachainConnectionParams, - RelaychainConnectionParams, RelaychainSigningParams, -}; +use crate::cli::{chain_schema::*, Balance}; use codec::Encode; use frame_support::Twox64Concat; @@ -30,12 +27,13 @@ use polkadot_runtime_common::{ }; use polkadot_runtime_parachains::paras::ParaLifecycle; use relay_substrate_client::{ - AccountIdOf, CallOf, Chain, Client, SignParam, TransactionSignScheme, UnsignedTransaction, + AccountIdOf, CallOf, Chain, Client, HashOf, SignParam, Subscription, TransactionStatusOf, + UnsignedTransaction, }; use rialto_runtime::SudoCall; use sp_core::{ storage::{well_known_keys::CODE, StorageKey}, - Bytes, Pair, + Pair, }; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; @@ -46,7 +44,7 @@ const NEXT_FREE_PARA_ID_STORAGE_NAME: &str = "NextFreeParaId"; const PARAS_LIFECYCLES_STORAGE_NAME: &str = "ParaLifecycles"; /// Register parachain. -#[derive(StructOpt, Debug, PartialEq)] +#[derive(StructOpt, Debug, PartialEq, Eq)] pub struct RegisterParachain { /// A parachain to register. #[structopt(possible_values = Parachain::VARIANTS, case_insensitive = true)] @@ -69,7 +67,7 @@ pub struct RegisterParachain { } /// Parachain to register. -#[derive(Debug, EnumString, EnumVariantNames, PartialEq)] +#[derive(Debug, EnumString, EnumVariantNames, PartialEq, Eq)] #[strum(serialize_all = "kebab_case")] pub enum Parachain { RialtoParachain, @@ -94,9 +92,9 @@ impl RegisterParachain { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.parachain, { - let relay_client = self.relay_connection.to_client::().await?; + let relay_client = self.relay_connection.into_client::().await?; let relay_sign = self.relay_sign.to_keypair::()?; - let para_client = self.para_connection.to_client::().await?; + let para_client = self.para_connection.into_client::().await?; // hopefully we're the only actor that is registering parachain right now // => read next parachain id @@ -122,20 +120,16 @@ impl RegisterParachain { relay_client .submit_and_watch_signed_extrinsic( relay_sudo_account.clone(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: reserve_parachain_signer, + }, move |_, transaction_nonce| { - Ok(Bytes( - Relaychain::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: relay_genesis_hash, - signer: reserve_parachain_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - reserve_parachain_id_call.into(), - transaction_nonce, - ), - })? - .encode(), + Ok(UnsignedTransaction::new( + reserve_parachain_id_call.into(), + transaction_nonce, )) }, ) @@ -171,20 +165,16 @@ impl RegisterParachain { relay_client .submit_and_watch_signed_extrinsic( relay_sudo_account.clone(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: register_parathread_signer, + }, move |_, transaction_nonce| { - Ok(Bytes( - Relaychain::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: relay_genesis_hash, - signer: register_parathread_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - register_parathread_call.into(), - transaction_nonce, - ), - })? - .encode(), + Ok(UnsignedTransaction::new( + register_parathread_call.into(), + transaction_nonce, )) }, ) @@ -233,22 +223,18 @@ impl RegisterParachain { .into(); let force_lease_signer = relay_sign.clone(); relay_client - .submit_signed_extrinsic(relay_sudo_account.clone(), move |_, transaction_nonce| { - Ok(Bytes( - Relaychain::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: relay_genesis_hash, - signer: force_lease_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - force_lease_call.into(), - transaction_nonce, - ), - })? - .encode(), - )) - }) + .submit_signed_extrinsic( + relay_sudo_account, + SignParam:: { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: force_lease_signer, + }, + move |_, transaction_nonce| { + Ok(UnsignedTransaction::new(force_lease_call.into(), transaction_nonce)) + }, + ) .await?; log::info!(target: "bridge", "Registered parachain leases: {:?}. Waiting for onboarding", para_id); @@ -270,6 +256,46 @@ impl RegisterParachain { } } +/// Wait until transaction is included into finalized block. +/// +/// Returns the hash of the finalized block with transaction. +pub(crate) async fn wait_until_transaction_is_finalized( + subscription: Subscription>, +) -> anyhow::Result> { + loop { + let transaction_status = subscription.next().await?; + match transaction_status { + Some(TransactionStatusOf::::FinalityTimeout(_)) | + Some(TransactionStatusOf::::Usurped(_)) | + Some(TransactionStatusOf::::Dropped) | + Some(TransactionStatusOf::::Invalid) | + None => + return Err(anyhow::format_err!( + "We've been waiting for finalization of {} transaction, but it now has the {:?} status", + C::NAME, + transaction_status, + )), + Some(TransactionStatusOf::::Finalized(block_hash)) => { + log::trace!( + target: "bridge", + "{} transaction has been finalized at block {}", + C::NAME, + block_hash, + ); + return Ok(block_hash) + }, + _ => { + log::trace!( + target: "bridge", + "Received intermediate status of {} transaction: {:?}", + C::NAME, + transaction_status, + ); + }, + } + } +} + /// Wait until parachain state is changed. async fn wait_para_state( relay_client: &Client, @@ -303,9 +329,6 @@ async fn wait_para_state( #[cfg(test)] mod tests { use super::*; - use crate::cli::{ - ParachainRuntimeVersionParams, RelaychainRuntimeVersionParams, RuntimeVersionType, - }; #[test] fn register_rialto_parachain() { diff --git a/relays/bin-substrate/src/cli/reinit_bridge.rs b/relays/bin-substrate/src/cli/reinit_bridge.rs deleted file mode 100644 index 89470872cb..0000000000 --- a/relays/bin-substrate/src/cli/reinit_bridge.rs +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -use crate::{ - chains::{ - kusama_headers_to_polkadot::KusamaFinalityToPolkadot, - polkadot_headers_to_kusama::PolkadotFinalityToKusama, - }, - cli::{ - swap_tokens::wait_until_transaction_is_finalized, SourceConnectionParams, - TargetConnectionParams, TargetSigningParams, - }, -}; -use bp_header_chain::justification::GrandpaJustification; -use bp_runtime::Chain; -use codec::Encode; -use finality_relay::{SourceClient, SourceHeader}; -use frame_support::weights::Weight; -use num_traits::One; -use pallet_bridge_grandpa::weights::WeightInfo; -use relay_substrate_client::{ - AccountIdOf, BlockNumberOf, Chain as _, Client, Error as SubstrateError, HeaderOf, SignParam, - SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, -}; -use sp_core::{Bytes, Pair}; -use std::convert::{TryFrom, TryInto}; -use structopt::StructOpt; -use strum::{EnumString, EnumVariantNames, VariantNames}; -use substrate_relay_helper::{ - finality_pipeline::SubstrateFinalitySyncPipeline, finality_source::SubstrateFinalitySource, - finality_target::SubstrateFinalityTarget, messages_source::read_client_state, - TransactionParams, -}; - -/// Reinitialize bridge pallet. -#[derive(Debug, PartialEq, StructOpt)] -pub struct ReinitBridge { - /// A bridge instance to reinitialize. - #[structopt(possible_values = ReinitBridgeName::VARIANTS, case_insensitive = true)] - bridge: ReinitBridgeName, - #[structopt(flatten)] - source: SourceConnectionParams, - #[structopt(flatten)] - target: TargetConnectionParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, -} - -#[derive(Debug, EnumString, EnumVariantNames, PartialEq)] -#[strum(serialize_all = "kebab_case")] -/// Bridge to initialize. -pub enum ReinitBridgeName { - KusamaToPolkadot, - PolkadotToKusama, -} - -macro_rules! select_bridge { - ($bridge: expr, $generic: tt) => { - match $bridge { - ReinitBridgeName::KusamaToPolkadot => { - use relay_polkadot_client::runtime; - - type Finality = KusamaFinalityToPolkadot; - type Call = runtime::Call; - - fn submit_finality_proof_call( - header_and_proof: HeaderAndProof, - ) -> runtime::Call { - runtime::Call::BridgeKusamaGrandpa( - runtime::BridgeKusamaGrandpaCall::submit_finality_proof( - Box::new(header_and_proof.0.into_inner()), - header_and_proof.1, - ), - ) - } - - fn set_pallet_operation_mode_call(operational: bool) -> runtime::Call { - runtime::Call::BridgeKusamaGrandpa( - runtime::BridgeKusamaGrandpaCall::set_operational(operational), - ) - } - - fn batch_all_call(calls: Vec) -> runtime::Call { - runtime::Call::Utility(runtime::UtilityCall::batch_all(calls)) - } - - $generic - }, - ReinitBridgeName::PolkadotToKusama => { - use relay_kusama_client::runtime; - - type Finality = PolkadotFinalityToKusama; - type Call = runtime::Call; - - fn submit_finality_proof_call( - header_and_proof: HeaderAndProof, - ) -> runtime::Call { - runtime::Call::BridgePolkadotGrandpa( - runtime::BridgePolkadotGrandpaCall::submit_finality_proof( - Box::new(header_and_proof.0.into_inner()), - header_and_proof.1, - ), - ) - } - - fn set_pallet_operation_mode_call(operational: bool) -> runtime::Call { - runtime::Call::BridgePolkadotGrandpa( - runtime::BridgePolkadotGrandpaCall::set_operational(operational), - ) - } - - fn batch_all_call(calls: Vec) -> runtime::Call { - runtime::Call::Utility(runtime::UtilityCall::batch_all(calls)) - } - - $generic - }, - } - }; -} - -impl ReinitBridge { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - select_bridge!(self.bridge, { - type Source = ::SourceChain; - type Target = ::TargetChain; - - let source_client = self.source.to_client::().await?; - let target_client = self.target.to_client::().await?; - let target_sign = self.target_sign.to_keypair::()?; - let transaction_params = TransactionParams { - signer: target_sign, - mortality: self.target_sign.target_transactions_mortality, - }; - - let finality_source = - SubstrateFinalitySource::::new(source_client.clone(), None); - let finality_target = SubstrateFinalityTarget::::new( - target_client.clone(), - transaction_params.clone(), - ); - - // this subcommand assumes that the pallet at the target chain is halted - ensure_pallet_operating_mode(&finality_target, false).await?; - - // we can't call `finality_target.best_finalized_source_block_id()`, because pallet is - // halted and the call will fail => just use what it uses internally - let current_number = - best_source_block_number_at_target::(&target_client).await?; - let target_number = finality_source.best_finalized_block_number().await?; - log::info!( - target: "bridge", - "Best finalized {} header: at {}: {}, at {}: {}", - Source::NAME, - Source::NAME, - target_number, - Target::NAME, - current_number, - ); - - // prepare list of mandatory headers from the range `(current_number; target_number]` - let headers_to_submit = find_mandatory_headers_in_range( - &finality_source, - (current_number + 1, target_number), - ) - .await?; - let latest_andatory_header_number = headers_to_submit.last().map(|(h, _)| h.number()); - log::info!( - target: "bridge", - "Missing {} mandatory {} headers at {}", - headers_to_submit.len(), - Source::NAME, - Target::NAME, - ); - - // split all mandatory headers into batches - let headers_batches = - make_mandatory_headers_batches::(headers_to_submit, |(_, proof)| { - // we don't have an access to the Kusama/Polkadot chain runtimes here, so we'll - // be using Millau weights. It isn't super-critical, unless real weights are - // magnitude higher or so - pallet_bridge_grandpa::weights::MillauWeight::::submit_finality_proof( - proof.commit.precommits.len().try_into().unwrap_or(u32::MAX), - proof.votes_ancestries.len().try_into().unwrap_or(u32::MAX), - ) - }); - log::info!( - target: "bridge", - "We're going to submit {} transactions to {} node", - headers_batches.len(), - Target::NAME, - ); - - // each batch is submitted as a separate transaction - let signer_account_id: AccountIdOf = transaction_params.signer.public().into(); - let genesis_hash = *target_client.genesis_hash(); - let (spec_version, transaction_version) = - target_client.simple_runtime_version().await?; - let last_batch_index = headers_batches.len() - 1; - for (i, headers_batch) in headers_batches.into_iter().enumerate() { - let is_last_batch = i == last_batch_index; - let expected_number = - headers_batch.last().expect("all batches are non-empty").0.number(); - let transaction_params = transaction_params.clone(); - log::info!( - target: "bridge", - "Going to submit transaction that updates best {} header at {} to {}", - Source::NAME, - Target::NAME, - expected_number, - ); - - // prepare `batch_all` call - let mut batch_calls = Vec::with_capacity(headers_batch.len() + 2); - // the first call is always resumes pallet operation - batch_calls.push(set_pallet_operation_mode_call(true)); - // followed by submit-finality-proofs calls - for header_and_proof in headers_batch { - batch_calls.push(submit_finality_proof_call(header_and_proof)); - } - // if it isn't the last batch, we shall halt pallet again - if !is_last_batch { - batch_calls.push(set_pallet_operation_mode_call(false)); - } - let submit_batch_call = batch_all_call(batch_calls); - - let batch_transaction_events = target_client - .submit_and_watch_signed_extrinsic( - signer_account_id.clone(), - move |best_block_id, transaction_nonce| { - Ok(Bytes( - Target::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: transaction_params.signer.clone(), - era: TransactionEra::new( - best_block_id, - transaction_params.mortality, - ), - unsigned: UnsignedTransaction::new( - submit_batch_call.into(), - transaction_nonce, - ), - })? - .encode(), - )) - }, - ) - .await?; - wait_until_transaction_is_finalized::(batch_transaction_events).await?; - - // verify that the best finalized header at target has been updated - let current_number = - best_source_block_number_at_target::(&target_client).await?; - if current_number != expected_number { - return Err(anyhow::format_err!( - "Transaction has failed to update best {} header at {} to {}. It is {}", - Source::NAME, - Target::NAME, - expected_number, - current_number, - )) - } - - // verify that the pallet is still halted (or operational if it is the last batch) - ensure_pallet_operating_mode(&finality_target, is_last_batch).await?; - } - - if let Some(latest_andatory_header_number) = latest_andatory_header_number { - log::info!( - target: "bridge", - "Successfully updated best {} header at {} to {}. Pallet is now operational", - Source::NAME, - Target::NAME, - latest_andatory_header_number, - ); - } - - Ok(()) - }) - } -} - -/// Mandatory header and its finality proof. -type HeaderAndProof

= ( - SyncHeader::SourceChain>>, - GrandpaJustification::SourceChain>>, -); -/// Vector of mandatory headers and their finality proofs. -type HeadersAndProofs

= Vec>; - -/// Returns best finalized source header number known to the bridge GRANDPA pallet at the target -/// chain. -/// -/// This function works even if bridge GRANDPA pallet at the target chain is halted. -async fn best_source_block_number_at_target( - target_client: &Client, -) -> anyhow::Result> { - Ok(read_client_state::( - target_client, - None, - P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD, - ) - .await? - .best_finalized_peer_at_best_self - .0) -} - -/// Verify that the bridge GRANDPA pallet at the target chain is either halted, or operational. -async fn ensure_pallet_operating_mode( - finality_target: &SubstrateFinalityTarget

, - operational: bool, -) -> anyhow::Result<()> { - match (operational, finality_target.ensure_pallet_active().await) { - (true, Ok(())) => Ok(()), - (false, Err(SubstrateError::BridgePalletIsHalted)) => Ok(()), - _ => - return Err(anyhow::format_err!( - "Bridge GRANDPA pallet at {} is expected to be {}, but it isn't", - P::TargetChain::NAME, - if operational { "operational" } else { "halted" }, - )), - } -} - -/// Returns list of all mandatory headers in given range. -async fn find_mandatory_headers_in_range( - finality_source: &SubstrateFinalitySource

, - range: (BlockNumberOf, BlockNumberOf), -) -> anyhow::Result> { - let mut mandatory_headers = Vec::new(); - let mut current = range.0; - while current <= range.1 { - let (header, proof) = finality_source.header_and_finality_proof(current).await?; - if header.is_mandatory() { - match proof { - Some(proof) => mandatory_headers.push((header, proof)), - None => - return Err(anyhow::format_err!( - "Missing GRANDPA justification for {} header {}", - P::SourceChain::NAME, - current, - )), - } - } - - current += One::one(); - } - - Ok(mandatory_headers) -} - -/// Given list of mandatory headers, prepare batches of headers, so that every batch may fit into -/// single transaction. -fn make_mandatory_headers_batches< - P: SubstrateFinalitySyncPipeline, - F: Fn(&HeaderAndProof

) -> Weight, ->( - mut headers_to_submit: HeadersAndProofs

, - submit_header_weight: F, -) -> Vec> { - // now that we have all mandatory headers, let's prepare transactions - // (let's keep all our transactions below 2/3 of max tx size/weight to have some reserve - // for utility overhead + for halting transaction) - let maximal_tx_size = P::TargetChain::max_extrinsic_size() * 2 / 3; - let maximal_tx_weight = P::TargetChain::max_extrinsic_weight() * 2 / 3; - let mut current_batch_size: u32 = 0; - let mut current_batch_weight: Weight = 0; - let mut batches = Vec::new(); - let mut i = 0; - while i < headers_to_submit.len() { - let header_and_proof_size = - headers_to_submit[i].0.encode().len() + headers_to_submit[i].1.encode().len(); - let header_and_proof_weight = submit_header_weight(&headers_to_submit[i]); - - let new_batch_size = current_batch_size - .saturating_add(u32::try_from(header_and_proof_size).unwrap_or(u32::MAX)); - let new_batch_weight = current_batch_weight.saturating_add(header_and_proof_weight); - - let is_exceeding_tx_size = new_batch_size > maximal_tx_size; - let is_exceeding_tx_weight = new_batch_weight > maximal_tx_weight; - let is_new_batch_required = is_exceeding_tx_size || is_exceeding_tx_weight; - - if is_new_batch_required { - // if `i` is 0 and we're here, it is a weird situation: even single header submission is - // larger than we've planned for a bunch of headers. Let's be optimistic and hope that - // the tx will still succeed. - let spit_off_index = std::cmp::max(i, 1); - let remaining_headers_to_submit = headers_to_submit.split_off(spit_off_index); - batches.push(headers_to_submit); - - // we'll reiterate the same header again => so set `current_*` to zero - current_batch_size = 0; - current_batch_weight = 0; - headers_to_submit = remaining_headers_to_submit; - i = 0; - } else { - current_batch_size = new_batch_size; - current_batch_weight = new_batch_weight; - i += 1; - } - } - if !headers_to_submit.is_empty() { - batches.push(headers_to_submit); - } - batches -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams}; - use bp_test_utils::{make_default_justification, test_header}; - use relay_polkadot_client::Polkadot; - use sp_runtime::{traits::Header as _, DigestItem}; - - fn make_header_and_justification( - i: u32, - size: u32, - ) -> (SyncHeader, GrandpaJustification) { - let size = size as usize; - let mut header: bp_kusama::Header = test_header(i); - let justification = make_default_justification(&header); - let actual_size = header.encode().len() + justification.encode().len(); - // additional digest means some additional bytes, so let's decrease `additional_digest_size` - // a bit - let additional_digest_size = size.saturating_sub(actual_size).saturating_sub(100); - header.digest_mut().push(DigestItem::Other(vec![0u8; additional_digest_size])); - let justification = make_default_justification(&header); - println!("{} {}", size, header.encode().len() + justification.encode().len()); - (header.into(), justification) - } - - #[test] - fn should_parse_cli_options() { - // when - let res = ReinitBridge::from_iter(vec![ - "reinit-bridge", - "kusama-to-polkadot", - "--source-host", - "127.0.0.1", - "--source-port", - "42", - "--target-host", - "127.0.0.1", - "--target-port", - "43", - "--target-signer", - "//Alice", - ]); - - // then - assert_eq!( - res, - ReinitBridge { - bridge: ReinitBridgeName::KusamaToPolkadot, - source: SourceConnectionParams { - source_host: "127.0.0.1".into(), - source_port: 42, - source_secure: false, - source_runtime_version: SourceRuntimeVersionParams { - source_version_mode: RuntimeVersionType::Bundle, - source_spec_version: None, - source_transaction_version: None, - } - }, - target: TargetConnectionParams { - target_host: "127.0.0.1".into(), - target_port: 43, - target_secure: false, - target_runtime_version: TargetRuntimeVersionParams { - target_version_mode: RuntimeVersionType::Bundle, - target_spec_version: None, - target_transaction_version: None, - } - }, - target_sign: TargetSigningParams { - target_signer: Some("//Alice".into()), - target_signer_password: None, - target_signer_file: None, - target_signer_password_file: None, - target_transactions_mortality: None, - }, - } - ); - } - - #[test] - fn make_mandatory_headers_batches_and_empty_headers() { - let batches = make_mandatory_headers_batches::(vec![], |_| 0); - assert!(batches.is_empty()); - } - - #[test] - fn make_mandatory_headers_batches_with_single_batch() { - let headers_to_submit = - vec![make_header_and_justification(10, Polkadot::max_extrinsic_size() / 3)]; - let batches = - make_mandatory_headers_batches::(headers_to_submit, |_| 0); - assert_eq!(batches.into_iter().map(|x| x.len()).collect::>(), vec![1],); - } - - #[test] - fn make_mandatory_headers_batches_group_by_size() { - let headers_to_submit = vec![ - make_header_and_justification(10, Polkadot::max_extrinsic_size() / 3), - make_header_and_justification(20, Polkadot::max_extrinsic_size() / 3), - make_header_and_justification(30, Polkadot::max_extrinsic_size() * 2 / 3), - make_header_and_justification(40, Polkadot::max_extrinsic_size()), - ]; - let batches = - make_mandatory_headers_batches::(headers_to_submit, |_| 0); - assert_eq!(batches.into_iter().map(|x| x.len()).collect::>(), vec![2, 1, 1],); - } - - #[test] - fn make_mandatory_headers_batches_group_by_weight() { - let headers_to_submit = vec![ - make_header_and_justification(10, 0), - make_header_and_justification(20, 0), - make_header_and_justification(30, 0), - make_header_and_justification(40, 0), - ]; - let batches = make_mandatory_headers_batches::( - headers_to_submit, - |(header, _)| { - if header.number() == 10 || header.number() == 20 { - Polkadot::max_extrinsic_weight() / 3 - } else if header.number() == 30 { - Polkadot::max_extrinsic_weight() * 2 / 3 - } else { - Polkadot::max_extrinsic_weight() - } - }, - ); - assert_eq!(batches.into_iter().map(|x| x.len()).collect::>(), vec![2, 1, 1],); - } -} diff --git a/relays/bin-substrate/src/cli/relay_headers.rs b/relays/bin-substrate/src/cli/relay_headers.rs index 45034aba4b..df6d96f722 100644 --- a/relays/bin-substrate/src/cli/relay_headers.rs +++ b/relays/bin-substrate/src/cli/relay_headers.rs @@ -14,15 +14,22 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +use async_trait::async_trait; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf}; +use sp_core::Pair; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; +use crate::chains::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + westend_headers_to_millau::WestendToMillauCliBridge, +}; use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; -use substrate_relay_helper::finality_pipeline::SubstrateFinalitySyncPipeline; +use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline; -use crate::cli::{ - PrometheusParams, SourceConnectionParams, TargetConnectionParams, TargetSigningParams, -}; +use crate::cli::{bridge::*, chain_schema::*, PrometheusParams}; /// Start headers relayer process. #[derive(StructOpt)] @@ -51,99 +58,61 @@ pub enum RelayHeadersBridge { MillauToRialto, RialtoToMillau, WestendToMillau, - RococoToWococo, - WococoToRococo, - KusamaToPolkadot, - PolkadotToKusama, + MillauToRialtoParachain, } -macro_rules! select_bridge { - ($bridge: expr, $generic: tt) => { - match $bridge { - RelayHeadersBridge::MillauToRialto => { - type Source = relay_millau_client::Millau; - type Target = relay_rialto_client::Rialto; - type Finality = crate::chains::millau_headers_to_rialto::MillauFinalityToRialto; - - $generic - }, - RelayHeadersBridge::RialtoToMillau => { - type Source = relay_rialto_client::Rialto; - type Target = relay_millau_client::Millau; - type Finality = crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau; - - $generic - }, - RelayHeadersBridge::WestendToMillau => { - type Source = relay_westend_client::Westend; - type Target = relay_millau_client::Millau; - type Finality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau; - - $generic - }, - RelayHeadersBridge::RococoToWococo => { - type Source = relay_rococo_client::Rococo; - type Target = relay_wococo_client::Wococo; - type Finality = crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo; - - $generic - }, - RelayHeadersBridge::WococoToRococo => { - type Source = relay_wococo_client::Wococo; - type Target = relay_rococo_client::Rococo; - type Finality = crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo; - - $generic - }, - RelayHeadersBridge::KusamaToPolkadot => { - type Source = relay_kusama_client::Kusama; - type Target = relay_polkadot_client::Polkadot; - type Finality = crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot; - - $generic - }, - RelayHeadersBridge::PolkadotToKusama => { - type Source = relay_polkadot_client::Polkadot; - type Target = relay_kusama_client::Kusama; - type Finality = crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama; - - $generic - }, - } - }; +#[async_trait] +trait HeadersRelayer: RelayToRelayHeadersCliBridge +where + AccountIdOf: From< as Pair>::Public>, +{ + /// Relay headers. + async fn relay_headers(data: RelayHeaders) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let target_client = data.target.into_client::().await?; + let target_transactions_mortality = data.target_sign.target_transactions_mortality; + let target_sign = data.target_sign.to_keypair::()?; + + let metrics_params: relay_utils::metrics::MetricsParams = data.prometheus_params.into(); + GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; + + let target_transactions_params = substrate_relay_helper::TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }; + Self::Finality::start_relay_guards( + &target_client, + &target_transactions_params, + target_client.can_start_version_guard(), + ) + .await?; + + substrate_relay_helper::finality::run::( + source_client, + target_client, + data.only_mandatory_headers, + target_transactions_params, + metrics_params, + ) + .await + } } +impl HeadersRelayer for MillauToRialtoCliBridge {} +impl HeadersRelayer for RialtoToMillauCliBridge {} +impl HeadersRelayer for WestendToMillauCliBridge {} +impl HeadersRelayer for MillauToRialtoParachainCliBridge {} + impl RelayHeaders { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { - select_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; - let target_client = self.target.to_client::().await?; - let target_transactions_mortality = self.target_sign.target_transactions_mortality; - let target_sign = self.target_sign.to_keypair::()?; - - let metrics_params: relay_utils::metrics::MetricsParams = self.prometheus_params.into(); - GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; - - let target_transactions_params = substrate_relay_helper::TransactionParams { - signer: target_sign, - mortality: target_transactions_mortality, - }; - Finality::start_relay_guards( - &target_client, - &target_transactions_params, - self.target.can_start_version_guard(), - ) - .await?; - - substrate_relay_helper::finality_pipeline::run::( - source_client, - target_client, - self.only_mandatory_headers, - target_transactions_params, - metrics_params, - ) - .await - }) + match self.bridge { + RelayHeadersBridge::MillauToRialto => MillauToRialtoCliBridge::relay_headers(self), + RelayHeadersBridge::RialtoToMillau => RialtoToMillauCliBridge::relay_headers(self), + RelayHeadersBridge::WestendToMillau => WestendToMillauCliBridge::relay_headers(self), + RelayHeadersBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::relay_headers(self), + } + .await } } diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages.rs deleted file mode 100644 index 4ff6ee0947..0000000000 --- a/relays/bin-substrate/src/cli/relay_headers_and_messages.rs +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Complex headers+messages relays support. -//! -//! To add new complex relay between `ChainA` and `ChainB`, you must: -//! -//! 1) ensure that there's a `declare_chain_options!(...)` for both chains; -//! 2) add `declare_bridge_options!(...)` for the bridge; -//! 3) add bridge support to the `select_bridge! { ... }` macro. - -use futures::{FutureExt, TryFutureExt}; -use structopt::StructOpt; -use strum::VariantNames; - -use codec::Encode; -use messages_relay::relay_strategy::MixStrategy; -use relay_substrate_client::{ - AccountIdOf, CallOf, Chain, ChainRuntimeVersion, Client, SignParam, TransactionSignScheme, - UnsignedTransaction, -}; -use relay_utils::metrics::MetricsParams; -use sp_core::{Bytes, Pair}; -use substrate_relay_helper::{ - finality_pipeline::SubstrateFinalitySyncPipeline, messages_lane::MessagesRelayParams, - on_demand_headers::OnDemandHeadersRelay, TransactionParams, -}; - -use crate::{ - cli::{relay_messages::RelayerMode, CliChain, HexLaneId, PrometheusParams, RuntimeVersionType}, - declare_chain_options, -}; - -/// Maximal allowed conversion rate error ratio (abs(real - stored) / stored) that we allow. -/// -/// If it is zero, then transaction will be submitted every time we see difference between -/// stored and real conversion rates. If it is large enough (e.g. > than 10 percents, which is 0.1), -/// then rational relayers may stop relaying messages because they were submitted using -/// lesser conversion rate. -pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05; - -/// Start headers+messages relayer process. -#[derive(StructOpt)] -pub enum RelayHeadersAndMessages { - MillauRialto(MillauRialtoHeadersAndMessages), - RococoWococo(RococoWococoHeadersAndMessages), - KusamaPolkadot(KusamaPolkadotHeadersAndMessages), -} - -/// Parameters that have the same names across all bridges. -#[derive(StructOpt)] -pub struct HeadersAndMessagesSharedParams { - /// Hex-encoded lane identifiers that should be served by the complex relay. - #[structopt(long, default_value = "00000000")] - lane: Vec, - #[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")] - relayer_mode: RelayerMode, - /// Create relayers fund accounts on both chains, if it does not exists yet. - #[structopt(long)] - create_relayers_fund_accounts: bool, - /// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) - /// are relayed. - #[structopt(long)] - only_mandatory_headers: bool, - #[structopt(flatten)] - prometheus_params: PrometheusParams, -} - -// The reason behind this macro is that 'normal' relays are using source and target chains -// terminology, which is unusable for both-way relays (if you're relaying headers from Rialto to -// Millau and from Millau to Rialto, then which chain is source?). -macro_rules! declare_bridge_options { - ($chain1:ident, $chain2:ident) => { - paste::item! { - #[doc = $chain1 " and " $chain2 " headers+messages relay params."] - #[derive(StructOpt)] - pub struct [<$chain1 $chain2 HeadersAndMessages>] { - #[structopt(flatten)] - shared: HeadersAndMessagesSharedParams, - #[structopt(flatten)] - left: [<$chain1 ConnectionParams>], - #[structopt(flatten)] - left_sign: [<$chain1 SigningParams>], - #[structopt(flatten)] - left_messages_pallet_owner: [<$chain1 MessagesPalletOwnerSigningParams>], - #[structopt(flatten)] - right: [<$chain2 ConnectionParams>], - #[structopt(flatten)] - right_sign: [<$chain2 SigningParams>], - #[structopt(flatten)] - right_messages_pallet_owner: [<$chain2 MessagesPalletOwnerSigningParams>], - } - - impl From for [<$chain1 $chain2 HeadersAndMessages>] { - fn from(relay_params: RelayHeadersAndMessages) -> [<$chain1 $chain2 HeadersAndMessages>] { - match relay_params { - RelayHeadersAndMessages::[<$chain1 $chain2>](params) => params, - _ => unreachable!(), - } - } - } - } - }; -} - -macro_rules! select_bridge { - ($bridge: expr, $generic: tt) => { - match $bridge { - RelayHeadersAndMessages::MillauRialto(_) => { - type Params = MillauRialtoHeadersAndMessages; - - type Left = relay_millau_client::Millau; - type Right = relay_rialto_client::Rialto; - - type LeftToRightFinality = - crate::chains::millau_headers_to_rialto::MillauFinalityToRialto; - type RightToLeftFinality = - crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau; - - type LeftAccountIdConverter = bp_millau::AccountIdConverter; - type RightAccountIdConverter = bp_rialto::AccountIdConverter; - - use crate::chains::{ - millau_messages_to_rialto::MillauMessagesToRialto as LeftToRightMessageLane, - rialto_messages_to_millau::RialtoMessagesToMillau as RightToLeftMessageLane, - }; - - async fn left_create_account( - _left_client: Client, - _left_sign: ::AccountKeyPair, - _account_id: AccountIdOf, - ) -> anyhow::Result<()> { - Err(anyhow::format_err!("Account creation is not supported by this bridge")) - } - - async fn right_create_account( - _right_client: Client, - _right_sign: ::AccountKeyPair, - _account_id: AccountIdOf, - ) -> anyhow::Result<()> { - Err(anyhow::format_err!("Account creation is not supported by this bridge")) - } - - $generic - }, - RelayHeadersAndMessages::RococoWococo(_) => { - type Params = RococoWococoHeadersAndMessages; - - type Left = relay_rococo_client::Rococo; - type Right = relay_wococo_client::Wococo; - - type LeftToRightFinality = - crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo; - type RightToLeftFinality = - crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo; - - type LeftAccountIdConverter = bp_rococo::AccountIdConverter; - type RightAccountIdConverter = bp_wococo::AccountIdConverter; - - use crate::chains::{ - rococo_messages_to_wococo::RococoMessagesToWococo as LeftToRightMessageLane, - wococo_messages_to_rococo::WococoMessagesToRococo as RightToLeftMessageLane, - }; - - async fn left_create_account( - left_client: Client, - left_sign: ::AccountKeyPair, - account_id: AccountIdOf, - ) -> anyhow::Result<()> { - submit_signed_extrinsic( - left_client, - left_sign, - relay_rococo_client::runtime::Call::Balances( - relay_rococo_client::runtime::BalancesCall::transfer( - bp_rococo::AccountAddress::Id(account_id), - bp_rococo::EXISTENTIAL_DEPOSIT.into(), - ), - ), - ) - .await - } - - async fn right_create_account( - right_client: Client, - right_sign: ::AccountKeyPair, - account_id: AccountIdOf, - ) -> anyhow::Result<()> { - submit_signed_extrinsic( - right_client, - right_sign, - relay_wococo_client::runtime::Call::Balances( - relay_wococo_client::runtime::BalancesCall::transfer( - bp_wococo::AccountAddress::Id(account_id), - bp_wococo::EXISTENTIAL_DEPOSIT.into(), - ), - ), - ) - .await - } - - $generic - }, - RelayHeadersAndMessages::KusamaPolkadot(_) => { - type Params = KusamaPolkadotHeadersAndMessages; - - type Left = relay_kusama_client::Kusama; - type Right = relay_polkadot_client::Polkadot; - - type LeftToRightFinality = - crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot; - type RightToLeftFinality = - crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama; - - type LeftAccountIdConverter = bp_kusama::AccountIdConverter; - type RightAccountIdConverter = bp_polkadot::AccountIdConverter; - - use crate::chains::{ - kusama_messages_to_polkadot::KusamaMessagesToPolkadot as LeftToRightMessageLane, - polkadot_messages_to_kusama::PolkadotMessagesToKusama as RightToLeftMessageLane, - }; - - async fn left_create_account( - left_client: Client, - left_sign: ::AccountKeyPair, - account_id: AccountIdOf, - ) -> anyhow::Result<()> { - submit_signed_extrinsic( - left_client, - left_sign, - relay_kusama_client::runtime::Call::Balances( - relay_kusama_client::runtime::BalancesCall::transfer( - bp_kusama::AccountAddress::Id(account_id), - bp_kusama::EXISTENTIAL_DEPOSIT.into(), - ), - ), - ) - .await - } - - async fn right_create_account( - right_client: Client, - right_sign: ::AccountKeyPair, - account_id: AccountIdOf, - ) -> anyhow::Result<()> { - submit_signed_extrinsic( - right_client, - right_sign, - relay_polkadot_client::runtime::Call::Balances( - relay_polkadot_client::runtime::BalancesCall::transfer( - bp_polkadot::AccountAddress::Id(account_id), - bp_polkadot::EXISTENTIAL_DEPOSIT.into(), - ), - ), - ) - .await - } - - $generic - }, - } - }; -} - -// All supported chains. -declare_chain_options!(Millau, millau); -declare_chain_options!(Rialto, rialto); -declare_chain_options!(Rococo, rococo); -declare_chain_options!(Wococo, wococo); -declare_chain_options!(Kusama, kusama); -declare_chain_options!(Polkadot, polkadot); -// All supported bridges. -declare_bridge_options!(Millau, Rialto); -declare_bridge_options!(Rococo, Wococo); -declare_bridge_options!(Kusama, Polkadot); - -impl RelayHeadersAndMessages { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - select_bridge!(self, { - let params: Params = self.into(); - - let left_client = params.left.to_client::().await?; - let left_transactions_mortality = params.left_sign.transactions_mortality()?; - let left_sign = params.left_sign.to_keypair::()?; - let left_messages_pallet_owner = - params.left_messages_pallet_owner.to_keypair::()?; - let right_client = params.right.to_client::().await?; - let right_transactions_mortality = params.right_sign.transactions_mortality()?; - let right_sign = params.right_sign.to_keypair::()?; - let right_messages_pallet_owner = - params.right_messages_pallet_owner.to_keypair::()?; - - let lanes = params.shared.lane; - let relayer_mode = params.shared.relayer_mode.into(); - let relay_strategy = MixStrategy::new(relayer_mode); - - // create metrics registry and register standalone metrics - let metrics_params: MetricsParams = params.shared.prometheus_params.into(); - let metrics_params = relay_utils::relay_metrics(metrics_params).into_params(); - let left_to_right_metrics = - substrate_relay_helper::messages_metrics::standalone_metrics::< - LeftToRightMessageLane, - >(left_client.clone(), right_client.clone())?; - let right_to_left_metrics = left_to_right_metrics.clone().reverse(); - - // start conversion rate update loops for left/right chains - if let Some(left_messages_pallet_owner) = left_messages_pallet_owner.clone() { - let left_client = left_client.clone(); - let format_err = || { - anyhow::format_err!( - "Cannon run conversion rate updater: {} -> {}", - Right::NAME, - Left::NAME - ) - }; - substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::< - LeftToRightMessageLane, - Left, - >( - left_client.clone(), - TransactionParams { - signer: left_messages_pallet_owner.clone(), - mortality: left_transactions_mortality, - }, - left_to_right_metrics - .target_to_source_conversion_rate - .as_ref() - .ok_or_else(format_err)? - .shared_value_ref(), - left_to_right_metrics - .target_to_base_conversion_rate - .as_ref() - .ok_or_else(format_err)? - .shared_value_ref(), - left_to_right_metrics - .source_to_base_conversion_rate - .as_ref() - .ok_or_else(format_err)? - .shared_value_ref(), - CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO, - ); - } - if let Some(right_messages_pallet_owner) = right_messages_pallet_owner.clone() { - let right_client = right_client.clone(); - let format_err = || { - anyhow::format_err!( - "Cannon run conversion rate updater: {} -> {}", - Left::NAME, - Right::NAME - ) - }; - substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::< - RightToLeftMessageLane, - Right, - >( - right_client.clone(), - TransactionParams { - signer: right_messages_pallet_owner.clone(), - mortality: right_transactions_mortality, - }, - right_to_left_metrics - .target_to_source_conversion_rate - .as_ref() - .ok_or_else(format_err)? - .shared_value_ref(), - right_to_left_metrics - .target_to_base_conversion_rate - .as_ref() - .ok_or_else(format_err)? - .shared_value_ref(), - right_to_left_metrics - .source_to_base_conversion_rate - .as_ref() - .ok_or_else(format_err)? - .shared_value_ref(), - CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO, - ); - } - - // optionally, create relayers fund account - if params.shared.create_relayers_fund_accounts { - let relayer_fund_acount_id = pallet_bridge_messages::relayer_fund_account_id::< - AccountIdOf, - LeftAccountIdConverter, - >(); - let relayers_fund_account_balance = - left_client.free_native_balance(relayer_fund_acount_id.clone()).await; - if let Err(relay_substrate_client::Error::AccountDoesNotExist) = - relayers_fund_account_balance - { - log::info!(target: "bridge", "Going to create relayers fund account at {}.", Left::NAME); - left_create_account( - left_client.clone(), - left_sign.clone(), - relayer_fund_acount_id, - ) - .await?; - } - - let relayer_fund_acount_id = pallet_bridge_messages::relayer_fund_account_id::< - AccountIdOf, - RightAccountIdConverter, - >(); - let relayers_fund_account_balance = - right_client.free_native_balance(relayer_fund_acount_id.clone()).await; - if let Err(relay_substrate_client::Error::AccountDoesNotExist) = - relayers_fund_account_balance - { - log::info!(target: "bridge", "Going to create relayers fund account at {}.", Right::NAME); - right_create_account( - right_client.clone(), - right_sign.clone(), - relayer_fund_acount_id, - ) - .await?; - } - } - - // add balance-related metrics - let metrics_params = - substrate_relay_helper::messages_metrics::add_relay_balances_metrics( - left_client.clone(), - metrics_params, - Some(left_sign.public().into()), - left_messages_pallet_owner.map(|kp| kp.public().into()), - ) - .await?; - let metrics_params = - substrate_relay_helper::messages_metrics::add_relay_balances_metrics( - right_client.clone(), - metrics_params, - Some(right_sign.public().into()), - right_messages_pallet_owner.map(|kp| kp.public().into()), - ) - .await?; - - // start on-demand header relays - let left_to_right_transaction_params = TransactionParams { - mortality: right_transactions_mortality, - signer: right_sign.clone(), - }; - let right_to_left_transaction_params = TransactionParams { - mortality: left_transactions_mortality, - signer: left_sign.clone(), - }; - LeftToRightFinality::start_relay_guards( - &right_client, - &left_to_right_transaction_params, - params.right.can_start_version_guard(), - ) - .await?; - RightToLeftFinality::start_relay_guards( - &left_client, - &right_to_left_transaction_params, - params.left.can_start_version_guard(), - ) - .await?; - let left_to_right_on_demand_headers = OnDemandHeadersRelay::new::( - left_client.clone(), - right_client.clone(), - left_to_right_transaction_params, - params.shared.only_mandatory_headers, - ); - let right_to_left_on_demand_headers = OnDemandHeadersRelay::new::( - right_client.clone(), - left_client.clone(), - right_to_left_transaction_params, - params.shared.only_mandatory_headers, - ); - - // Need 2x capacity since we consider both directions for each lane - let mut message_relays = Vec::with_capacity(lanes.len() * 2); - for lane in lanes { - let lane = lane.into(); - let left_to_right_messages = substrate_relay_helper::messages_lane::run::< - LeftToRightMessageLane, - >(MessagesRelayParams { - source_client: left_client.clone(), - source_transaction_params: TransactionParams { - signer: left_sign.clone(), - mortality: left_transactions_mortality, - }, - target_client: right_client.clone(), - target_transaction_params: TransactionParams { - signer: right_sign.clone(), - mortality: right_transactions_mortality, - }, - source_to_target_headers_relay: Some(left_to_right_on_demand_headers.clone()), - target_to_source_headers_relay: Some(right_to_left_on_demand_headers.clone()), - lane_id: lane, - metrics_params: metrics_params.clone().disable(), - standalone_metrics: Some(left_to_right_metrics.clone()), - relay_strategy: relay_strategy.clone(), - }) - .map_err(|e| anyhow::format_err!("{}", e)) - .boxed(); - let right_to_left_messages = substrate_relay_helper::messages_lane::run::< - RightToLeftMessageLane, - >(MessagesRelayParams { - source_client: right_client.clone(), - source_transaction_params: TransactionParams { - signer: right_sign.clone(), - mortality: right_transactions_mortality, - }, - target_client: left_client.clone(), - target_transaction_params: TransactionParams { - signer: left_sign.clone(), - mortality: left_transactions_mortality, - }, - source_to_target_headers_relay: Some(right_to_left_on_demand_headers.clone()), - target_to_source_headers_relay: Some(left_to_right_on_demand_headers.clone()), - lane_id: lane, - metrics_params: metrics_params.clone().disable(), - standalone_metrics: Some(right_to_left_metrics.clone()), - relay_strategy: relay_strategy.clone(), - }) - .map_err(|e| anyhow::format_err!("{}", e)) - .boxed(); - - message_relays.push(left_to_right_messages); - message_relays.push(right_to_left_messages); - } - - relay_utils::relay_metrics(metrics_params) - .expose() - .await - .map_err(|e| anyhow::format_err!("{}", e))?; - - futures::future::select_all(message_relays).await.0 - }) - } -} - -/// Sign and submit transaction with given call to the chain. -async fn submit_signed_extrinsic>( - client: Client, - sign: C::AccountKeyPair, - call: CallOf, -) -> anyhow::Result<()> -where - AccountIdOf: From<<::AccountKeyPair as Pair>::Public>, - CallOf: Send, -{ - let genesis_hash = *client.genesis_hash(); - let (spec_version, transaction_version) = client.simple_runtime_version().await?; - client - .submit_signed_extrinsic(sign.public().into(), move |_, transaction_nonce| { - Ok(Bytes( - C::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: sign, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) - }) - .await - .map(drop) - .map_err(|e| anyhow::format_err!("{}", e)) -} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs new file mode 100644 index 0000000000..98a0469ae4 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs @@ -0,0 +1,737 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Complex 2-ways headers+messages relays support. +//! +//! To add new complex relay between `ChainA` and `ChainB`, you must: +//! +//! 1) ensure that there's a `declare_chain_cli_schema!(...)` for both chains. +//! 2) add `declare_chain_to_chain_bridge_schema!(...)` or +//! `declare_chain_to_parachain_bridge_schema` for the bridge. +//! 3) declare a new struct for the added bridge and implement the `Full2WayBridge` trait for it. + +#[macro_use] +mod relay_to_relay; +#[macro_use] +mod relay_to_parachain; + +use async_trait::async_trait; +use std::{marker::PhantomData, sync::Arc}; +use structopt::StructOpt; +use strum::VariantNames; + +use futures::{FutureExt, TryFutureExt}; +use relay_to_parachain::*; +use relay_to_relay::*; + +use crate::{ + chains::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + }, + cli::{ + bridge::{ + CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge, + RelayToRelayHeadersCliBridge, + }, + chain_schema::*, + relay_messages::RelayerMode, + CliChain, HexLaneId, PrometheusParams, + }, + declare_chain_cli_schema, +}; +use bp_messages::LaneId; +use bp_runtime::{BalanceOf, BlockNumberOf}; +use messages_relay::relay_strategy::MixStrategy; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, Client, TransactionSignScheme, +}; +use relay_utils::metrics::MetricsParams; +use sp_core::Pair; +use substrate_relay_helper::{ + messages_lane::MessagesRelayParams, messages_metrics::StandaloneMessagesMetrics, + on_demand::OnDemandRelay, TaggedAccount, TransactionParams, +}; + +/// Maximal allowed conversion rate error ratio (abs(real - stored) / stored) that we allow. +/// +/// If it is zero, then transaction will be submitted every time we see difference between +/// stored and real conversion rates. If it is large enough (e.g. > than 10 percents, which is 0.1), +/// then rational relayers may stop relaying messages because they were submitted using +/// lesser conversion rate. +pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05; + +/// Parameters that have the same names across all bridges. +#[derive(Debug, PartialEq, StructOpt)] +pub struct HeadersAndMessagesSharedParams { + /// Hex-encoded lane identifiers that should be served by the complex relay. + #[structopt(long, default_value = "00000000")] + pub lane: Vec, + #[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")] + pub relayer_mode: RelayerMode, + /// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) + /// are relayed. + #[structopt(long)] + pub only_mandatory_headers: bool, + #[structopt(flatten)] + pub prometheus_params: PrometheusParams, +} + +pub struct Full2WayBridgeCommonParams< + Left: TransactionSignScheme + CliChain, + Right: TransactionSignScheme + CliChain, +> { + pub shared: HeadersAndMessagesSharedParams, + pub left: BridgeEndCommonParams, + pub right: BridgeEndCommonParams, + + pub metrics_params: MetricsParams, + pub left_to_right_metrics: StandaloneMessagesMetrics, + pub right_to_left_metrics: StandaloneMessagesMetrics, +} + +impl + Full2WayBridgeCommonParams +{ + pub fn new>( + shared: HeadersAndMessagesSharedParams, + left: BridgeEndCommonParams, + right: BridgeEndCommonParams, + ) -> anyhow::Result { + // Create metrics registry. + let metrics_params = shared.prometheus_params.clone().into(); + let metrics_params = relay_utils::relay_metrics(metrics_params).into_params(); + let left_to_right_metrics = substrate_relay_helper::messages_metrics::standalone_metrics::< + L2R::MessagesLane, + >(left.client.clone(), right.client.clone())?; + let right_to_left_metrics = left_to_right_metrics.clone().reverse(); + + Ok(Self { + shared, + left, + right, + metrics_params, + left_to_right_metrics, + right_to_left_metrics, + }) + } +} + +pub struct BridgeEndCommonParams { + pub client: Client, + pub sign: AccountKeyPairOf, + pub transactions_mortality: Option, + pub messages_pallet_owner: Option>, + pub accounts: Vec>>, +} + +struct FullBridge< + 'a, + Source: TransactionSignScheme + CliChain, + Target: TransactionSignScheme + CliChain, + Bridge: MessagesCliBridge, +> { + shared: &'a HeadersAndMessagesSharedParams, + source: &'a mut BridgeEndCommonParams, + target: &'a mut BridgeEndCommonParams, + metrics_params: &'a MetricsParams, + metrics: &'a StandaloneMessagesMetrics, + _phantom_data: PhantomData, +} + +impl< + 'a, + Source: TransactionSignScheme + CliChain, + Target: TransactionSignScheme + CliChain, + Bridge: MessagesCliBridge, + > FullBridge<'a, Source, Target, Bridge> +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom> + Into, +{ + fn new( + shared: &'a HeadersAndMessagesSharedParams, + source: &'a mut BridgeEndCommonParams, + target: &'a mut BridgeEndCommonParams, + metrics_params: &'a MetricsParams, + metrics: &'a StandaloneMessagesMetrics, + ) -> Self { + Self { shared, source, target, metrics_params, metrics, _phantom_data: Default::default() } + } + + fn start_conversion_rate_update_loop(&mut self) -> anyhow::Result<()> { + if let Some(ref messages_pallet_owner) = self.source.messages_pallet_owner { + let format_err = || { + anyhow::format_err!( + "Cannon run conversion rate updater: {} -> {}", + Target::NAME, + Source::NAME + ) + }; + substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::< + Bridge::MessagesLane, + Source, + >( + self.source.client.clone(), + TransactionParams { + signer: messages_pallet_owner.clone(), + mortality: self.source.transactions_mortality, + }, + self.metrics + .target_to_source_conversion_rate + .as_ref() + .ok_or_else(format_err)? + .shared_value_ref(), + self.metrics + .target_to_base_conversion_rate + .as_ref() + .ok_or_else(format_err)? + .shared_value_ref(), + self.metrics + .source_to_base_conversion_rate + .as_ref() + .ok_or_else(format_err)? + .shared_value_ref(), + CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO, + ); + self.source.accounts.push(TaggedAccount::MessagesPalletOwner { + id: messages_pallet_owner.public().into(), + bridged_chain: Target::NAME.to_string(), + }); + } + Ok(()) + } + + fn messages_relay_params( + &self, + source_to_target_headers_relay: Arc>>, + target_to_source_headers_relay: Arc>>, + lane_id: LaneId, + ) -> MessagesRelayParams { + let relayer_mode = self.shared.relayer_mode.into(); + let relay_strategy = MixStrategy::new(relayer_mode); + + MessagesRelayParams { + source_client: self.source.client.clone(), + source_transaction_params: TransactionParams { + signer: self.source.sign.clone(), + mortality: self.source.transactions_mortality, + }, + target_client: self.target.client.clone(), + target_transaction_params: TransactionParams { + signer: self.target.sign.clone(), + mortality: self.target.transactions_mortality, + }, + source_to_target_headers_relay: Some(source_to_target_headers_relay), + target_to_source_headers_relay: Some(target_to_source_headers_relay), + lane_id, + metrics_params: self.metrics_params.clone().disable(), + standalone_metrics: Some(self.metrics.clone()), + relay_strategy, + } + } +} + +// All supported chains. +declare_chain_cli_schema!(Millau, millau); +declare_chain_cli_schema!(Rialto, rialto); +declare_chain_cli_schema!(RialtoParachain, rialto_parachain); +// Means to override signers of different layer transactions. +declare_chain_cli_schema!(MillauHeadersToRialto, millau_headers_to_rialto); +declare_chain_cli_schema!(MillauHeadersToRialtoParachain, millau_headers_to_rialto_parachain); +declare_chain_cli_schema!(RialtoHeadersToMillau, rialto_headers_to_millau); +declare_chain_cli_schema!(RialtoParachainsToMillau, rialto_parachains_to_millau); +// All supported bridges. +declare_relay_to_relay_bridge_schema!(Millau, Rialto); +declare_relay_to_parachain_bridge_schema!(Millau, RialtoParachain, Rialto); + +#[async_trait] +trait Full2WayBridgeBase: Sized + Send + Sync { + /// The CLI params for the bridge. + type Params; + /// The left relay chain. + type Left: TransactionSignScheme + + CliChain>; + /// The right destination chain (it can be a relay or a parachain). + type Right: TransactionSignScheme + + CliChain>; + + fn common(&self) -> &Full2WayBridgeCommonParams; + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams; + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>>, + Arc>>, + )>; +} + +#[async_trait] +trait Full2WayBridge: Sized + Sync +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom> + Into, + BalanceOf: TryFrom> + Into, +{ + type Base: Full2WayBridgeBase; + + /// The left relay chain. + type Left: Chain + + ChainWithBalances + + TransactionSignScheme + + CliChain>; + /// The right relay chain. + type Right: Chain + + ChainWithBalances + + TransactionSignScheme + + CliChain>; + + // Left to Right bridge + type L2R: MessagesCliBridge; + // Right to Left bridge + type R2L: MessagesCliBridge; + + fn new(params: ::Params) -> anyhow::Result; + + fn base(&self) -> &Self::Base; + + fn mut_base(&mut self) -> &mut Self::Base; + + fn left_to_right(&mut self) -> FullBridge { + let common = self.mut_base().mut_common(); + FullBridge::<_, _, Self::L2R>::new( + &common.shared, + &mut common.left, + &mut common.right, + &common.metrics_params, + &common.left_to_right_metrics, + ) + } + + fn right_to_left(&mut self) -> FullBridge { + let common = self.mut_base().mut_common(); + FullBridge::<_, _, Self::R2L>::new( + &common.shared, + &mut common.right, + &mut common.left, + &common.metrics_params, + &common.right_to_left_metrics, + ) + } + + async fn run(&mut self) -> anyhow::Result<()> { + // Register standalone metrics. + { + let common = self.mut_base().mut_common(); + common.left.accounts.push(TaggedAccount::Messages { + id: common.left.sign.public().into(), + bridged_chain: Self::Right::NAME.to_string(), + }); + common.right.accounts.push(TaggedAccount::Messages { + id: common.right.sign.public().into(), + bridged_chain: Self::Left::NAME.to_string(), + }); + } + + // start conversion rate update loops for left/right chains + self.left_to_right().start_conversion_rate_update_loop()?; + self.right_to_left().start_conversion_rate_update_loop()?; + + // start on-demand header relays + let (left_to_right_on_demand_headers, right_to_left_on_demand_headers) = + self.mut_base().start_on_demand_headers_relayers().await?; + + // add balance-related metrics + { + let common = self.mut_base().mut_common(); + substrate_relay_helper::messages_metrics::add_relay_balances_metrics( + common.left.client.clone(), + &mut common.metrics_params, + &common.left.accounts, + ) + .await?; + substrate_relay_helper::messages_metrics::add_relay_balances_metrics( + common.right.client.clone(), + &mut common.metrics_params, + &common.right.accounts, + ) + .await?; + } + + let lanes = self.base().common().shared.lane.clone(); + // Need 2x capacity since we consider both directions for each lane + let mut message_relays = Vec::with_capacity(lanes.len() * 2); + for lane in lanes { + let lane = lane.into(); + + let left_to_right_messages = substrate_relay_helper::messages_lane::run::< + ::MessagesLane, + >(self.left_to_right().messages_relay_params( + left_to_right_on_demand_headers.clone(), + right_to_left_on_demand_headers.clone(), + lane, + )) + .map_err(|e| anyhow::format_err!("{}", e)) + .boxed(); + message_relays.push(left_to_right_messages); + + let right_to_left_messages = substrate_relay_helper::messages_lane::run::< + ::MessagesLane, + >(self.right_to_left().messages_relay_params( + right_to_left_on_demand_headers.clone(), + left_to_right_on_demand_headers.clone(), + lane, + )) + .map_err(|e| anyhow::format_err!("{}", e)) + .boxed(); + message_relays.push(right_to_left_messages); + } + + relay_utils::relay_metrics(self.base().common().metrics_params.clone()) + .expose() + .await + .map_err(|e| anyhow::format_err!("{}", e))?; + + futures::future::select_all(message_relays).await.0 + } +} + +pub struct MillauRialtoFull2WayBridge { + base: ::Base, +} + +#[async_trait] +impl Full2WayBridge for MillauRialtoFull2WayBridge { + type Base = RelayToRelayBridge; + type Left = relay_millau_client::Millau; + type Right = relay_rialto_client::Rialto; + type L2R = MillauToRialtoCliBridge; + type R2L = RialtoToMillauCliBridge; + + fn new(base: Self::Base) -> anyhow::Result { + Ok(Self { base }) + } + + fn base(&self) -> &Self::Base { + &self.base + } + + fn mut_base(&mut self) -> &mut Self::Base { + &mut self.base + } +} + +pub struct MillauRialtoParachainFull2WayBridge { + base: ::Base, +} + +#[async_trait] +impl Full2WayBridge for MillauRialtoParachainFull2WayBridge { + type Base = RelayToParachainBridge; + type Left = relay_millau_client::Millau; + type Right = relay_rialto_parachain_client::RialtoParachain; + type L2R = MillauToRialtoParachainCliBridge; + type R2L = RialtoParachainToMillauCliBridge; + + fn new(base: Self::Base) -> anyhow::Result { + Ok(Self { base }) + } + + fn base(&self) -> &Self::Base { + &self.base + } + + fn mut_base(&mut self) -> &mut Self::Base { + &mut self.base + } +} + +/// Start headers+messages relayer process. +#[derive(Debug, PartialEq, StructOpt)] +pub enum RelayHeadersAndMessages { + MillauRialto(MillauRialtoHeadersAndMessages), + MillauRialtoParachain(MillauRialtoParachainHeadersAndMessages), +} + +impl RelayHeadersAndMessages { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + RelayHeadersAndMessages::MillauRialto(params) => + MillauRialtoFull2WayBridge::new(params.into_bridge().await?)?.run().await, + RelayHeadersAndMessages::MillauRialtoParachain(params) => + MillauRialtoParachainFull2WayBridge::new(params.into_bridge().await?)? + .run() + .await, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_parse_relay_to_relay_options() { + // when + let res = RelayHeadersAndMessages::from_iter(vec![ + "relay-headers-and-messages", + "millau-rialto", + "--millau-host", + "millau-node-alice", + "--millau-port", + "9944", + "--millau-signer", + "//Charlie", + "--millau-messages-pallet-owner", + "//RialtoMessagesOwner", + "--millau-transactions-mortality", + "64", + "--rialto-host", + "rialto-node-alice", + "--rialto-port", + "9944", + "--rialto-signer", + "//Charlie", + "--rialto-messages-pallet-owner", + "//MillauMessagesOwner", + "--rialto-transactions-mortality", + "64", + "--lane", + "00000000", + "--lane", + "73776170", + "--prometheus-host", + "0.0.0.0", + ]); + + // then + assert_eq!( + res, + RelayHeadersAndMessages::MillauRialto(MillauRialtoHeadersAndMessages { + shared: HeadersAndMessagesSharedParams { + lane: vec![ + HexLaneId([0x00, 0x00, 0x00, 0x00]), + HexLaneId([0x73, 0x77, 0x61, 0x70]) + ], + relayer_mode: RelayerMode::Rational, + only_mandatory_headers: false, + prometheus_params: PrometheusParams { + no_prometheus: false, + prometheus_host: "0.0.0.0".into(), + prometheus_port: 9616, + }, + }, + left: MillauConnectionParams { + millau_host: "millau-node-alice".into(), + millau_port: 9944, + millau_secure: false, + millau_runtime_version: MillauRuntimeVersionParams { + millau_version_mode: RuntimeVersionType::Bundle, + millau_spec_version: None, + millau_transaction_version: None, + }, + }, + left_sign: MillauSigningParams { + millau_signer: Some("//Charlie".into()), + millau_signer_password: None, + millau_signer_file: None, + millau_signer_password_file: None, + millau_transactions_mortality: Some(64), + }, + left_messages_pallet_owner: MillauMessagesPalletOwnerSigningParams { + millau_messages_pallet_owner: Some("//RialtoMessagesOwner".into()), + millau_messages_pallet_owner_password: None, + }, + left_headers_to_right_sign_override: MillauHeadersToRialtoSigningParams { + millau_headers_to_rialto_signer: None, + millau_headers_to_rialto_signer_password: None, + millau_headers_to_rialto_signer_file: None, + millau_headers_to_rialto_signer_password_file: None, + millau_headers_to_rialto_transactions_mortality: None, + }, + right: RialtoConnectionParams { + rialto_host: "rialto-node-alice".into(), + rialto_port: 9944, + rialto_secure: false, + rialto_runtime_version: RialtoRuntimeVersionParams { + rialto_version_mode: RuntimeVersionType::Bundle, + rialto_spec_version: None, + rialto_transaction_version: None, + }, + }, + right_sign: RialtoSigningParams { + rialto_signer: Some("//Charlie".into()), + rialto_signer_password: None, + rialto_signer_file: None, + rialto_signer_password_file: None, + rialto_transactions_mortality: Some(64), + }, + right_messages_pallet_owner: RialtoMessagesPalletOwnerSigningParams { + rialto_messages_pallet_owner: Some("//MillauMessagesOwner".into()), + rialto_messages_pallet_owner_password: None, + }, + right_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams { + rialto_headers_to_millau_signer: None, + rialto_headers_to_millau_signer_password: None, + rialto_headers_to_millau_signer_file: None, + rialto_headers_to_millau_signer_password_file: None, + rialto_headers_to_millau_transactions_mortality: None, + }, + }), + ); + } + + #[test] + fn should_parse_relay_to_parachain_options() { + // when + let res = RelayHeadersAndMessages::from_iter(vec![ + "relay-headers-and-messages", + "millau-rialto-parachain", + "--millau-host", + "millau-node-alice", + "--millau-port", + "9944", + "--millau-signer", + "//Iden", + "--rialto-headers-to-millau-signer", + "//Ken", + "--millau-messages-pallet-owner", + "//RialtoParachainMessagesOwner", + "--millau-transactions-mortality", + "64", + "--rialto-parachain-host", + "rialto-parachain-collator-charlie", + "--rialto-parachain-port", + "9944", + "--rialto-parachain-signer", + "//George", + "--rialto-parachain-messages-pallet-owner", + "//MillauMessagesOwner", + "--rialto-parachain-transactions-mortality", + "64", + "--rialto-host", + "rialto-node-alice", + "--rialto-port", + "9944", + "--lane", + "00000000", + "--prometheus-host", + "0.0.0.0", + ]); + + // then + assert_eq!( + res, + RelayHeadersAndMessages::MillauRialtoParachain( + MillauRialtoParachainHeadersAndMessages { + shared: HeadersAndMessagesSharedParams { + lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])], + relayer_mode: RelayerMode::Rational, + only_mandatory_headers: false, + prometheus_params: PrometheusParams { + no_prometheus: false, + prometheus_host: "0.0.0.0".into(), + prometheus_port: 9616, + }, + }, + left: MillauConnectionParams { + millau_host: "millau-node-alice".into(), + millau_port: 9944, + millau_secure: false, + millau_runtime_version: MillauRuntimeVersionParams { + millau_version_mode: RuntimeVersionType::Bundle, + millau_spec_version: None, + millau_transaction_version: None, + }, + }, + left_sign: MillauSigningParams { + millau_signer: Some("//Iden".into()), + millau_signer_password: None, + millau_signer_file: None, + millau_signer_password_file: None, + millau_transactions_mortality: Some(64), + }, + left_messages_pallet_owner: MillauMessagesPalletOwnerSigningParams { + millau_messages_pallet_owner: Some("//RialtoParachainMessagesOwner".into()), + millau_messages_pallet_owner_password: None, + }, + left_headers_to_right_sign_override: + MillauHeadersToRialtoParachainSigningParams { + millau_headers_to_rialto_parachain_signer: None, + millau_headers_to_rialto_parachain_signer_password: None, + millau_headers_to_rialto_parachain_signer_file: None, + millau_headers_to_rialto_parachain_signer_password_file: None, + millau_headers_to_rialto_parachain_transactions_mortality: None, + }, + right: RialtoParachainConnectionParams { + rialto_parachain_host: "rialto-parachain-collator-charlie".into(), + rialto_parachain_port: 9944, + rialto_parachain_secure: false, + rialto_parachain_runtime_version: RialtoParachainRuntimeVersionParams { + rialto_parachain_version_mode: RuntimeVersionType::Bundle, + rialto_parachain_spec_version: None, + rialto_parachain_transaction_version: None, + }, + }, + right_sign: RialtoParachainSigningParams { + rialto_parachain_signer: Some("//George".into()), + rialto_parachain_signer_password: None, + rialto_parachain_signer_file: None, + rialto_parachain_signer_password_file: None, + rialto_parachain_transactions_mortality: Some(64), + }, + right_messages_pallet_owner: RialtoParachainMessagesPalletOwnerSigningParams { + rialto_parachain_messages_pallet_owner: Some( + "//MillauMessagesOwner".into() + ), + rialto_parachain_messages_pallet_owner_password: None, + }, + right_relay_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams { + rialto_headers_to_millau_signer: Some("//Ken".into()), + rialto_headers_to_millau_signer_password: None, + rialto_headers_to_millau_signer_file: None, + rialto_headers_to_millau_signer_password_file: None, + rialto_headers_to_millau_transactions_mortality: None, + }, + right_parachains_to_left_sign_override: RialtoParachainsToMillauSigningParams { + rialto_parachains_to_millau_signer: None, + rialto_parachains_to_millau_signer_password: None, + rialto_parachains_to_millau_signer_file: None, + rialto_parachains_to_millau_signer_password_file: None, + rialto_parachains_to_millau_transactions_mortality: None, + }, + right_relay: RialtoConnectionParams { + rialto_host: "rialto-node-alice".into(), + rialto_port: 9944, + rialto_secure: false, + rialto_runtime_version: RialtoRuntimeVersionParams { + rialto_version_mode: RuntimeVersionType::Bundle, + rialto_spec_version: None, + rialto_transaction_version: None, + }, + }, + } + ), + ); + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs new file mode 100644 index 0000000000..4123dae5a7 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs @@ -0,0 +1,239 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use async_trait::async_trait; +use std::sync::Arc; + +use crate::cli::{ + bridge::{ + CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge, + RelayToRelayHeadersCliBridge, + }, + relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, + CliChain, +}; +use bp_polkadot_core::parachains::ParaHash; +use bp_runtime::BlockNumberOf; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, Chain, Client, TransactionSignScheme}; +use sp_core::Pair; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, + on_demand::{ + headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, + }, + TaggedAccount, TransactionParams, +}; + +pub struct RelayToParachainBridge< + L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge, +> { + pub common: + Full2WayBridgeCommonParams<::Target, ::Target>, + pub right_relay: Client<::SourceRelay>, + + // override for right_relay->left headers signer + pub right_headers_to_left_transaction_params: + TransactionParams::Target>>, + // override for right->left parachains signer + pub right_parachains_to_left_transaction_params: + TransactionParams::Target>>, + // override for left->right headers signer + pub left_headers_to_right_transaction_params: + TransactionParams::Target>>, +} + +macro_rules! declare_relay_to_parachain_bridge_schema { + // chain, parachain, relay-chain-of-parachain + ($left_chain:ident, $right_parachain:ident, $right_chain:ident) => { + bp_runtime::paste::item! { + #[doc = $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."] + #[derive(Debug, PartialEq, StructOpt)] + pub struct [<$left_chain $right_parachain HeadersAndMessages>] { + #[structopt(flatten)] + shared: HeadersAndMessagesSharedParams, + #[structopt(flatten)] + left: [<$left_chain ConnectionParams>], + // default signer, which is always used to sign messages relay transactions on the left chain + #[structopt(flatten)] + left_sign: [<$left_chain SigningParams>], + // override for right_relay->left headers signer + #[structopt(flatten)] + right_relay_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>], + // override for right->left parachains signer + #[structopt(flatten)] + right_parachains_to_left_sign_override: [<$right_chain ParachainsTo $left_chain SigningParams>], + #[structopt(flatten)] + left_messages_pallet_owner: [<$left_chain MessagesPalletOwnerSigningParams>], + #[structopt(flatten)] + right: [<$right_parachain ConnectionParams>], + // default signer, which is always used to sign messages relay transactions on the right chain + #[structopt(flatten)] + right_sign: [<$right_parachain SigningParams>], + // override for left->right headers signer + #[structopt(flatten)] + left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_parachain SigningParams>], + #[structopt(flatten)] + right_messages_pallet_owner: [<$right_parachain MessagesPalletOwnerSigningParams>], + #[structopt(flatten)] + right_relay: [<$right_chain ConnectionParams>], + } + + impl [<$left_chain $right_parachain HeadersAndMessages>] { + async fn into_bridge< + Left: TransactionSignScheme + CliChain>, + Right: TransactionSignScheme + CliChain>, + RightRelay: TransactionSignScheme + CliChain, + L2R: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + >( + self, + ) -> anyhow::Result> { + Ok(RelayToParachainBridge { + common: Full2WayBridgeCommonParams::new::( + self.shared, + BridgeEndCommonParams { + client: self.left.into_client::().await?, + sign: self.left_sign.to_keypair::()?, + transactions_mortality: self.left_sign.transactions_mortality()?, + messages_pallet_owner: self.left_messages_pallet_owner.to_keypair::()?, + accounts: vec![], + }, + BridgeEndCommonParams { + client: self.right.into_client::().await?, + sign: self.right_sign.to_keypair::()?, + transactions_mortality: self.right_sign.transactions_mortality()?, + messages_pallet_owner: self.right_messages_pallet_owner.to_keypair::()?, + accounts: vec![], + }, + )?, + right_relay: self.right_relay.into_client::().await?, + right_headers_to_left_transaction_params: self + .right_relay_headers_to_left_sign_override + .transaction_params_or::( + &self.left_sign, + )?, + right_parachains_to_left_transaction_params: self + .right_parachains_to_left_sign_override + .transaction_params_or::( + &self.left_sign, + )?, + left_headers_to_right_transaction_params: self + .left_headers_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + }) + } + } + } + }; +} + +#[async_trait] +impl< + Left: Chain + TransactionSignScheme + CliChain>, + Right: Chain + + TransactionSignScheme + + CliChain>, + RightRelay: Chain + + TransactionSignScheme + + CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + > Full2WayBridgeBase for RelayToParachainBridge +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, +{ + type Params = RelayToParachainBridge; + type Left = Left; + type Right = Right; + + fn common(&self) -> &Full2WayBridgeCommonParams { + &self.common + } + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams { + &mut self.common + } + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>>, + Arc>>, + )> { + self.common.left.accounts.push(TaggedAccount::Headers { + id: self.right_headers_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.left.accounts.push(TaggedAccount::Parachains { + id: self.right_parachains_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.right.accounts.push(TaggedAccount::Headers { + id: self.left_headers_to_right_transaction_params.signer.public().into(), + bridged_chain: Left::NAME.to_string(), + }); + + ::Finality::start_relay_guards( + &self.common.right.client, + &self.left_headers_to_right_transaction_params, + self.common.right.client.can_start_version_guard(), + ) + .await?; + ::RelayFinality::start_relay_guards( + &self.common.left.client, + &self.right_headers_to_left_transaction_params, + self.common.left.client.can_start_version_guard(), + ) + .await?; + + let left_to_right_on_demand_headers = + OnDemandHeadersRelay::new::<::Finality>( + self.common.left.client.clone(), + self.common.right.client.clone(), + self.left_headers_to_right_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + ); + let right_relay_to_left_on_demand_headers = + OnDemandHeadersRelay::new::<::RelayFinality>( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_headers_to_left_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + ); + let right_to_left_on_demand_parachains = OnDemandParachainsRelay::new::< + ::ParachainFinality, + >( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_parachains_to_left_transaction_params.clone(), + Arc::new(right_relay_to_left_on_demand_headers), + ); + + Ok(( + Arc::new(left_to_right_on_demand_headers), + Arc::new(right_to_left_on_demand_parachains), + )) + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs new file mode 100644 index 0000000000..2e092ad406 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs @@ -0,0 +1,190 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use async_trait::async_trait; +use std::sync::Arc; + +use crate::cli::{ + bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}, + relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, + CliChain, +}; +use bp_runtime::BlockNumberOf; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, Chain, TransactionSignScheme}; +use sp_core::Pair; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, + on_demand::{headers::OnDemandHeadersRelay, OnDemandRelay}, + TaggedAccount, TransactionParams, +}; + +pub struct RelayToRelayBridge< + L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: MessagesCliBridge + RelayToRelayHeadersCliBridge, +> { + pub common: + Full2WayBridgeCommonParams<::Target, ::Target>, + // override for right->left headers signer + pub right_to_left_transaction_params: + TransactionParams::Target>>, + // override for left->right headers signer + pub left_to_right_transaction_params: + TransactionParams::Target>>, +} + +macro_rules! declare_relay_to_relay_bridge_schema { + ($left_chain:ident, $right_chain:ident) => { + bp_runtime::paste::item! { + #[doc = $left_chain " and " $right_chain " headers+messages relay params."] + #[derive(Debug, PartialEq, StructOpt)] + pub struct [<$left_chain $right_chain HeadersAndMessages>] { + #[structopt(flatten)] + shared: HeadersAndMessagesSharedParams, + // default signer, which is always used to sign messages relay transactions on the left chain + #[structopt(flatten)] + left: [<$left_chain ConnectionParams>], + // override for right->left headers signer + #[structopt(flatten)] + right_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>], + #[structopt(flatten)] + left_sign: [<$left_chain SigningParams>], + #[structopt(flatten)] + left_messages_pallet_owner: [<$left_chain MessagesPalletOwnerSigningParams>], + // default signer, which is always used to sign messages relay transactions on the right chain + #[structopt(flatten)] + right: [<$right_chain ConnectionParams>], + // override for left->right headers signer + #[structopt(flatten)] + left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_chain SigningParams>], + #[structopt(flatten)] + right_sign: [<$right_chain SigningParams>], + #[structopt(flatten)] + right_messages_pallet_owner: [<$right_chain MessagesPalletOwnerSigningParams>], + } + + impl [<$left_chain $right_chain HeadersAndMessages>] { + async fn into_bridge< + Left: TransactionSignScheme + CliChain>, + Right: TransactionSignScheme + CliChain>, + L2R: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, + >( + self, + ) -> anyhow::Result> { + Ok(RelayToRelayBridge { + common: Full2WayBridgeCommonParams::new::( + self.shared, + BridgeEndCommonParams { + client: self.left.into_client::().await?, + sign: self.left_sign.to_keypair::()?, + transactions_mortality: self.left_sign.transactions_mortality()?, + messages_pallet_owner: self.left_messages_pallet_owner.to_keypair::()?, + accounts: vec![], + }, + BridgeEndCommonParams { + client: self.right.into_client::().await?, + sign: self.right_sign.to_keypair::()?, + transactions_mortality: self.right_sign.transactions_mortality()?, + messages_pallet_owner: self.right_messages_pallet_owner.to_keypair::()?, + accounts: vec![], + }, + )?, + right_to_left_transaction_params: self + .right_headers_to_left_sign_override + .transaction_params_or::(&self.left_sign)?, + left_to_right_transaction_params: self + .left_headers_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + }) + } + } + } + }; +} + +#[async_trait] +impl< + Left: Chain + TransactionSignScheme + CliChain>, + Right: Chain + TransactionSignScheme + CliChain>, + L2R: CliBridgeBase + + MessagesCliBridge + + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + RelayToRelayHeadersCliBridge, + > Full2WayBridgeBase for RelayToRelayBridge +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, +{ + type Params = RelayToRelayBridge; + type Left = Left; + type Right = Right; + + fn common(&self) -> &Full2WayBridgeCommonParams { + &self.common + } + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams { + &mut self.common + } + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>>, + Arc>>, + )> { + self.common.right.accounts.push(TaggedAccount::Headers { + id: self.left_to_right_transaction_params.signer.public().into(), + bridged_chain: Self::Left::NAME.to_string(), + }); + self.common.left.accounts.push(TaggedAccount::Headers { + id: self.right_to_left_transaction_params.signer.public().into(), + bridged_chain: Self::Right::NAME.to_string(), + }); + + ::Finality::start_relay_guards( + &self.common.right.client, + &self.left_to_right_transaction_params, + self.common.right.client.can_start_version_guard(), + ) + .await?; + ::Finality::start_relay_guards( + &self.common.left.client, + &self.right_to_left_transaction_params, + self.common.left.client.can_start_version_guard(), + ) + .await?; + + let left_to_right_on_demand_headers = + OnDemandHeadersRelay::new::<::Finality>( + self.common.left.client.clone(), + self.common.right.client.clone(), + self.left_to_right_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + ); + let right_to_left_on_demand_headers = + OnDemandHeadersRelay::new::<::Finality>( + self.common.right.client.clone(), + self.common.left.client.clone(), + self.right_to_left_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + ); + + Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_headers))) + } +} diff --git a/relays/bin-substrate/src/cli/relay_messages.rs b/relays/bin-substrate/src/cli/relay_messages.rs index 45087fad5e..a68ce03054 100644 --- a/relays/bin-substrate/src/cli/relay_messages.rs +++ b/relays/bin-substrate/src/cli/relay_messages.rs @@ -14,22 +14,25 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +use async_trait::async_trait; +use sp_core::Pair; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; +use crate::chains::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, +}; use messages_relay::relay_strategy::MixStrategy; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, BalanceOf, TransactionSignScheme}; use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams}; -use crate::{ - cli::{ - bridge::FullBridge, HexLaneId, PrometheusParams, SourceConnectionParams, - SourceSigningParams, TargetConnectionParams, TargetSigningParams, - }, - select_full_bridge, -}; +use crate::cli::{bridge::*, chain_schema::*, CliChain, HexLaneId, PrometheusParams}; /// Relayer operating mode. -#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq)] +#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq)] #[strum(serialize_all = "kebab_case")] pub enum RelayerMode { /// The relayer doesn't care about rewards. @@ -71,40 +74,65 @@ pub struct RelayMessages { prometheus_params: PrometheusParams, } +#[async_trait] +trait MessagesRelayer: MessagesCliBridge +where + Self::Source: TransactionSignScheme + + CliChain>, + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom>, +{ + async fn relay_messages(data: RelayMessages) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let source_sign = data.source_sign.to_keypair::()?; + let source_transactions_mortality = data.source_sign.transactions_mortality()?; + let target_client = data.target.into_client::().await?; + let target_sign = data.target_sign.to_keypair::()?; + let target_transactions_mortality = data.target_sign.transactions_mortality()?; + let relayer_mode = data.relayer_mode.into(); + let relay_strategy = MixStrategy::new(relayer_mode); + + substrate_relay_helper::messages_lane::run::(MessagesRelayParams { + source_client, + source_transaction_params: TransactionParams { + signer: source_sign, + mortality: source_transactions_mortality, + }, + target_client, + target_transaction_params: TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }, + source_to_target_headers_relay: None, + target_to_source_headers_relay: None, + lane_id: data.lane.into(), + metrics_params: data.prometheus_params.into(), + standalone_metrics: None, + relay_strategy, + }) + .await + .map_err(|e| anyhow::format_err!("{}", e)) + } +} + +impl MessagesRelayer for MillauToRialtoCliBridge {} +impl MessagesRelayer for RialtoToMillauCliBridge {} +impl MessagesRelayer for MillauToRialtoParachainCliBridge {} +impl MessagesRelayer for RialtoParachainToMillauCliBridge {} + impl RelayMessages { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { - select_full_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; - let source_sign = self.source_sign.to_keypair::()?; - let source_transactions_mortality = self.source_sign.transactions_mortality()?; - let target_client = self.target.to_client::().await?; - let target_sign = self.target_sign.to_keypair::()?; - let target_transactions_mortality = self.target_sign.transactions_mortality()?; - let relayer_mode = self.relayer_mode.into(); - let relay_strategy = MixStrategy::new(relayer_mode); - - substrate_relay_helper::messages_lane::run::(MessagesRelayParams { - source_client, - source_transaction_params: TransactionParams { - signer: source_sign, - mortality: source_transactions_mortality, - }, - target_client, - target_transaction_params: TransactionParams { - signer: target_sign, - mortality: target_transactions_mortality, - }, - source_to_target_headers_relay: None, - target_to_source_headers_relay: None, - lane_id: self.lane.into(), - metrics_params: self.prometheus_params.into(), - standalone_metrics: None, - relay_strategy, - }) - .await - .map_err(|e| anyhow::format_err!("{}", e)) - }) + match self.bridge { + FullBridge::MillauToRialto => MillauToRialtoCliBridge::relay_messages(self), + FullBridge::RialtoToMillau => RialtoToMillauCliBridge::relay_messages(self), + FullBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::relay_messages(self), + FullBridge::RialtoParachainToMillau => + RialtoParachainToMillauCliBridge::relay_messages(self), + } + .await } } diff --git a/relays/bin-substrate/src/cli/relay_parachains.rs b/relays/bin-substrate/src/cli/relay_parachains.rs new file mode 100644 index 0000000000..94b856019f --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_parachains.rs @@ -0,0 +1,123 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use crate::chains::{ + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + westend_parachains_to_millau::WestmintToMillauCliBridge, +}; +use async_std::sync::Mutex; +use async_trait::async_trait; +use bp_polkadot_core::parachains::ParaId; +use parachains_relay::parachains_loop::{ + AvailableHeader, ParachainSyncParams, SourceClient, TargetClient, +}; +use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; +use std::sync::Arc; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; +use substrate_relay_helper::{ + parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter}, + TransactionParams, +}; + +use crate::cli::{bridge::ParachainToRelayHeadersCliBridge, chain_schema::*, PrometheusParams}; + +/// Start parachain heads relayer process. +#[derive(StructOpt)] +pub struct RelayParachains { + /// A bridge instance to relay parachains heads for. + #[structopt(possible_values = RelayParachainsBridge::VARIANTS, case_insensitive = true)] + bridge: RelayParachainsBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, +} + +/// Parachain heads relay bridge. +#[derive(Debug, EnumString, EnumVariantNames)] +#[strum(serialize_all = "kebab_case")] +pub enum RelayParachainsBridge { + RialtoToMillau, + WestendToMillau, +} + +#[async_trait] +trait ParachainsRelayer: ParachainToRelayHeadersCliBridge +where + ParachainsSource: + SourceClient>, + ParachainsTarget: + TargetClient>, +{ + async fn relay_headers(data: RelayParachains) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let source_client = ParachainsSource::::new( + source_client, + Arc::new(Mutex::new(AvailableHeader::Missing)), + ); + + let target_transaction_params = TransactionParams { + signer: data.target_sign.to_keypair::()?, + mortality: data.target_sign.target_transactions_mortality, + }; + let target_client = data.target.into_client::().await?; + let target_client = ParachainsTarget::::new( + target_client.clone(), + target_transaction_params, + ); + + let metrics_params: relay_utils::metrics::MetricsParams = data.prometheus_params.into(); + GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; + + parachains_relay::parachains_loop::run( + source_client, + target_client, + ParachainSyncParams { + parachains: vec![ + ParaId(::SOURCE_PARACHAIN_PARA_ID) + ], + stall_timeout: std::time::Duration::from_secs(60), + strategy: parachains_relay::parachains_loop::ParachainSyncStrategy::Any, + }, + metrics_params, + futures::future::pending(), + ) + .await + .map_err(|e| anyhow::format_err!("{}", e)) + } +} + +impl ParachainsRelayer for RialtoParachainToMillauCliBridge {} + +impl ParachainsRelayer for WestmintToMillauCliBridge {} + +impl RelayParachains { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + RelayParachainsBridge::RialtoToMillau => + RialtoParachainToMillauCliBridge::relay_headers(self), + RelayParachainsBridge::WestendToMillau => + WestmintToMillauCliBridge::relay_headers(self), + } + .await + } +} diff --git a/relays/bin-substrate/src/cli/resubmit_transactions.rs b/relays/bin-substrate/src/cli/resubmit_transactions.rs index f92c035082..ac479986ed 100644 --- a/relays/bin-substrate/src/cli/resubmit_transactions.rs +++ b/relays/bin-substrate/src/cli/resubmit_transactions.rs @@ -14,15 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::cli::{Balance, TargetConnectionParams, TargetSigningParams}; +use crate::cli::{chain_schema::*, Balance}; +use bp_runtime::HeaderIdProvider; use codec::{Decode, Encode}; use num_traits::{One, Zero}; use relay_substrate_client::{ BlockWithJustification, Chain, Client, Error as SubstrateError, HeaderIdOf, HeaderOf, SignParam, TransactionSignScheme, }; -use relay_utils::{FailedClient, HeaderId}; +use relay_utils::FailedClient; use sp_core::Bytes; use sp_runtime::{ traits::{Hash, Header as HeaderT}, @@ -62,8 +63,6 @@ pub struct ResubmitTransactions { #[strum(serialize_all = "kebab_case")] pub enum RelayChain { Millau, - Kusama, - Polkadot, } /// Strategy to use for priority selection. @@ -93,18 +92,6 @@ macro_rules! select_bridge { type Target = relay_millau_client::Millau; type TargetSign = relay_millau_client::Millau; - $generic - }, - RelayChain::Kusama => { - type Target = relay_kusama_client::Kusama; - type TargetSign = relay_kusama_client::Kusama; - - $generic - }, - RelayChain::Polkadot => { - type Target = relay_polkadot_client::Polkadot; - type TargetSign = relay_polkadot_client::Polkadot; - $generic }, } @@ -116,7 +103,7 @@ impl ResubmitTransactions { pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.chain, { let relay_loop_name = format!("ResubmitTransactions{}", Target::NAME); - let client = self.target.to_client::().await?; + let client = self.target.into_client::().await?; let transaction_params = TransactionParams { signer: self.target_sign.to_keypair::()?, mortality: self.target_sign.target_transactions_mortality, @@ -288,7 +275,7 @@ async fn run_loop_iteration>( let (is_updated, updated_transaction) = update_transaction_tip::( &client, &transaction_params, - HeaderId(*context.best_header.number(), context.best_header.hash()), + context.best_header.id(), original_transaction, context.tip_step, context.tip_limit, @@ -438,14 +425,15 @@ async fn update_transaction_tip>( current_priority = client .validate_transaction( at_block.1, - S::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *client.genesis_hash(), - signer: transaction_params.signer.clone(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: unsigned_tx.clone(), - })?, + S::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: *client.genesis_hash(), + signer: transaction_params.signer.clone(), + }, + unsigned_tx.clone(), + )?, ) .await?? .priority; @@ -461,17 +449,18 @@ async fn update_transaction_tip>( Ok(( old_tip != unsigned_tx.tip, - S::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *client.genesis_hash(), - signer: transaction_params.signer.clone(), - era: relay_substrate_client::TransactionEra::new( + S::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: *client.genesis_hash(), + signer: transaction_params.signer.clone(), + }, + unsigned_tx.era(relay_substrate_client::TransactionEra::new( at_block, transaction_params.mortality, - ), - unsigned: unsigned_tx, - })?, + )), + )?, )) } diff --git a/relays/bin-substrate/src/cli/send_message.rs b/relays/bin-substrate/src/cli/send_message.rs index ddb1ff59b5..79d1efee63 100644 --- a/relays/bin-substrate/src/cli/send_message.rs +++ b/relays/bin-substrate/src/cli/send_message.rs @@ -14,21 +14,30 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::cli::{ - bridge::FullBridge, - encode_call::{self, CliEncodeCall}, - estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride}, - Balance, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, - SourceSigningParams, TargetConnectionParams, TargetSigningParams, +use crate::{ + chains::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + }, + cli::{ + bridge::{FullBridge, MessagesCliBridge}, + chain_schema::*, + encode_message::{self, CliEncodeMessage, RawMessage}, + estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride}, + Balance, CliChain, HexLaneId, + }, +}; +use async_trait::async_trait; +use codec::{Decode, Encode}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, ChainBase, SignParam, TransactionSignScheme, + UnsignedTransaction, }; -use bp_message_dispatch::{CallOrigin, MessagePayload}; -use bp_runtime::Chain as _; -use codec::Encode; -use frame_support::weights::Weight; -use relay_substrate_client::{Chain, SignParam, TransactionSignScheme, UnsignedTransaction}; use sp_core::{Bytes, Pair}; -use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner}; -use std::fmt::Debug; +use sp_runtime::AccountId32; +use std::fmt::{Debug, Display}; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; @@ -61,8 +70,10 @@ pub struct SendMessage { source: SourceConnectionParams, #[structopt(flatten)] source_sign: SourceSigningParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, + /// Send message using XCM pallet instead. By default message is sent using + /// bridge messages pallet. + #[structopt(long)] + use_xcm_pallet: bool, /// Hex-encoded lane id. Defaults to `00000000`. #[structopt(long, default_value = "00000000")] lane: HexLaneId, @@ -72,254 +83,154 @@ pub struct SendMessage { /// your message won't be relayed. #[structopt(long)] conversion_rate_override: Option, - /// Where dispatch fee is paid? - #[structopt( - long, - possible_values = DispatchFeePayment::VARIANTS, - case_insensitive = true, - default_value = "at-source-chain", - )] - dispatch_fee_payment: DispatchFeePayment, - /// Dispatch weight of the message. If not passed, determined automatically. - #[structopt(long)] - dispatch_weight: Option>, /// Delivery and dispatch fee in source chain base currency units. If not passed, determined /// automatically. #[structopt(long)] fee: Option, /// Message type. #[structopt(subcommand)] - message: crate::cli::encode_call::Call, - /// The origin to use when dispatching the message on the target chain. Defaults to - /// `SourceAccount`. - #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] - origin: Origins, - - // Normally we don't need to connect to the target chain to send message. But for testing - // we may want to use **actual** `spec_version` of the target chain when composing a message. - // Then we'll need to read version from the target chain node. - #[structopt(flatten)] - target: TargetConnectionParams, + message: crate::cli::encode_message::Message, } -impl SendMessage { - pub async fn encode_payload( - &mut self, - ) -> anyhow::Result>> { - crate::select_full_bridge!(self.bridge, { - let SendMessage { - source_sign, - target_sign, - ref mut message, - dispatch_fee_payment, - dispatch_weight, - origin, - bridge, - .. - } = self; - - let source_sign = source_sign.to_keypair::()?; - - encode_call::preprocess_call::(message, bridge.bridge_instance_index()); - let target_call = Target::encode_call(message)?; - let target_spec_version = self.target.selected_chain_spec_version::().await?; - - let payload = { - let target_call_weight = prepare_call_dispatch_weight( - dispatch_weight, - || { - Ok(ExplicitOrMaximal::Explicit( - Target::get_dispatch_info(&target_call)?.weight, - )) - }, - compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()), - )?; - let source_sender_public: MultiSigner = source_sign.public().into(); - let source_account_id = source_sender_public.into_account(); - - message_payload( - target_spec_version, - target_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(source_account_id), - Origins::Target => { - let target_sign = target_sign.to_keypair::()?; - let digest = account_ownership_digest( - &target_call, - source_account_id.clone(), - target_spec_version, - ); - let target_origin_public = target_sign.public(); - let digest_signature = target_sign.sign(&digest); - CallOrigin::TargetAccount( - source_account_id, - target_origin_public.into(), - digest_signature.into(), - ) - }, - }, - &target_call, - *dispatch_fee_payment, +#[async_trait] +trait MessageSender: MessagesCliBridge +where + Self::Source: ChainBase + + TransactionSignScheme + + CliChain> + + CliEncodeMessage, + ::Balance: Display + From + Into, + ::Call: Sync, + ::SignedTransaction: Sync, + AccountIdOf: From< as Pair>::Public>, + AccountId32: From< as Pair>::Public>, +{ + async fn send_message(data: SendMessage) -> anyhow::Result<()> { + let payload = encode_message::encode_message::(&data.message)?; + + let source_client = data.source.into_client::().await?; + let source_sign = data.source_sign.to_keypair::()?; + + let lane = data.lane.clone().into(); + let conversion_rate_override = data.conversion_rate_override; + let fee = match data.fee { + Some(fee) => fee, + None => Balance( + estimate_message_delivery_and_dispatch_fee::( + &source_client, + conversion_rate_override, + Self::ESTIMATE_MESSAGE_FEE_METHOD, + lane, + &payload, ) - }; - Ok(payload) - }) - } - - /// Run the command. - pub async fn run(mut self) -> anyhow::Result<()> { - crate::select_full_bridge!(self.bridge, { - let payload = self.encode_payload().await?; - - let source_client = self.source.to_client::().await?; - let source_sign = self.source_sign.to_keypair::()?; - - let lane = self.lane.clone().into(); - let conversion_rate_override = self.conversion_rate_override; - let fee = match self.fee { - Some(fee) => fee, - None => Balance( - estimate_message_delivery_and_dispatch_fee::( - &source_client, - conversion_rate_override, - ESTIMATE_MESSAGE_FEE_METHOD, - lane, - payload.clone(), - ) - .await? as _, - ), - }; - let dispatch_weight = payload.weight; - let payload_len = payload.encode().len(); - let send_message_call = Source::encode_call(&encode_call::Call::BridgeSendMessage { - bridge_instance_index: self.bridge.bridge_instance_index(), - lane: self.lane, - payload: HexBytes::encode(&payload), - fee, - })?; + .await? + .into(), + ), + }; + let payload_len = payload.encoded_size(); + let send_message_call = if data.use_xcm_pallet { + Self::Source::encode_send_xcm( + decode_xcm(payload)?, + data.bridge.bridge_instance_index(), + )? + } else { + Self::Source::encode_send_message_call( + data.lane.0, + payload, + fee.cast().into(), + data.bridge.bridge_instance_index(), + )? + }; - let source_genesis_hash = *source_client.genesis_hash(); - let (spec_version, transaction_version) = - source_client.simple_runtime_version().await?; - let estimated_transaction_fee = source_client - .estimate_extrinsic_fee(Bytes( - Source::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: source_genesis_hash, - signer: source_sign.clone(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(send_message_call.clone(), 0), - })? - .encode(), - )) - .await?; - source_client - .submit_signed_extrinsic(source_sign.public().into(), move |_, transaction_nonce| { - let signed_source_call = Source::sign_transaction(SignParam { + let source_genesis_hash = *source_client.genesis_hash(); + let (spec_version, transaction_version) = source_client.simple_runtime_version().await?; + let estimated_transaction_fee = source_client + .estimate_extrinsic_fee(Bytes( + Self::Source::sign_transaction( + SignParam { spec_version, transaction_version, genesis_hash: source_genesis_hash, signer: source_sign.clone(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(send_message_call, transaction_nonce), - })? - .encode(); - + }, + UnsignedTransaction::new(send_message_call.clone(), 0), + )? + .encode(), + )) + .await?; + source_client + .submit_signed_extrinsic( + source_sign.public().into(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash: source_genesis_hash, + signer: source_sign.clone(), + }, + move |_, transaction_nonce| { + let unsigned = UnsignedTransaction::new(send_message_call, transaction_nonce); log::info!( target: "bridge", - "Sending message to {}. Lane: {:?}. Size: {}. Dispatch weight: {}. Fee: {}", - Target::NAME, + "Sending message to {}. Lane: {:?}. Size: {}. Fee: {}", + Self::Target::NAME, lane, payload_len, - dispatch_weight, fee, ); log::info!( target: "bridge", - "The source account ({:?}) balance will be reduced by (at most) {} (message fee) + {} (tx fee ) = {} {} tokens", - AccountId32::from(source_sign.public()), + "The source account ({:?}) balance will be reduced by (at most) {} (message fee) + + {} (tx fee ) = {} {} tokens", AccountId32::from(source_sign.public()), fee.0, estimated_transaction_fee.inclusion_fee(), - fee.0.saturating_add(estimated_transaction_fee.inclusion_fee() as _), - Source::NAME, - ); - log::info!( - target: "bridge", - "Signed {} Call: {:?}", - Source::NAME, - HexBytes::encode(&signed_source_call) + fee.0.saturating_add(estimated_transaction_fee.inclusion_fee().into()), + Self::Source::NAME, ); - Ok(Bytes(signed_source_call)) - }) - .await?; - }); + Ok(unsigned) + }, + ) + .await?; Ok(()) } } -fn prepare_call_dispatch_weight( - user_specified_dispatch_weight: &Option>, - weight_from_pre_dispatch_call: impl Fn() -> anyhow::Result>, - maximal_allowed_weight: Weight, -) -> anyhow::Result { - match user_specified_dispatch_weight - .clone() - .map(Ok) - .unwrap_or_else(weight_from_pre_dispatch_call)? - { - ExplicitOrMaximal::Explicit(weight) => Ok(weight), - ExplicitOrMaximal::Maximal => Ok(maximal_allowed_weight), - } -} - -pub(crate) fn message_payload( - spec_version: u32, - weight: Weight, - origin: CallOrigin, - call: &impl Encode, - dispatch_fee_payment: DispatchFeePayment, -) -> MessagePayload> -where - SAccountId: Encode + Debug, - TPublic: Encode + Debug, - TSignature: Encode + Debug, -{ - // Display nicely formatted call. - let payload = MessagePayload { - spec_version, - weight, - origin, - dispatch_fee_payment: dispatch_fee_payment.into(), - call: HexBytes::encode(call), - }; - - log::info!(target: "bridge", "Created Message Payload: {:#?}", payload); - log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload)); +impl MessageSender for MillauToRialtoCliBridge {} +impl MessageSender for RialtoToMillauCliBridge {} +impl MessageSender for MillauToRialtoParachainCliBridge {} +impl MessageSender for RialtoParachainToMillauCliBridge {} - // re-pack to return `Vec` - let MessagePayload { spec_version, weight, origin, dispatch_fee_payment, call } = payload; - MessagePayload { spec_version, weight, origin, dispatch_fee_payment, call: call.0 } +impl SendMessage { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + FullBridge::MillauToRialto => MillauToRialtoCliBridge::send_message(self), + FullBridge::RialtoToMillau => RialtoToMillauCliBridge::send_message(self), + FullBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::send_message(self), + FullBridge::RialtoParachainToMillau => + RialtoParachainToMillauCliBridge::send_message(self), + } + .await + } } -pub(crate) fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { - bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight( - maximal_extrinsic_weight, - ) +/// Decode SCALE encoded raw XCM message. +fn decode_xcm(message: RawMessage) -> anyhow::Result> { + Decode::decode(&mut &message[..]) + .map_err(|e| anyhow::format_err!("Failed to decode XCM program: {:?}", e)) } #[cfg(test)] mod tests { use super::*; - use crate::cli::CliChain; - use hex_literal::hex; + use crate::cli::{ExplicitOrMaximal, HexBytes}; - #[async_std::test] - async fn send_remark_rialto_to_millau() { + #[test] + fn send_raw_rialto_to_millau() { // given - let mut send_message = SendMessage::from_iter(vec![ + let send_message = SendMessage::from_iter(vec![ "send-message", "rialto-to-millau", "--source-port", @@ -328,117 +239,48 @@ mod tests { "//Alice", "--conversion-rate-override", "0.75", - "remark", - "--remark-payload", - "1234", + "raw", + "dead", ]); - // when - let payload = send_message.encode_payload().await.unwrap(); - // then + assert_eq!(send_message.bridge, FullBridge::RialtoToMillau); + assert_eq!(send_message.source.source_port, 1234); + assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into())); assert_eq!( - payload, - MessagePayload { - spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version, - weight: 0, - origin: CallOrigin::SourceAccount( - sp_keyring::AccountKeyring::Alice.to_account_id() - ), - dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain, - call: hex!("0001081234").to_vec(), - } + send_message.conversion_rate_override, + Some(ConversionRateOverride::Explicit(0.75)) ); - } - - #[async_std::test] - async fn send_remark_millau_to_rialto() { - // given - let mut send_message = SendMessage::from_iter(vec![ - "send-message", - "millau-to-rialto", - "--source-port", - "1234", - "--source-signer", - "//Alice", - "--origin", - "Target", - "--target-signer", - "//Bob", - "--conversion-rate-override", - "metric", - "remark", - "--remark-payload", - "1234", - ]); - - // when - let payload = send_message.encode_payload().await.unwrap(); - - // then - // Since signatures are randomized we extract it from here and only check the rest. - let signature = match payload.origin { - CallOrigin::TargetAccount(_, _, ref sig) => sig.clone(), - _ => panic!("Unexpected `CallOrigin`: {:?}", payload), - }; assert_eq!( - payload, - MessagePayload { - spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version, - weight: 0, - origin: CallOrigin::TargetAccount( - sp_keyring::AccountKeyring::Alice.to_account_id(), - sp_keyring::AccountKeyring::Bob.into(), - signature, - ), - dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain, - call: hex!("0001081234").to_vec(), - } + send_message.message, + crate::cli::encode_message::Message::Raw { data: HexBytes(vec![0xDE, 0xAD]) } ); } #[test] - fn accepts_send_message_command_without_target_sign_options() { + fn send_sized_rialto_to_millau() { // given - let send_message = SendMessage::from_iter_safe(vec![ + let send_message = SendMessage::from_iter(vec![ "send-message", "rialto-to-millau", "--source-port", "1234", "--source-signer", "//Alice", - "--origin", - "Target", - "remark", - "--remark-payload", - "1234", - ]); - - assert!(send_message.is_ok()); - } - - #[async_std::test] - async fn accepts_non_default_dispatch_fee_payment() { - // given - let mut send_message = SendMessage::from_iter(vec![ - "send-message", - "rialto-to-millau", - "--source-port", - "1234", - "--source-signer", - "//Alice", - "--dispatch-fee-payment", - "at-target-chain", - "remark", + "--conversion-rate-override", + "metric", + "sized", + "max", ]); - // when - let payload = send_message.encode_payload().await.unwrap(); - // then + assert_eq!(send_message.bridge, FullBridge::RialtoToMillau); + assert_eq!(send_message.source.source_port, 1234); + assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into())); + assert_eq!(send_message.conversion_rate_override, Some(ConversionRateOverride::Metric)); assert_eq!( - payload.dispatch_fee_payment, - bp_runtime::messages::DispatchFeePayment::AtTargetChain + send_message.message, + crate::cli::encode_message::Message::Sized { size: ExplicitOrMaximal::Maximal } ); } } diff --git a/relays/bin-substrate/src/cli/swap_tokens.rs b/relays/bin-substrate/src/cli/swap_tokens.rs deleted file mode 100644 index 0758deddfd..0000000000 --- a/relays/bin-substrate/src/cli/swap_tokens.rs +++ /dev/null @@ -1,869 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Tokens swap using token-swap bridge pallet. - -// TokenSwapBalances fields are never directly accessed, but the whole struct is printed -// to show token swap progress -#![allow(dead_code)] - -use codec::Encode; -use num_traits::One; -use rand::random; -use structopt::StructOpt; -use strum::{EnumString, EnumVariantNames, VariantNames}; - -use frame_support::dispatch::GetDispatchInfo; -use relay_substrate_client::{ - AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithBalances, - Client, Error as SubstrateError, HashOf, SignParam, SignatureOf, Subscription, - TransactionSignScheme, TransactionStatusOf, UnsignedTransaction, -}; -use sp_core::{blake2_256, storage::StorageKey, Bytes, Pair, U256}; -use sp_runtime::traits::{Convert, Header as HeaderT}; - -use crate::cli::{ - estimate_fee::ConversionRateOverride, Balance, CliChain, SourceConnectionParams, - SourceSigningParams, TargetConnectionParams, TargetSigningParams, -}; - -/// Swap tokens. -#[derive(StructOpt, Debug, PartialEq)] -pub struct SwapTokens { - /// A bridge instance to use in token swap. - #[structopt(possible_values = SwapTokensBridge::VARIANTS, case_insensitive = true)] - bridge: SwapTokensBridge, - - #[structopt(flatten)] - source: SourceConnectionParams, - #[structopt(flatten)] - source_sign: SourceSigningParams, - - #[structopt(flatten)] - target: TargetConnectionParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, - - #[structopt(subcommand)] - swap_type: TokenSwapType, - /// Source chain balance that source signer wants to swap. - #[structopt(long)] - source_balance: Balance, - /// Target chain balance that target signer wants to swap. - #[structopt(long)] - target_balance: Balance, - /// A way to override conversion rate from target to source tokens. - /// - /// If not specified, conversion rate from runtime storage is used. It may be obsolete and - /// your message won't be relayed. - #[structopt(long)] - target_to_source_conversion_rate_override: Option, - /// A way to override conversion rate from source to target tokens. - /// - /// If not specified, conversion rate from runtime storage is used. It may be obsolete and - /// your message won't be relayed. - #[structopt(long)] - source_to_target_conversion_rate_override: Option, -} - -/// Token swap type. -#[derive(StructOpt, Debug, PartialEq, Eq, Clone)] -pub enum TokenSwapType { - /// The `target_sign` is temporary and only have funds for single swap. - NoLock, - /// This swap type prevents `source_signer` from restarting the swap after it has been - /// completed. - LockUntilBlock { - /// Number of blocks before the swap expires. - #[structopt(long)] - blocks_before_expire: u32, - /// Unique swap nonce. - #[structopt(long)] - swap_nonce: Option, - }, -} - -/// Swap tokens bridge. -#[derive(Debug, EnumString, EnumVariantNames, PartialEq)] -#[strum(serialize_all = "kebab_case")] -pub enum SwapTokensBridge { - /// Use token-swap pallet deployed at Millau to swap tokens with Rialto. - MillauToRialto, -} - -macro_rules! select_bridge { - ($bridge: expr, $generic: tt) => { - match $bridge { - SwapTokensBridge::MillauToRialto => { - type Source = relay_millau_client::Millau; - type Target = relay_rialto_client::Rialto; - const SOURCE_SPEC_VERSION: u32 = millau_runtime::VERSION.spec_version; - const TARGET_SPEC_VERSION: u32 = rialto_runtime::VERSION.spec_version; - - type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter; - - use bp_millau::{ - derive_account_from_rialto_id as derive_source_account_from_target_account, - TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_TARGET_TO_SOURCE_MESSAGE_FEE_METHOD, - WITH_RIALTO_TOKEN_SWAP_PALLET_NAME as TOKEN_SWAP_PALLET_NAME, - }; - use bp_rialto::{ - derive_account_from_millau_id as derive_target_account_from_source_account, - TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_SOURCE_TO_TARGET_MESSAGE_FEE_METHOD, - }; - - const SOURCE_CHAIN_ID: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; - const TARGET_CHAIN_ID: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID; - - const SOURCE_TO_TARGET_LANE_ID: bp_messages::LaneId = *b"swap"; - const TARGET_TO_SOURCE_LANE_ID: bp_messages::LaneId = [0, 0, 0, 0]; - - $generic - }, - } - }; -} - -impl SwapTokens { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - select_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; - let source_sign = self.source_sign.to_keypair::()?; - let target_client = self.target.to_client::().await?; - let target_sign = self.target_sign.to_keypair::()?; - let target_to_source_conversion_rate_override = - self.target_to_source_conversion_rate_override; - let source_to_target_conversion_rate_override = - self.source_to_target_conversion_rate_override; - - // names of variables in this function are matching names used by the - // `pallet-bridge-token-swap` - - // prepare token swap intention - let token_swap = self - .prepare_token_swap::(&source_client, &source_sign, &target_sign) - .await?; - - // group all accounts that will be used later - let accounts = TokenSwapAccounts { - source_account_at_bridged_chain: derive_target_account_from_source_account( - bp_runtime::SourceAccount::Account( - token_swap.source_account_at_this_chain.clone(), - ), - ), - target_account_at_this_chain: derive_source_account_from_target_account( - bp_runtime::SourceAccount::Account( - token_swap.target_account_at_bridged_chain.clone(), - ), - ), - source_account_at_this_chain: token_swap.source_account_at_this_chain.clone(), - target_account_at_bridged_chain: token_swap.target_account_at_bridged_chain.clone(), - swap_account: FromSwapToThisAccountIdConverter::convert( - token_swap.using_encoded(blake2_256).into(), - ), - }; - - // account balances are used to demonstrate what's happening :) - let initial_balances = - read_account_balances(&accounts, &source_client, &target_client).await?; - - // before calling something that may fail, log what we're trying to do - log::info!(target: "bridge", "Starting swap: {:?}", token_swap); - log::info!(target: "bridge", "Swap accounts: {:?}", accounts); - log::info!(target: "bridge", "Initial account balances: {:?}", initial_balances); - - // - // Step 1: swap is created - // - - // prepare `Currency::transfer` call that will happen at the target chain - let bridged_currency_transfer: CallOf = pallet_balances::Call::transfer { - dest: accounts.source_account_at_bridged_chain.clone().into(), - value: token_swap.target_balance_at_bridged_chain, - } - .into(); - let bridged_currency_transfer_weight = - bridged_currency_transfer.get_dispatch_info().weight; - - // sign message - let bridged_chain_spec_version = TARGET_SPEC_VERSION; - let signature_payload = pallet_bridge_dispatch::account_ownership_digest( - &bridged_currency_transfer, - &accounts.swap_account, - &bridged_chain_spec_version, - SOURCE_CHAIN_ID, - TARGET_CHAIN_ID, - ); - let bridged_currency_transfer_signature: SignatureOf = - target_sign.sign(&signature_payload).into(); - - // prepare `create_swap` call - let target_public_at_bridged_chain: AccountPublicOf = - target_sign.public().into(); - let swap_delivery_and_dispatch_fee = - crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee::< - Source, - Target, - _, - >( - &source_client, - target_to_source_conversion_rate_override.clone(), - ESTIMATE_SOURCE_TO_TARGET_MESSAGE_FEE_METHOD, - SOURCE_TO_TARGET_LANE_ID, - bp_message_dispatch::MessagePayload { - spec_version: TARGET_SPEC_VERSION, - weight: bridged_currency_transfer_weight, - origin: bp_message_dispatch::CallOrigin::TargetAccount( - accounts.swap_account.clone(), - target_public_at_bridged_chain.clone(), - bridged_currency_transfer_signature.clone(), - ), - dispatch_fee_payment: - bp_runtime::messages::DispatchFeePayment::AtTargetChain, - call: bridged_currency_transfer.encode(), - }, - ) - .await?; - let create_swap_call: CallOf = pallet_bridge_token_swap::Call::create_swap { - swap: token_swap.clone(), - swap_creation_params: Box::new(bp_token_swap::TokenSwapCreation { - target_public_at_bridged_chain, - swap_delivery_and_dispatch_fee, - bridged_chain_spec_version, - bridged_currency_transfer: bridged_currency_transfer.encode(), - bridged_currency_transfer_weight, - bridged_currency_transfer_signature, - }), - } - .into(); - - // start tokens swap - let source_genesis_hash = *source_client.genesis_hash(); - let create_swap_signer = source_sign.clone(); - let (spec_version, transaction_version) = - source_client.simple_runtime_version().await?; - let swap_created_at = wait_until_transaction_is_finalized::( - source_client - .submit_and_watch_signed_extrinsic( - accounts.source_account_at_this_chain.clone(), - move |_, transaction_nonce| { - Ok(Bytes( - Source::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: source_genesis_hash, - signer: create_swap_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - create_swap_call.into(), - transaction_nonce, - ), - })? - .encode(), - )) - }, - ) - .await?, - ) - .await?; - - // read state of swap after it has been created - let token_swap_hash = token_swap.hash(); - let token_swap_storage_key = bp_token_swap::storage_keys::pending_swaps_key( - TOKEN_SWAP_PALLET_NAME, - token_swap_hash, - ); - match read_token_swap_state(&source_client, swap_created_at, &token_swap_storage_key) - .await? - { - Some(bp_token_swap::TokenSwapState::Started) => { - log::info!(target: "bridge", "Swap has been successfully started"); - let intermediate_balances = - read_account_balances(&accounts, &source_client, &target_client).await?; - log::info!(target: "bridge", "Intermediate balances: {:?}", intermediate_balances); - }, - Some(token_swap_state) => - return Err(anyhow::format_err!( - "Fresh token swap has unexpected state: {:?}", - token_swap_state, - )), - None => return Err(anyhow::format_err!("Failed to start token swap")), - }; - - // - // Step 2: message is being relayed to the target chain and dispathed there - // - - // wait until message is dispatched at the target chain and dispatch result delivered - // back to source chain - let token_swap_state = wait_until_token_swap_state_is_changed( - &source_client, - &token_swap_storage_key, - bp_token_swap::TokenSwapState::Started, - ) - .await?; - let is_transfer_succeeded = match token_swap_state { - Some(bp_token_swap::TokenSwapState::Started) => { - unreachable!("wait_until_token_swap_state_is_changed only returns if state is not Started; qed",) - }, - None => - return Err(anyhow::format_err!("Fresh token swap has disappeared unexpectedly")), - Some(bp_token_swap::TokenSwapState::Confirmed) => { - log::info!( - target: "bridge", - "Transfer has been successfully dispatched at the target chain. Swap can be claimed", - ); - true - }, - Some(bp_token_swap::TokenSwapState::Failed) => { - log::info!( - target: "bridge", - "Transfer has been dispatched with an error at the target chain. Swap can be canceled", - ); - false - }, - }; - - // by this time: (1) token swap account has been created and (2) if transfer has been - // successfully dispatched, both target chain balances have changed - let intermediate_balances = - read_account_balances(&accounts, &source_client, &target_client).await?; - log::info!(target: "bridge", "Intermediate balances: {:?}", intermediate_balances); - - // transfer has been dispatched, but we may need to wait until block where swap can be - // claimed/canceled - if let bp_token_swap::TokenSwapType::LockClaimUntilBlock( - ref last_available_block_number, - _, - ) = token_swap.swap_type - { - wait_until_swap_unlocked( - &source_client, - last_available_block_number + BlockNumberOf::::one(), - ) - .await?; - } - - // - // Step 3: we may now claim or cancel the swap - // - - if is_transfer_succeeded { - log::info!(target: "bridge", "Claiming the swap"); - - // prepare `claim_swap` message that will be sent over the bridge - let claim_swap_call: CallOf = - pallet_bridge_token_swap::Call::claim_swap { swap: token_swap }.into(); - let claim_swap_message = bp_message_dispatch::MessagePayload { - spec_version: SOURCE_SPEC_VERSION, - weight: claim_swap_call.get_dispatch_info().weight, - origin: bp_message_dispatch::CallOrigin::SourceAccount( - accounts.target_account_at_bridged_chain.clone(), - ), - dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain, - call: claim_swap_call.encode(), - }; - let claim_swap_delivery_and_dispatch_fee = - crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee::< - Target, - Source, - _, - >( - &target_client, - source_to_target_conversion_rate_override.clone(), - ESTIMATE_TARGET_TO_SOURCE_MESSAGE_FEE_METHOD, - TARGET_TO_SOURCE_LANE_ID, - claim_swap_message.clone(), - ) - .await?; - let send_message_call: CallOf = - pallet_bridge_messages::Call::send_message { - lane_id: TARGET_TO_SOURCE_LANE_ID, - payload: claim_swap_message, - delivery_and_dispatch_fee: claim_swap_delivery_and_dispatch_fee, - } - .into(); - - // send `claim_swap` message - let target_genesis_hash = *target_client.genesis_hash(); - let (spec_version, transaction_version) = - target_client.simple_runtime_version().await?; - let _ = wait_until_transaction_is_finalized::( - target_client - .submit_and_watch_signed_extrinsic( - accounts.target_account_at_bridged_chain.clone(), - move |_, transaction_nonce| { - Ok(Bytes( - Target::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: target_genesis_hash, - signer: target_sign, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - send_message_call.into(), - transaction_nonce, - ), - })? - .encode(), - )) - }, - ) - .await?, - ) - .await?; - - // wait until swap state is updated - let token_swap_state = wait_until_token_swap_state_is_changed( - &source_client, - &token_swap_storage_key, - bp_token_swap::TokenSwapState::Confirmed, - ) - .await?; - if token_swap_state != None { - return Err(anyhow::format_err!( - "Confirmed token swap state has been changed to {:?} unexpectedly", - token_swap_state - )) - } - } else { - log::info!(target: "bridge", "Cancelling the swap"); - let cancel_swap_call: CallOf = - pallet_bridge_token_swap::Call::cancel_swap { swap: token_swap.clone() }.into(); - let (spec_version, transaction_version) = - source_client.simple_runtime_version().await?; - let _ = wait_until_transaction_is_finalized::( - source_client - .submit_and_watch_signed_extrinsic( - accounts.source_account_at_this_chain.clone(), - move |_, transaction_nonce| { - Ok(Bytes( - Source::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: source_genesis_hash, - signer: source_sign, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - cancel_swap_call.into(), - transaction_nonce, - ), - })? - .encode(), - )) - }, - ) - .await?, - ) - .await?; - } - - // print final balances - let final_balances = - read_account_balances(&accounts, &source_client, &target_client).await?; - log::info!(target: "bridge", "Final account balances: {:?}", final_balances); - - Ok(()) - }) - } - - /// Prepare token swap intention. - async fn prepare_token_swap( - &self, - source_client: &Client, - source_sign: &Source::KeyPair, - target_sign: &Target::KeyPair, - ) -> anyhow::Result< - bp_token_swap::TokenSwap< - BlockNumberOf, - BalanceOf, - AccountIdOf, - BalanceOf, - AccountIdOf, - >, - > - where - AccountIdOf: From<::Public>, - AccountIdOf: From<::Public>, - BalanceOf: From, - BalanceOf: From, - { - // accounts that are directly controlled by participants - let source_account_at_this_chain: AccountIdOf = source_sign.public().into(); - let target_account_at_bridged_chain: AccountIdOf = target_sign.public().into(); - - // balances that we're going to swap - let source_balance_at_this_chain: BalanceOf = self.source_balance.cast().into(); - let target_balance_at_bridged_chain: BalanceOf = self.target_balance.cast().into(); - - // prepare token swap intention - Ok(bp_token_swap::TokenSwap { - swap_type: self.prepare_token_swap_type(source_client).await?, - source_balance_at_this_chain, - source_account_at_this_chain: source_account_at_this_chain.clone(), - target_balance_at_bridged_chain, - target_account_at_bridged_chain: target_account_at_bridged_chain.clone(), - }) - } - - /// Prepare token swap type. - async fn prepare_token_swap_type( - &self, - source_client: &Client, - ) -> anyhow::Result>> { - match self.swap_type { - TokenSwapType::NoLock => - Ok(bp_token_swap::TokenSwapType::TemporaryTargetAccountAtBridgedChain), - TokenSwapType::LockUntilBlock { blocks_before_expire, ref swap_nonce } => { - let blocks_before_expire: BlockNumberOf = blocks_before_expire.into(); - let current_source_block_number = *source_client.best_header().await?.number(); - Ok(bp_token_swap::TokenSwapType::LockClaimUntilBlock( - current_source_block_number + blocks_before_expire, - swap_nonce.unwrap_or_else(|| { - U256::from(random::()).overflowing_mul(U256::from(random::())).0 - }), - )) - }, - } - } -} - -/// Accounts that are participating in the swap. -#[derive(Debug)] -struct TokenSwapAccounts { - source_account_at_this_chain: ThisAccountId, - source_account_at_bridged_chain: BridgedAccountId, - target_account_at_bridged_chain: BridgedAccountId, - target_account_at_this_chain: ThisAccountId, - swap_account: ThisAccountId, -} - -/// Swap accounts balances. -#[derive(Debug)] -struct TokenSwapBalances { - source_account_at_this_chain_balance: Option, - source_account_at_bridged_chain_balance: Option, - target_account_at_bridged_chain_balance: Option, - target_account_at_this_chain_balance: Option, - swap_account_balance: Option, -} - -/// Read swap accounts balances. -async fn read_account_balances( - accounts: &TokenSwapAccounts, AccountIdOf>, - source_client: &Client, - target_client: &Client, -) -> anyhow::Result, BalanceOf>> { - Ok(TokenSwapBalances { - source_account_at_this_chain_balance: read_account_balance( - source_client, - &accounts.source_account_at_this_chain, - ) - .await?, - source_account_at_bridged_chain_balance: read_account_balance( - target_client, - &accounts.source_account_at_bridged_chain, - ) - .await?, - target_account_at_bridged_chain_balance: read_account_balance( - target_client, - &accounts.target_account_at_bridged_chain, - ) - .await?, - target_account_at_this_chain_balance: read_account_balance( - source_client, - &accounts.target_account_at_this_chain, - ) - .await?, - swap_account_balance: read_account_balance(source_client, &accounts.swap_account).await?, - }) -} - -/// Read account balance. -async fn read_account_balance( - client: &Client, - account: &AccountIdOf, -) -> anyhow::Result>> { - match client.free_native_balance(account.clone()).await { - Ok(balance) => Ok(Some(balance)), - Err(SubstrateError::AccountDoesNotExist) => Ok(None), - Err(error) => Err(anyhow::format_err!( - "Failed to read balance of {} account {:?}: {:?}", - C::NAME, - account, - error, - )), - } -} - -/// Wait until transaction is included into finalized block. -/// -/// Returns the hash of the finalized block with transaction. -pub(crate) async fn wait_until_transaction_is_finalized( - subscription: Subscription>, -) -> anyhow::Result> { - loop { - let transaction_status = subscription.next().await?; - match transaction_status { - Some(TransactionStatusOf::::FinalityTimeout(_)) | - Some(TransactionStatusOf::::Usurped(_)) | - Some(TransactionStatusOf::::Dropped) | - Some(TransactionStatusOf::::Invalid) | - None => - return Err(anyhow::format_err!( - "We've been waiting for finalization of {} transaction, but it now has the {:?} status", - C::NAME, - transaction_status, - )), - Some(TransactionStatusOf::::Finalized(block_hash)) => { - log::trace!( - target: "bridge", - "{} transaction has been finalized at block {}", - C::NAME, - block_hash, - ); - return Ok(block_hash) - }, - _ => { - log::trace!( - target: "bridge", - "Received intermediate status of {} transaction: {:?}", - C::NAME, - transaction_status, - ); - }, - } - } -} - -/// Waits until token swap state is changed from `Started` to something else. -async fn wait_until_token_swap_state_is_changed( - client: &Client, - swap_state_storage_key: &StorageKey, - previous_token_swap_state: bp_token_swap::TokenSwapState, -) -> anyhow::Result> { - log::trace!(target: "bridge", "Waiting for token swap state change"); - loop { - async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await; - - let best_block = client.best_finalized_header_number().await?; - let best_block_hash = client.block_hash_by_number(best_block).await?; - log::trace!(target: "bridge", "Inspecting {} block {}/{}", C::NAME, best_block, best_block_hash); - - let token_swap_state = - read_token_swap_state(client, best_block_hash, swap_state_storage_key).await?; - match token_swap_state { - Some(new_token_swap_state) if new_token_swap_state == previous_token_swap_state => {}, - _ => { - log::trace!( - target: "bridge", - "Token swap state has been changed from {:?} to {:?}", - previous_token_swap_state, - token_swap_state, - ); - return Ok(token_swap_state) - }, - } - } -} - -/// Waits until swap can be claimed or canceled. -async fn wait_until_swap_unlocked( - client: &Client, - required_block_number: BlockNumberOf, -) -> anyhow::Result<()> { - log::trace!(target: "bridge", "Waiting for token swap unlock"); - loop { - async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await; - - let best_block = client.best_finalized_header_number().await?; - let best_block_hash = client.block_hash_by_number(best_block).await?; - if best_block >= required_block_number { - return Ok(()) - } - - log::trace!(target: "bridge", "Skipping {} block {}/{}", C::NAME, best_block, best_block_hash); - } -} - -/// Read state of the active token swap. -async fn read_token_swap_state( - client: &Client, - at_block: C::Hash, - swap_state_storage_key: &StorageKey, -) -> anyhow::Result> { - Ok(client.storage_value(swap_state_storage_key.clone(), Some(at_block)).await?) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams}; - - #[test] - fn swap_tokens_millau_to_rialto_no_lock() { - let swap_tokens = SwapTokens::from_iter(vec![ - "swap-tokens", - "millau-to-rialto", - "--source-host", - "127.0.0.1", - "--source-port", - "9000", - "--source-signer", - "//Alice", - "--source-balance", - "8000000000", - "--target-host", - "127.0.0.1", - "--target-port", - "9001", - "--target-signer", - "//Bob", - "--target-balance", - "9000000000", - "no-lock", - ]); - - assert_eq!( - swap_tokens, - SwapTokens { - bridge: SwapTokensBridge::MillauToRialto, - source: SourceConnectionParams { - source_host: "127.0.0.1".into(), - source_port: 9000, - source_secure: false, - source_runtime_version: SourceRuntimeVersionParams { - source_version_mode: RuntimeVersionType::Bundle, - source_spec_version: None, - source_transaction_version: None, - } - }, - source_sign: SourceSigningParams { - source_signer: Some("//Alice".into()), - source_signer_password: None, - source_signer_file: None, - source_signer_password_file: None, - source_transactions_mortality: None, - }, - target: TargetConnectionParams { - target_host: "127.0.0.1".into(), - target_port: 9001, - target_secure: false, - target_runtime_version: TargetRuntimeVersionParams { - target_version_mode: RuntimeVersionType::Bundle, - target_spec_version: None, - target_transaction_version: None, - } - }, - target_sign: TargetSigningParams { - target_signer: Some("//Bob".into()), - target_signer_password: None, - target_signer_file: None, - target_signer_password_file: None, - target_transactions_mortality: None, - }, - swap_type: TokenSwapType::NoLock, - source_balance: Balance(8000000000), - target_balance: Balance(9000000000), - target_to_source_conversion_rate_override: None, - source_to_target_conversion_rate_override: None, - } - ); - } - - #[test] - fn swap_tokens_millau_to_rialto_lock_until() { - let swap_tokens = SwapTokens::from_iter(vec![ - "swap-tokens", - "millau-to-rialto", - "--source-host", - "127.0.0.1", - "--source-port", - "9000", - "--source-signer", - "//Alice", - "--source-balance", - "8000000000", - "--target-host", - "127.0.0.1", - "--target-port", - "9001", - "--target-signer", - "//Bob", - "--target-balance", - "9000000000", - "--target-to-source-conversion-rate-override", - "metric", - "--source-to-target-conversion-rate-override", - "84.56", - "lock-until-block", - "--blocks-before-expire", - "1", - ]); - - assert_eq!( - swap_tokens, - SwapTokens { - bridge: SwapTokensBridge::MillauToRialto, - source: SourceConnectionParams { - source_host: "127.0.0.1".into(), - source_port: 9000, - source_secure: false, - source_runtime_version: SourceRuntimeVersionParams { - source_version_mode: RuntimeVersionType::Bundle, - source_spec_version: None, - source_transaction_version: None, - } - }, - source_sign: SourceSigningParams { - source_signer: Some("//Alice".into()), - source_signer_password: None, - source_signer_file: None, - source_signer_password_file: None, - source_transactions_mortality: None, - }, - target: TargetConnectionParams { - target_host: "127.0.0.1".into(), - target_port: 9001, - target_secure: false, - target_runtime_version: TargetRuntimeVersionParams { - target_version_mode: RuntimeVersionType::Bundle, - target_spec_version: None, - target_transaction_version: None, - } - }, - target_sign: TargetSigningParams { - target_signer: Some("//Bob".into()), - target_signer_password: None, - target_signer_file: None, - target_signer_password_file: None, - target_transactions_mortality: None, - }, - swap_type: TokenSwapType::LockUntilBlock { - blocks_before_expire: 1, - swap_nonce: None, - }, - source_balance: Balance(8000000000), - target_balance: Balance(9000000000), - target_to_source_conversion_rate_override: Some(ConversionRateOverride::Metric), - source_to_target_conversion_rate_override: Some(ConversionRateOverride::Explicit( - 84.56 - )), - } - ); - } -} diff --git a/relays/bin-substrate/src/main.rs b/relays/bin-substrate/src/main.rs index 13db6beefa..bc84786ee2 100644 --- a/relays/bin-substrate/src/main.rs +++ b/relays/bin-substrate/src/main.rs @@ -26,6 +26,6 @@ fn main() { let run = command.run(); let result = async_std::task::block_on(run); if let Err(error) = result { - log::error!(target: "bridge", "Failed to start relay: {}", error); + log::error!(target: "bridge", "substrate-relay: {}", error); } } diff --git a/relays/client-kusama/Cargo.toml b/relays/client-kusama/Cargo.toml index 35c24c1089..2efe62d8ec 100644 --- a/relays/client-kusama/Cargo.toml +++ b/relays/client-kusama/Cargo.toml @@ -6,25 +6,14 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } -scale-info = { version = "2.0.1", features = ["derive"] } # Bridge dependencies -bp-header-chain = { path = "../../primitives/header-chain" } bp-kusama = { path = "../../primitives/chain-kusama" } -bp-message-dispatch = { path = "../../primitives/message-dispatch" } -bp-messages = { path = "../../primitives/messages" } -bp-polkadot = { path = "../../primitives/chain-polkadot" } -bp-polkadot-core = { path = "../../primitives/polkadot-core" } -bp-runtime = { path = "../../primitives/runtime" } -bridge-runtime-common = { path = "../../bin/runtime-common" } -pallet-bridge-dispatch = { path = "../../modules/dispatch" } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-kusama/src/lib.rs b/relays/client-kusama/src/lib.rs index e228f2dc24..b076da7ab7 100644 --- a/relays/client-kusama/src/lib.rs +++ b/relays/client-kusama/src/lib.rs @@ -16,19 +16,11 @@ //! Types used to connect to the Kusama chain. -use bp_messages::MessageNonce; -use codec::Encode; use frame_support::weights::Weight; -use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, - Error as SubstrateError, SignParam, TransactionSignScheme, UnsignedTransaction, -}; -use sp_core::{storage::StorageKey, Pair}; -use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, ChainWithGrandpa}; +use sp_core::storage::StorageKey; use std::time::Duration; -pub mod runtime; - /// Kusama header id. pub type HeaderId = relay_utils::HeaderId; @@ -63,10 +55,9 @@ impl Chain for Kusama { bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_kusama::SignedBlock; - type Call = crate::runtime::Call; + type Call = (); type WeightToFee = bp_kusama::WeightToFee; } @@ -74,78 +65,11 @@ impl ChainWithGrandpa for Kusama { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = bp_kusama::WITH_KUSAMA_GRANDPA_PALLET_NAME; } -impl ChainWithMessages for Kusama { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = - bp_kusama::WITH_KUSAMA_MESSAGES_PALLET_NAME; - const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = - bp_kusama::TO_KUSAMA_MESSAGE_DETAILS_METHOD; - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = - bp_kusama::PAY_INBOUND_DISPATCH_FEE_WEIGHT; - const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = - bp_kusama::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = - bp_kusama::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - type WeightInfo = (); -} - impl ChainWithBalances for Kusama { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_kusama::account_info_storage_key(account_id)) } } -impl TransactionSignScheme for Kusama { - type Chain = Kusama; - type AccountKeyPair = sp_core::sr25519::Pair; - type SignedTransaction = crate::runtime::UncheckedExtrinsic; - - fn sign_transaction(param: SignParam) -> Result { - let raw_payload = SignedPayload::new( - param.unsigned.call.clone(), - bp_kusama::SignedExtensions::new( - param.spec_version, - param.transaction_version, - param.era, - param.genesis_hash, - param.unsigned.nonce, - param.unsigned.tip, - ), - ) - .expect("SignedExtension never fails."); - - let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); - let signer: sp_runtime::MultiSigner = param.signer.public().into(); - let (call, extra, _) = raw_payload.deconstruct(); - - Ok(bp_kusama::UncheckedExtrinsic::new_signed( - call, - sp_runtime::MultiAddress::Id(signer.into_account()), - signature.into(), - extra, - )) - } - - fn is_signed(tx: &Self::SignedTransaction) -> bool { - tx.signature.is_some() - } - - fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { - tx.signature - .as_ref() - .map(|(address, _, _)| { - *address == bp_kusama::AccountId::from(*signer.public().as_array_ref()).into() - }) - .unwrap_or(false) - } - - fn parse_transaction(tx: Self::SignedTransaction) -> Option> { - let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { call: tx.function, nonce: extra.nonce(), tip: extra.tip() }) - } -} - /// Kusama header type used in headers sync. pub type SyncHeader = relay_substrate_client::SyncHeader; - -/// Kusama signing params. -pub type SigningParams = sp_core::sr25519::Pair; diff --git a/relays/client-kusama/src/runtime.rs b/relays/client-kusama/src/runtime.rs deleted file mode 100644 index 59a919e6cb..0000000000 --- a/relays/client-kusama/src/runtime.rs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Types that are specific to the Kusama runtime. - -use bp_messages::{LaneId, UnrewardedRelayersState}; -use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike}; -use bp_runtime::Chain; -use codec::{Compact, Decode, Encode}; -use frame_support::weights::Weight; -use scale_info::TypeInfo; -use sp_runtime::FixedU128; - -/// Unchecked Kusama extrinsic. -pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic; - -/// Polkadot account ownership digest from Kusama. -/// -/// The byte vector returned by this function should be signed with a Polkadot account private key. -/// This way, the owner of `kusama_account_id` on Kusama proves that the Polkadot account private -/// key is also under his control. -pub fn kusama_to_polkadot_account_ownership_digest( - polkadot_call: &Call, - kusama_account_id: AccountId, - polkadot_spec_version: SpecVersion, -) -> Vec -where - Call: codec::Encode, - AccountId: codec::Encode, - SpecVersion: codec::Encode, -{ - pallet_bridge_dispatch::account_ownership_digest( - polkadot_call, - kusama_account_id, - polkadot_spec_version, - bp_runtime::KUSAMA_CHAIN_ID, - bp_runtime::POLKADOT_CHAIN_ID, - ) -} - -/// Kusama Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to Kusama chain. -/// Ideally this code would be auto-generated from metadata, because we want to -/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. -/// -/// All entries here (like pretty much in the entire file) must be kept in sync with Kusama -/// `construct_runtime`, so that we maintain SCALE-compatibility. -/// -/// See: [link](https://github.com/paritytech/polkadot/blob/master/runtime/kusama/src/lib.rs) -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// System pallet. - #[codec(index = 0)] - System(SystemCall), - /// Balances pallet. - #[codec(index = 4)] - Balances(BalancesCall), - /// Utility pallet. - #[codec(index = 24)] - Utility(UtilityCall), - /// Polkadot bridge pallet. - #[codec(index = 110)] - BridgePolkadotGrandpa(BridgePolkadotGrandpaCall), - /// Polkadot messages pallet. - #[codec(index = 111)] - BridgePolkadotMessages(BridgePolkadotMessagesCall), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum SystemCall { - #[codec(index = 1)] - remark(Vec), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BalancesCall { - #[codec(index = 0)] - transfer(AccountAddress, Compact), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgePolkadotGrandpaCall { - #[codec(index = 0)] - submit_finality_proof( - Box<::Header>, - bp_header_chain::justification::GrandpaJustification<::Header>, - ), - #[codec(index = 1)] - initialize(bp_header_chain::InitializationData<::Header>), - #[codec(index = 3)] - set_operational(bool), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgePolkadotMessagesCall { - #[codec(index = 2)] - update_pallet_parameter(BridgePolkadotMessagesParameter), - #[codec(index = 3)] - send_message( - LaneId, - bp_message_dispatch::MessagePayload< - bp_kusama::AccountId, - bp_polkadot::AccountId, - bp_polkadot::AccountPublic, - Vec, - >, - bp_kusama::Balance, - ), - #[codec(index = 5)] - receive_messages_proof( - bp_polkadot::AccountId, - bridge_runtime_common::messages::target::FromBridgedChainMessagesProof, - u32, - Weight, - ), - #[codec(index = 6)] - receive_messages_delivery_proof( - bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof< - bp_polkadot::Hash, - >, - UnrewardedRelayersState, - ), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum UtilityCall { - #[codec(index = 2)] - batch_all(Vec), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum BridgePolkadotMessagesParameter { - #[codec(index = 0)] - PolkadotToKusamaConversionRate(FixedU128), -} - -impl sp_runtime::traits::Dispatchable for Call { - type Origin = (); - type Config = (); - type Info = (); - type PostInfo = (); - - fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { - unimplemented!("The Call is not expected to be dispatched.") - } -} diff --git a/relays/client-millau/Cargo.toml b/relays/client-millau/Cargo.toml index 9893243345..66395d5de8 100644 --- a/relays/client-millau/Cargo.toml +++ b/relays/client-millau/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.1.5" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } diff --git a/relays/client-millau/src/lib.rs b/relays/client-millau/src/lib.rs index eae9d9b458..7bab3669c4 100644 --- a/relays/client-millau/src/lib.rs +++ b/relays/client-millau/src/lib.rs @@ -31,7 +31,7 @@ use std::time::Duration; pub type HeaderId = relay_utils::HeaderId; /// Millau chain definition. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Millau; impl ChainBase for Millau { @@ -63,6 +63,8 @@ impl ChainWithMessages for Millau { bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_millau::FROM_MILLAU_MESSAGE_DETAILS_METHOD; const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT; const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = @@ -80,7 +82,6 @@ impl Chain for Millau { bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = millau_runtime::SignedBlock; type Call = millau_runtime::Call; @@ -101,25 +102,30 @@ impl TransactionSignScheme for Millau { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = millau_runtime::UncheckedExtrinsic; - fn sign_transaction(param: SignParam) -> Result { + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { let raw_payload = SignedPayload::from_raw( - param.unsigned.call.clone(), + unsigned.call.clone(), ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(param.era.frame_era()), - frame_system::CheckNonce::::from(param.unsigned.nonce), + frame_system::CheckEra::::from(unsigned.era.frame_era()), + frame_system::CheckNonce::::from(unsigned.nonce), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(param.unsigned.tip), + pallet_transaction_payment::ChargeTransactionPayment::::from(unsigned.tip), + millau_runtime::BridgeRejectObsoleteHeadersAndMessages, ), ( (), param.spec_version, param.transaction_version, param.genesis_hash, - param.era.signed_payload(param.genesis_hash), + unsigned.era.signed_payload(param.genesis_hash), + (), (), (), (), @@ -152,13 +158,17 @@ impl TransactionSignScheme for Millau { fn parse_transaction(tx: Self::SignedTransaction) -> Option> { let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { - call: tx.function.into(), - nonce: Compact::>::decode(&mut &extra.5.encode()[..]).ok()?.into(), - tip: Compact::>::decode(&mut &extra.7.encode()[..]) - .ok()? - .into(), - }) + Some( + UnsignedTransaction::new( + tx.function.into(), + Compact::>::decode(&mut &extra.5.encode()[..]).ok()?.into(), + ) + .tip( + Compact::>::decode(&mut &extra.7.encode()[..]) + .ok()? + .into(), + ), + ) } } @@ -182,15 +192,17 @@ mod tests { .into(), nonce: 777, tip: 888, - }; - let signed_transaction = Millau::sign_transaction(SignParam { - spec_version: 42, - transaction_version: 50000, - genesis_hash: [42u8; 64].into(), - signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), era: TransactionEra::immortal(), - unsigned: unsigned.clone(), - }) + }; + let signed_transaction = Millau::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 64].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) .unwrap(); let parsed_transaction = Millau::parse_transaction(signed_transaction).unwrap(); assert_eq!(parsed_transaction, unsigned); diff --git a/relays/client-polkadot/Cargo.toml b/relays/client-polkadot/Cargo.toml index 96cfa2ce1b..aefbadfdd1 100644 --- a/relays/client-polkadot/Cargo.toml +++ b/relays/client-polkadot/Cargo.toml @@ -6,25 +6,14 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } -scale-info = { version = "2.0.1", features = ["derive"] } # Bridge dependencies -bp-header-chain = { path = "../../primitives/header-chain" } -bp-kusama = { path = "../../primitives/chain-kusama" } -bp-message-dispatch = { path = "../../primitives/message-dispatch" } -bp-messages = { path = "../../primitives/messages" } bp-polkadot = { path = "../../primitives/chain-polkadot" } -bp-polkadot-core = { path = "../../primitives/polkadot-core" } -bp-runtime = { path = "../../primitives/runtime" } -bridge-runtime-common = { path = "../../bin/runtime-common" } -pallet-bridge-dispatch = { path = "../../modules/dispatch" } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-polkadot/src/lib.rs b/relays/client-polkadot/src/lib.rs index d4ada45e36..9327c76c4e 100644 --- a/relays/client-polkadot/src/lib.rs +++ b/relays/client-polkadot/src/lib.rs @@ -16,19 +16,11 @@ //! Types used to connect to the Polkadot chain. -use bp_messages::MessageNonce; -use codec::Encode; use frame_support::weights::Weight; -use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, - Error as SubstrateError, SignParam, TransactionSignScheme, UnsignedTransaction, -}; -use sp_core::{storage::StorageKey, Pair}; -use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, ChainWithGrandpa}; +use sp_core::storage::StorageKey; use std::time::Duration; -pub mod runtime; - /// Polkadot header id. pub type HeaderId = relay_utils::HeaderId; @@ -63,10 +55,9 @@ impl Chain for Polkadot { bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_polkadot::SignedBlock; - type Call = crate::runtime::Call; + type Call = (); type WeightToFee = bp_polkadot::WeightToFee; } @@ -75,78 +66,11 @@ impl ChainWithGrandpa for Polkadot { bp_polkadot::WITH_POLKADOT_GRANDPA_PALLET_NAME; } -impl ChainWithMessages for Polkadot { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = - bp_polkadot::WITH_POLKADOT_MESSAGES_PALLET_NAME; - const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = - bp_polkadot::TO_POLKADOT_MESSAGE_DETAILS_METHOD; - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = - bp_polkadot::PAY_INBOUND_DISPATCH_FEE_WEIGHT; - const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = - bp_polkadot::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = - bp_polkadot::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - type WeightInfo = (); -} - impl ChainWithBalances for Polkadot { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_polkadot::account_info_storage_key(account_id)) } } -impl TransactionSignScheme for Polkadot { - type Chain = Polkadot; - type AccountKeyPair = sp_core::sr25519::Pair; - type SignedTransaction = crate::runtime::UncheckedExtrinsic; - - fn sign_transaction(param: SignParam) -> Result { - let raw_payload = SignedPayload::new( - param.unsigned.call.clone(), - bp_polkadot::SignedExtensions::new( - param.spec_version, - param.transaction_version, - param.era, - param.genesis_hash, - param.unsigned.nonce, - param.unsigned.tip, - ), - ) - .expect("SignedExtension never fails."); - - let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); - let signer: sp_runtime::MultiSigner = param.signer.public().into(); - let (call, extra, _) = raw_payload.deconstruct(); - - Ok(bp_polkadot::UncheckedExtrinsic::new_signed( - call, - sp_runtime::MultiAddress::Id(signer.into_account()), - signature.into(), - extra, - )) - } - - fn is_signed(tx: &Self::SignedTransaction) -> bool { - tx.signature.is_some() - } - - fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { - tx.signature - .as_ref() - .map(|(address, _, _)| { - *address == bp_polkadot::AccountId::from(*signer.public().as_array_ref()).into() - }) - .unwrap_or(false) - } - - fn parse_transaction(tx: Self::SignedTransaction) -> Option> { - let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { call: tx.function, nonce: extra.nonce(), tip: extra.tip() }) - } -} - /// Polkadot header type used in headers sync. pub type SyncHeader = relay_substrate_client::SyncHeader; - -/// Polkadot signing params. -pub type SigningParams = sp_core::sr25519::Pair; diff --git a/relays/client-polkadot/src/runtime.rs b/relays/client-polkadot/src/runtime.rs deleted file mode 100644 index fa45115a6b..0000000000 --- a/relays/client-polkadot/src/runtime.rs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Types that are specific to the Polkadot runtime. - -use bp_messages::{LaneId, UnrewardedRelayersState}; -use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike}; -use bp_runtime::Chain; -use codec::{Compact, Decode, Encode}; -use frame_support::weights::Weight; -use scale_info::TypeInfo; -use sp_runtime::FixedU128; - -/// Unchecked Polkadot extrinsic. -pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic; - -/// Kusama account ownership digest from Polkadot. -/// -/// The byte vector returned by this function should be signed with a Kusama account private key. -/// This way, the owner of `kusam_account_id` on Polkadot proves that the Kusama account private key -/// is also under his control. -pub fn polkadot_to_kusama_account_ownership_digest( - kusama_call: &Call, - kusam_account_id: AccountId, - kusama_spec_version: SpecVersion, -) -> Vec -where - Call: codec::Encode, - AccountId: codec::Encode, - SpecVersion: codec::Encode, -{ - pallet_bridge_dispatch::account_ownership_digest( - kusama_call, - kusam_account_id, - kusama_spec_version, - bp_runtime::POLKADOT_CHAIN_ID, - bp_runtime::KUSAMA_CHAIN_ID, - ) -} - -/// Polkadot Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to Polkadot chain. -/// Ideally this code would be auto-generated from metadata, because we want to -/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. -/// -/// All entries here (like pretty much in the entire file) must be kept in sync with Polkadot -/// `construct_runtime`, so that we maintain SCALE-compatibility. -/// -/// See: [link](https://github.com/paritytech/kusama/blob/master/runtime/kusam/src/lib.rs) -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// System pallet. - #[codec(index = 0)] - System(SystemCall), - /// Balances pallet. - #[codec(index = 5)] - Balances(BalancesCall), - /// Utility pallet. - #[codec(index = 26)] - Utility(UtilityCall), - /// Kusama bridge pallet. - #[codec(index = 110)] - BridgeKusamaGrandpa(BridgeKusamaGrandpaCall), - /// Kusama messages pallet. - #[codec(index = 111)] - BridgeKusamaMessages(BridgeKusamaMessagesCall), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum SystemCall { - #[codec(index = 1)] - remark(Vec), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BalancesCall { - #[codec(index = 0)] - transfer(AccountAddress, Compact), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeKusamaGrandpaCall { - #[codec(index = 0)] - submit_finality_proof( - Box<::Header>, - bp_header_chain::justification::GrandpaJustification<::Header>, - ), - #[codec(index = 1)] - initialize(bp_header_chain::InitializationData<::Header>), - #[codec(index = 3)] - set_operational(bool), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeKusamaMessagesCall { - #[codec(index = 2)] - update_pallet_parameter(BridgeKusamaMessagesParameter), - #[codec(index = 3)] - send_message( - LaneId, - bp_message_dispatch::MessagePayload< - bp_polkadot::AccountId, - bp_kusama::AccountId, - bp_kusama::AccountPublic, - Vec, - >, - bp_polkadot::Balance, - ), - #[codec(index = 5)] - receive_messages_proof( - bp_kusama::AccountId, - bridge_runtime_common::messages::target::FromBridgedChainMessagesProof, - u32, - Weight, - ), - #[codec(index = 6)] - receive_messages_delivery_proof( - bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof< - bp_kusama::Hash, - >, - UnrewardedRelayersState, - ), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum UtilityCall { - #[codec(index = 2)] - batch_all(Vec), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum BridgeKusamaMessagesParameter { - #[codec(index = 0)] - KusamaToPolkadotConversionRate(FixedU128), -} - -impl sp_runtime::traits::Dispatchable for Call { - type Origin = (); - type Config = (); - type Info = (); - type PostInfo = (); - - fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { - unimplemented!("The Call is not expected to be dispatched.") - } -} diff --git a/relays/client-rialto-parachain/Cargo.toml b/relays/client-rialto-parachain/Cargo.toml index ebc2856064..915d0e786c 100644 --- a/relays/client-rialto-parachain/Cargo.toml +++ b/relays/client-rialto-parachain/Cargo.toml @@ -6,12 +6,14 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } # Bridge dependencies -bp-rialto = { path = "../../primitives/chain-rialto" } +bp-messages = { path = "../../primitives/messages" } +bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" } rialto-parachain-runtime = { path = "../../bin/rialto-parachain/runtime" } # Substrate Dependencies @@ -19,3 +21,5 @@ rialto-parachain-runtime = { path = "../../bin/rialto-parachain/runtime" } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-rialto-parachain/src/lib.rs b/relays/client-rialto-parachain/src/lib.rs index 65bf46f660..c678a21420 100644 --- a/relays/client-rialto-parachain/src/lib.rs +++ b/relays/client-rialto-parachain/src/lib.rs @@ -16,8 +16,15 @@ //! Types used to connect to the Rialto-Substrate chain. +use bp_messages::MessageNonce; +use codec::Encode; use frame_support::weights::Weight; -use relay_substrate_client::{Chain, ChainBase}; +use relay_substrate_client::{ + Chain, ChainBase, ChainWithBalances, ChainWithMessages, Error as SubstrateError, SignParam, + TransactionSignScheme, UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; use std::time::Duration; /// Rialto header id. @@ -40,24 +47,123 @@ impl ChainBase for RialtoParachain { type Signature = rialto_parachain_runtime::Signature; fn max_extrinsic_size() -> u32 { - bp_rialto::Rialto::max_extrinsic_size() + bp_rialto_parachain::RialtoParachain::max_extrinsic_size() } fn max_extrinsic_weight() -> Weight { - bp_rialto::Rialto::max_extrinsic_weight() + bp_rialto_parachain::RialtoParachain::max_extrinsic_weight() } } impl Chain for RialtoParachain { const NAME: &'static str = "RialtoParachain"; - const TOKEN_ID: Option<&'static str> = None; - // should be fixed/changed in https://github.com/paritytech/parity-bridges-common/pull/1199 - const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = ""; + // RialtoParachain token has no value, but we associate it with DOT token + const TOKEN_ID: Option<&'static str> = Some("polkadot"); + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rialto_parachain::BEST_FINALIZED_RIALTO_PARACHAIN_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); - const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; + const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE; type SignedBlock = rialto_parachain_runtime::SignedBlock; type Call = rialto_parachain_runtime::Call; - type WeightToFee = bp_rialto::WeightToFee; + type WeightToFee = bp_rialto_parachain::WeightToFee; } + +impl ChainWithBalances for RialtoParachain { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + use frame_support::storage::generator::StorageMap; + StorageKey( + frame_system::Account::::storage_map_final_key( + account_id, + ), + ) + } +} + +impl ChainWithMessages for RialtoParachain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto_parachain::TO_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto_parachain::FROM_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_rialto_parachain::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto_parachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); +} + +impl TransactionSignScheme for RialtoParachain { + type Chain = RialtoParachain; + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = rialto_parachain_runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::from_raw( + unsigned.call, + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from( + unsigned.era.frame_era(), + ), + frame_system::CheckNonce::::from(unsigned.nonce), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::< + rialto_parachain_runtime::Runtime, + >::from(unsigned.tip), + ), + ( + (), + param.spec_version, + param.transaction_version, + param.genesis_hash, + unsigned.era.signed_payload(param.genesis_hash), + (), + (), + (), + ), + ); + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(rialto_parachain_runtime::UncheckedExtrinsic::new_signed( + call.into_decoded()?, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| { + *address == rialto_parachain_runtime::Address::Id(signer.public().into()) + }) + .unwrap_or(false) + } + + fn parse_transaction(_tx: Self::SignedTransaction) -> Option> { + unimplemented!("TODO") + } +} + +/// RialtoParachain signing params. +pub type SigningParams = sp_core::sr25519::Pair; + +/// RialtoParachain header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; diff --git a/relays/client-rialto/Cargo.toml b/relays/client-rialto/Cargo.toml index 37c55dd5f1..ef339feb8a 100644 --- a/relays/client-rialto/Cargo.toml +++ b/relays/client-rialto/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.1.5" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } diff --git a/relays/client-rialto/src/lib.rs b/relays/client-rialto/src/lib.rs index 858227e808..b2984336cd 100644 --- a/relays/client-rialto/src/lib.rs +++ b/relays/client-rialto/src/lib.rs @@ -21,7 +21,8 @@ use codec::{Compact, Decode, Encode}; use frame_support::weights::Weight; use relay_substrate_client::{ BalanceOf, Chain, ChainBase, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, - Error as SubstrateError, IndexOf, SignParam, TransactionSignScheme, UnsignedTransaction, + Error as SubstrateError, IndexOf, RelayChain, SignParam, TransactionSignScheme, + UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; @@ -31,7 +32,7 @@ use std::time::Duration; pub type HeaderId = relay_utils::HeaderId; /// Rialto chain definition -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Rialto; impl ChainBase for Rialto { @@ -62,13 +63,18 @@ impl Chain for Rialto { bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = rialto_runtime::SignedBlock; type Call = rialto_runtime::Call; type WeightToFee = bp_rialto::WeightToFee; } +impl RelayChain for Rialto { + const PARAS_PALLET_NAME: &'static str = bp_rialto::PARAS_PALLET_NAME; + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = + bp_rialto::WITH_RIALTO_BRIDGE_PARAS_PALLET_NAME; +} + impl ChainWithGrandpa for Rialto { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = bp_rialto::WITH_RIALTO_GRANDPA_PALLET_NAME; } @@ -78,6 +84,8 @@ impl ChainWithMessages for Rialto { bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto::FROM_RIALTO_MESSAGE_DETAILS_METHOD; const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT; const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = @@ -101,25 +109,28 @@ impl TransactionSignScheme for Rialto { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = rialto_runtime::UncheckedExtrinsic; - fn sign_transaction(param: SignParam) -> Result { + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { let raw_payload = SignedPayload::from_raw( - param.unsigned.call.clone(), + unsigned.call.clone(), ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(param.era.frame_era()), - frame_system::CheckNonce::::from(param.unsigned.nonce), + frame_system::CheckEra::::from(unsigned.era.frame_era()), + frame_system::CheckNonce::::from(unsigned.nonce), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(param.unsigned.tip), + pallet_transaction_payment::ChargeTransactionPayment::::from(unsigned.tip), ), ( (), param.spec_version, param.transaction_version, param.genesis_hash, - param.era.signed_payload(param.genesis_hash), + unsigned.era.signed_payload(param.genesis_hash), (), (), (), @@ -150,13 +161,17 @@ impl TransactionSignScheme for Rialto { fn parse_transaction(tx: Self::SignedTransaction) -> Option> { let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { - call: tx.function.into(), - nonce: Compact::>::decode(&mut &extra.5.encode()[..]).ok()?.into(), - tip: Compact::>::decode(&mut &extra.7.encode()[..]) - .ok()? - .into(), - }) + Some( + UnsignedTransaction::new( + tx.function.into(), + Compact::>::decode(&mut &extra.5.encode()[..]).ok()?.into(), + ) + .tip( + Compact::>::decode(&mut &extra.7.encode()[..]) + .ok()? + .into(), + ), + ) } } @@ -180,15 +195,17 @@ mod tests { .into(), nonce: 777, tip: 888, - }; - let signed_transaction = Rialto::sign_transaction(SignParam { - spec_version: 42, - transaction_version: 50000, - genesis_hash: [42u8; 32].into(), - signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), era: TransactionEra::immortal(), - unsigned: unsigned.clone(), - }) + }; + let signed_transaction = Rialto::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) .unwrap(); let parsed_transaction = Rialto::parse_transaction(signed_transaction).unwrap(); assert_eq!(parsed_transaction, unsigned); diff --git a/relays/client-rococo/Cargo.toml b/relays/client-rococo/Cargo.toml index 2b78684a85..14d3c8ca23 100644 --- a/relays/client-rococo/Cargo.toml +++ b/relays/client-rococo/Cargo.toml @@ -6,26 +6,14 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } -scale-info = { version = "2.0.1", features = ["derive"] } # Bridge dependencies -bridge-runtime-common = { path = "../../bin/runtime-common" } -bp-header-chain = { path = "../../primitives/header-chain" } -bp-message-dispatch = { path = "../../primitives/message-dispatch" } -bp-messages = { path = "../../primitives/messages" } -bp-polkadot-core = { path = "../../primitives/polkadot-core" } bp-rococo = { path = "../../primitives/chain-rococo" } -bp-runtime = { path = "../../primitives/runtime" } -bp-wococo = { path = "../../primitives/chain-wococo" } -pallet-bridge-dispatch = { path = "../../modules/dispatch" } -pallet-bridge-messages = { path = "../../modules/messages" } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-rococo/src/lib.rs b/relays/client-rococo/src/lib.rs index f63041df9e..c33af96aed 100644 --- a/relays/client-rococo/src/lib.rs +++ b/relays/client-rococo/src/lib.rs @@ -16,19 +16,11 @@ //! Types used to connect to the Rococo-Substrate chain. -use bp_messages::MessageNonce; -use codec::Encode; use frame_support::weights::Weight; -use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, - Error as SubstrateError, SignParam, TransactionSignScheme, UnsignedTransaction, -}; -use sp_core::{storage::StorageKey, Pair}; -use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, ChainWithGrandpa}; +use sp_core::storage::StorageKey; use std::time::Duration; -pub mod runtime; - /// Rococo header id. pub type HeaderId = relay_utils::HeaderId; @@ -66,10 +58,9 @@ impl Chain for Rococo { bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_rococo::SignedBlock; - type Call = crate::runtime::Call; + type Call = (); type WeightToFee = bp_rococo::WeightToFee; } @@ -77,75 +68,8 @@ impl ChainWithGrandpa for Rococo { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = bp_rococo::WITH_ROCOCO_GRANDPA_PALLET_NAME; } -impl ChainWithMessages for Rococo { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = - bp_rococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; - const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = - bp_rococo::TO_ROCOCO_MESSAGE_DETAILS_METHOD; - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = - bp_rococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; - const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = - bp_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = - bp_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - type WeightInfo = (); -} - impl ChainWithBalances for Rococo { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_rococo::account_info_storage_key(account_id)) } } - -impl TransactionSignScheme for Rococo { - type Chain = Rococo; - type AccountKeyPair = sp_core::sr25519::Pair; - type SignedTransaction = crate::runtime::UncheckedExtrinsic; - - fn sign_transaction(param: SignParam) -> Result { - let raw_payload = SignedPayload::new( - param.unsigned.call.clone(), - bp_rococo::SignedExtensions::new( - param.spec_version, - param.transaction_version, - param.era, - param.genesis_hash, - param.unsigned.nonce, - param.unsigned.tip, - ), - ) - .expect("SignedExtension never fails."); - - let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); - let signer: sp_runtime::MultiSigner = param.signer.public().into(); - let (call, extra, _) = raw_payload.deconstruct(); - - Ok(bp_rococo::UncheckedExtrinsic::new_signed( - call, - sp_runtime::MultiAddress::Id(signer.into_account()), - signature.into(), - extra, - )) - } - - fn is_signed(tx: &Self::SignedTransaction) -> bool { - tx.signature.is_some() - } - - fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { - tx.signature - .as_ref() - .map(|(address, _, _)| { - *address == bp_rococo::AccountId::from(*signer.public().as_array_ref()).into() - }) - .unwrap_or(false) - } - - fn parse_transaction(tx: Self::SignedTransaction) -> Option> { - let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { call: tx.function, nonce: extra.nonce(), tip: extra.tip() }) - } -} - -/// Rococo signing params. -pub type SigningParams = sp_core::sr25519::Pair; diff --git a/relays/client-rococo/src/runtime.rs b/relays/client-rococo/src/runtime.rs deleted file mode 100644 index b138080599..0000000000 --- a/relays/client-rococo/src/runtime.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Types that are specific to the Rococo runtime. - -use bp_messages::{LaneId, UnrewardedRelayersState}; -use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike}; -use bp_runtime::Chain; -use codec::{Compact, Decode, Encode}; -use frame_support::weights::Weight; -use scale_info::TypeInfo; - -/// Unchecked Rococo extrinsic. -pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic; - -/// Wococo account ownership digest from Rococo. -/// -/// The byte vector returned by this function should be signed with a Wococo account private key. -/// This way, the owner of `rococo_account_id` on Rococo proves that the Wococo account private key -/// is also under his control. -pub fn rococo_to_wococo_account_ownership_digest( - wococo_call: &Call, - rococo_account_id: AccountId, - wococo_spec_version: SpecVersion, -) -> Vec -where - Call: codec::Encode, - AccountId: codec::Encode, - SpecVersion: codec::Encode, -{ - pallet_bridge_dispatch::account_ownership_digest( - wococo_call, - rococo_account_id, - wococo_spec_version, - bp_runtime::ROCOCO_CHAIN_ID, - bp_runtime::WOCOCO_CHAIN_ID, - ) -} - -/// Rococo Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to Rococo chain. -/// Ideally this code would be auto-generated from metadata, because we want to -/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. -/// -/// All entries here (like pretty much in the entire file) must be kept in sync with Rococo -/// `construct_runtime`, so that we maintain SCALE-compatibility. -/// -/// See: [link](https://github.com/paritytech/polkadot/blob/master/runtime/rococo/src/lib.rs) -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// System pallet. - #[codec(index = 0)] - System(SystemCall), - /// Balances pallet. - #[codec(index = 4)] - Balances(BalancesCall), - /// Wococo bridge pallet. - #[codec(index = 41)] - BridgeGrandpaWococo(BridgeGrandpaWococoCall), - /// Wococo messages pallet. - #[codec(index = 44)] - BridgeWococoMessages(BridgeWococoMessagesCall), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum SystemCall { - #[codec(index = 1)] - remark(Vec), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BalancesCall { - #[codec(index = 0)] - transfer(AccountAddress, Compact), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeGrandpaWococoCall { - #[codec(index = 0)] - submit_finality_proof( - Box<::Header>, - bp_header_chain::justification::GrandpaJustification<::Header>, - ), - #[codec(index = 1)] - initialize(bp_header_chain::InitializationData<::Header>), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeWococoMessagesCall { - #[codec(index = 3)] - send_message( - LaneId, - bp_message_dispatch::MessagePayload< - bp_rococo::AccountId, - bp_wococo::AccountId, - bp_wococo::AccountPublic, - Vec, - >, - bp_rococo::Balance, - ), - #[codec(index = 5)] - receive_messages_proof( - bp_wococo::AccountId, - bridge_runtime_common::messages::target::FromBridgedChainMessagesProof, - u32, - Weight, - ), - #[codec(index = 6)] - receive_messages_delivery_proof( - bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof< - bp_wococo::Hash, - >, - UnrewardedRelayersState, - ), -} - -impl sp_runtime::traits::Dispatchable for Call { - type Origin = (); - type Config = (); - type Info = (); - type PostInfo = (); - - fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { - unimplemented!("The Call is not expected to be dispatched.") - } -} diff --git a/relays/client-substrate/Cargo.toml b/relays/client-substrate/Cargo.toml index dad864965e..721415fb2d 100644 --- a/relays/client-substrate/Cargo.toml +++ b/relays/client-substrate/Cargo.toml @@ -7,10 +7,11 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-std = { version = "1.6.5", features = ["attributes"] } -async-trait = "0.1.40" -codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.8", features = ["macros", "ws-client"] } -log = "0.4.11" +async-trait = "0.1" +codec = { package = "parity-scale-codec", version = "3.1.5" } +futures = "0.3.7" +jsonrpsee = { version = "0.15", features = ["macros", "ws-client"] } +log = "0.4.17" num-traits = "0.2" rand = "0.7" serde = { version = "1.0" } @@ -44,5 +45,6 @@ sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" } -#[dev-dependencies] -futures = "0.3.7" +[features] +default = [] +test-helpers = [] diff --git a/relays/client-substrate/src/chain.rs b/relays/client-substrate/src/chain.rs index 60adfb0a88..9562d68d46 100644 --- a/relays/client-substrate/src/chain.rs +++ b/relays/client-substrate/src/chain.rs @@ -15,9 +15,11 @@ // along with Parity Bridges Common. If not, see . use bp_messages::MessageNonce; -use bp_runtime::{Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEraOf}; +use bp_runtime::{ + Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEra, TransactionEraOf, +}; use codec::{Codec, Encode}; -use frame_support::weights::{Weight, WeightToFeePolynomial}; +use frame_support::weights::{Weight, WeightToFee}; use jsonrpsee::core::{DeserializeOwned, Serialize}; use num_traits::Zero; use sc_transaction_pool_api::TransactionStatus; @@ -52,8 +54,6 @@ pub trait Chain: ChainBase + Clone { const AVERAGE_BLOCK_INTERVAL: Duration; /// Maximal expected storage proof overhead (in bytes). const STORAGE_PROOF_OVERHEAD: u32; - /// Maximal size (in bytes) of SCALE-encoded account id on this chain. - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32; /// Block type. type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification; @@ -61,7 +61,21 @@ pub trait Chain: ChainBase + Clone { type Call: Clone + Codec + Dispatchable + Debug + Send; /// Type that is used by the chain, to convert from weight to fee. - type WeightToFee: WeightToFeePolynomial; + type WeightToFee: WeightToFee; +} + +/// Substrate-based relay chain that supports parachains. +/// +/// We assume that the parachains are supported using `runtime_parachains::paras` pallet. +pub trait RelayChain: Chain { + /// Name of the `runtime_parachains::paras` pallet in the runtime of this chain. + const PARAS_PALLET_NAME: &'static str; + /// Name of the bridge parachains pallet (used in `construct_runtime` macro call) that is + /// deployed at the **bridged** chain. + /// + /// We assume that all chains that are bridging with this `ChainWithGrandpa` are using + /// the same name. + const PARACHAINS_FINALITY_PALLET_NAME: &'static str; } /// Substrate-based chain that is using direct GRANDPA finality from minimal relay-client point of @@ -91,6 +105,10 @@ pub trait ChainWithMessages: Chain { /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str; + /// Name of the `FromInboundLaneApi::message_details` runtime API method. + /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str; + /// Additional weight of the dispatch fee payment if dispatch is paid at the target chain /// and this `ChainWithMessages` is the target chain. const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight; @@ -142,26 +160,36 @@ pub struct UnsignedTransaction { pub nonce: C::Index, /// Tip included into transaction. pub tip: C::Balance, + /// Transaction era used by the chain. + pub era: TransactionEraOf, } impl UnsignedTransaction { - /// Create new unsigned transaction with given call, nonce and zero tip. + /// Create new unsigned transaction with given call, nonce, era and zero tip. pub fn new(call: EncodedOrDecodedCall, nonce: C::Index) -> Self { - Self { call, nonce, tip: Zero::zero() } + Self { call, nonce, era: TransactionEra::Immortal, tip: Zero::zero() } } /// Set transaction tip. + #[must_use] pub fn tip(mut self, tip: C::Balance) -> Self { self.tip = tip; self } + + /// Set transaction era. + #[must_use] + pub fn era(mut self, era: TransactionEraOf) -> Self { + self.era = era; + self + } } /// Account key pair used by transactions signing scheme. pub type AccountKeyPairOf = ::AccountKeyPair; /// Substrate-based chain transactions signing scheme. -pub trait TransactionSignScheme { +pub trait TransactionSignScheme: 'static { /// Chain that this scheme is to be used. type Chain: Chain; /// Type of key pairs used to sign transactions. @@ -170,7 +198,10 @@ pub trait TransactionSignScheme { type SignedTransaction: Clone + Debug + Codec + Send + 'static; /// Create transaction for given runtime call, signed by given account. - fn sign_transaction(param: SignParam) -> Result + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result where Self: Sized; @@ -196,10 +227,6 @@ pub struct SignParam { pub genesis_hash: ::Hash, /// Signer account pub signer: T::AccountKeyPair, - /// Transaction era used by the chain. - pub era: TransactionEraOf, - /// Transaction before it is signed. - pub unsigned: UnsignedTransaction, } impl BlockWithJustification for SignedBlock { diff --git a/relays/client-substrate/src/client.rs b/relays/client-substrate/src/client.rs index 1e48bc3339..b1f0eb8587 100644 --- a/relays/client-substrate/src/client.rs +++ b/relays/client-substrate/src/client.rs @@ -17,26 +17,30 @@ //! Substrate node client. use crate::{ - chain::{Chain, ChainWithBalances, TransactionStatusOf}, - rpc::SubstrateClient, - AccountIdOf, BlockNumberOf, ConnectionParams, Error, HashOf, HeaderIdOf, HeaderOf, IndexOf, - Result, + chain::{Chain, ChainWithBalances}, + rpc::{ + SubstrateAuthorClient, SubstrateChainClient, SubstrateFrameSystemClient, + SubstrateGrandpaClient, SubstrateStateClient, SubstrateSystemClient, + SubstrateTransactionPaymentClient, + }, + ConnectionParams, Error, HashOf, HeaderIdOf, Result, SignParam, TransactionSignScheme, + TransactionStatusOf, UnsignedTransaction, }; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; +use bp_runtime::{HeaderIdProvider, StorageDoubleMapKeyProvider, StorageMapKeyProvider}; use codec::{Decode, Encode}; use frame_system::AccountInfo; use futures::{SinkExt, StreamExt}; use jsonrpsee::{ - core::{client::SubscriptionClientT, DeserializeOwned}, - types::params::ParamsSer, + core::DeserializeOwned, ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder}, }; -use num_traits::{Bounded, CheckedSub, One, Zero}; +use num_traits::{Bounded, Zero}; use pallet_balances::AccountData; use pallet_transaction_payment::InclusionFee; -use relay_utils::{relay_loop::RECONNECT_DELAY, HeaderId}; +use relay_utils::relay_loop::RECONNECT_DELAY; use sp_core::{ storage::{StorageData, StorageKey}, Bytes, Hasher, @@ -77,7 +81,7 @@ pub struct Client { /// Tokio runtime handle. tokio: Arc, /// Client connection params. - params: ConnectionParams, + params: Arc, /// Substrate RPC client. client: Arc, /// Genesis block hash. @@ -96,7 +100,7 @@ impl relay_utils::relay_loop::Client for Client { type Error = Error; async fn reconnect(&mut self) -> Result<()> { - let (tokio, client) = Self::build_client(self.params.clone()).await?; + let (tokio, client) = Self::build_client(&self.params).await?; self.tokio = tokio; self.client = client; Ok(()) @@ -128,6 +132,7 @@ impl Client { /// This function will keep connecting to given Substrate node until connection is established /// and is functional. If attempt fail, it will wait for `RECONNECT_DELAY` and retry again. pub async fn new(params: ConnectionParams) -> Self { + let params = Arc::new(params); loop { match Self::try_connect(params.clone()).await { Ok(client) => return client, @@ -146,22 +151,14 @@ impl Client { /// Try to connect to Substrate node over websocket. Returns Substrate RPC client if connection /// has been established or error otherwise. - pub async fn try_connect(params: ConnectionParams) -> Result { - let (tokio, client) = Self::build_client(params.clone()).await?; + pub async fn try_connect(params: Arc) -> Result { + let (tokio, client) = Self::build_client(¶ms).await?; let number: C::BlockNumber = Zero::zero(); let genesis_hash_client = client.clone(); let genesis_hash = tokio .spawn(async move { - SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::chain_get_block_hash(&*genesis_hash_client, Some(number)) - .await + SubstrateChainClient::::block_hash(&*genesis_hash_client, Some(number)).await }) .await??; @@ -178,7 +175,7 @@ impl Client { /// Build client to use in connection. async fn build_client( - params: ConnectionParams, + params: &ConnectionParams, ) -> Result<(Arc, Arc)> { let tokio = tokio::runtime::Runtime::new()?; let uri = format!( @@ -187,6 +184,8 @@ impl Client { params.host, params.port, ); + log::info!(target: "bridge", "Connecting to {} node at {}", C::NAME, uri); + let client = tokio .spawn(async move { RpcClientBuilder::default() @@ -217,15 +216,7 @@ impl Client { /// Returns true if client is connected to at least one peer and is in synced state. pub async fn ensure_synced(&self) -> Result<()> { self.jsonrpsee_execute(|client| async move { - let health = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::system_health(&*client) - .await?; + let health = SubstrateSystemClient::::health(&*client).await?; let is_synced = !health.is_syncing && (!health.should_have_peers || health.peers > 0); if is_synced { Ok(()) @@ -244,15 +235,7 @@ impl Client { /// Return hash of the best finalized block. pub async fn best_finalized_header_hash(&self) -> Result { self.jsonrpsee_execute(|client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::chain_get_finalized_head(&*client) - .await?) + Ok(SubstrateChainClient::::finalized_head(&*client).await?) }) .await } @@ -262,21 +245,18 @@ impl Client { Ok(*self.header_by_hash(self.best_finalized_header_hash().await?).await?.number()) } + /// Return header of the best finalized block. + pub async fn best_finalized_header(&self) -> Result { + self.header_by_hash(self.best_finalized_header_hash().await?).await + } + /// Returns the best Substrate header. pub async fn best_header(&self) -> Result where C::Header: DeserializeOwned, { self.jsonrpsee_execute(|client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::chain_get_header(&*client, None) - .await?) + Ok(SubstrateChainClient::::header(&*client, None).await?) }) .await } @@ -284,15 +264,7 @@ impl Client { /// Get a Substrate block from its hash. pub async fn get_block(&self, block_hash: Option) -> Result { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::chain_get_block(&*client, block_hash) - .await?) + Ok(SubstrateChainClient::::block(&*client, block_hash).await?) }) .await } @@ -303,15 +275,7 @@ impl Client { C::Header: DeserializeOwned, { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::chain_get_header(&*client, Some(block_hash)) - .await?) + Ok(SubstrateChainClient::::header(&*client, Some(block_hash)).await?) }) .await } @@ -319,15 +283,7 @@ impl Client { /// Get a Substrate block hash by its number. pub async fn block_hash_by_number(&self, number: C::BlockNumber) -> Result { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::chain_get_block_hash(&*client, Some(number)) - .await?) + Ok(SubstrateChainClient::::block_hash(&*client, Some(number)).await?) }) .await } @@ -345,15 +301,7 @@ impl Client { /// Return runtime version. pub async fn runtime_version(&self) -> Result { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_runtime_version(&*client) - .await?) + Ok(SubstrateStateClient::::runtime_version(&*client).await?) }) .await } @@ -372,6 +320,41 @@ impl Client { .transpose() } + /// Read `MapStorage` value from runtime storage. + pub async fn storage_map_value( + &self, + pallet_prefix: &str, + key: &T::Key, + block_hash: Option, + ) -> Result> { + let storage_key = T::final_key(pallet_prefix, key); + + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::Value::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + + /// Read `DoubleMapStorage` value from runtime storage. + pub async fn storage_double_map_value( + &self, + pallet_prefix: &str, + key1: &T::Key1, + key2: &T::Key2, + block_hash: Option, + ) -> Result> { + let storage_key = T::final_key(pallet_prefix, key1, key2); + + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::Value::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + /// Read raw value from runtime storage. pub async fn raw_storage_value( &self, @@ -379,15 +362,7 @@ impl Client { block_hash: Option, ) -> Result> { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_get_storage(&*client, storage_key, block_hash) - .await?) + Ok(SubstrateStateClient::::storage(&*client, storage_key, block_hash).await?) }) .await } @@ -399,16 +374,10 @@ impl Client { { self.jsonrpsee_execute(move |client| async move { let storage_key = C::account_info_storage_key(&account); - let encoded_account_data = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_get_storage(&*client, storage_key, None) - .await? - .ok_or(Error::AccountDoesNotExist)?; + let encoded_account_data = + SubstrateStateClient::::storage(&*client, storage_key, None) + .await? + .ok_or(Error::AccountDoesNotExist)?; let decoded_account_data = AccountInfo::>::decode( &mut &encoded_account_data.0[..], ) @@ -423,15 +392,7 @@ impl Client { /// Note: It's the caller's responsibility to make sure `account` is a valid SS58 address. pub async fn next_account_index(&self, account: C::AccountId) -> Result { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::system_account_next_index(&*client, account) - .await?) + Ok(SubstrateFrameSystemClient::::account_next_index(&*client, account).await?) }) .await } @@ -441,16 +402,13 @@ impl Client { /// Note: The given transaction needs to be SCALE encoded beforehand. pub async fn submit_unsigned_extrinsic(&self, transaction: Bytes) -> Result { self.jsonrpsee_execute(move |client| async move { - let tx_hash = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::author_submit_extrinsic(&*client, transaction) - .await?; - log::trace!(target: "bridge", "Sent transaction to Substrate node: {:?}", tx_hash); + let tx_hash = SubstrateAuthorClient::::submit_extrinsic(&*client, transaction) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; + log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); Ok(tx_hash) }) .await @@ -463,36 +421,35 @@ impl Client { /// if all client instances are clones of the same initial `Client`. /// /// Note: The given transaction needs to be SCALE encoded beforehand. - pub async fn submit_signed_extrinsic( + pub async fn submit_signed_extrinsic + 'static>( &self, extrinsic_signer: C::AccountId, - prepare_extrinsic: impl FnOnce(HeaderIdOf, C::Index) -> Result + Send + 'static, + signing_data: SignParam, + prepare_extrinsic: impl FnOnce(HeaderIdOf, C::Index) -> Result> + + Send + + 'static, ) -> Result { let _guard = self.submit_signed_extrinsic_lock.lock().await; let transaction_nonce = self.next_account_index(extrinsic_signer).await?; let best_header = self.best_header().await?; // By using parent of best block here, we are protecing again best-block reorganizations. - // E.g. transaction my have been submitted when the best block was `A[num=100]`. Then it has - // been changed to `B[num=100]`. Hash of `A` has been included into transaction signature - // payload. So when signature will be checked, the check will fail and transaction will be - // dropped from the pool. - let best_header_id = match best_header.number().checked_sub(&One::one()) { - Some(parent_block_number) => HeaderId(parent_block_number, *best_header.parent_hash()), - None => HeaderId(*best_header.number(), best_header.hash()), - }; + // E.g. transaction may have been submitted when the best block was `A[num=100]`. Then it + // has been changed to `B[num=100]`. Hash of `A` has been included into transaction + // signature payload. So when signature will be checked, the check will fail and transaction + // will be dropped from the pool. + let best_header_id = best_header.parent_id().unwrap_or_else(|| best_header.id()); self.jsonrpsee_execute(move |client| async move { let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?; - let tx_hash = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::author_submit_extrinsic(&*client, extrinsic) - .await?; + let signed_extrinsic = S::sign_transaction(signing_data, extrinsic)?.encode(); + let tx_hash = + SubstrateAuthorClient::::submit_extrinsic(&*client, Bytes(signed_extrinsic)) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); Ok(tx_hash) }) @@ -501,27 +458,34 @@ impl Client { /// Does exactly the same as `submit_signed_extrinsic`, but keeps watching for extrinsic status /// after submission. - pub async fn submit_and_watch_signed_extrinsic( + pub async fn submit_and_watch_signed_extrinsic< + S: TransactionSignScheme + 'static, + >( &self, extrinsic_signer: C::AccountId, - prepare_extrinsic: impl FnOnce(HeaderIdOf, C::Index) -> Result + Send + 'static, + signing_data: SignParam, + prepare_extrinsic: impl FnOnce(HeaderIdOf, C::Index) -> Result> + + Send + + 'static, ) -> Result>> { let _guard = self.submit_signed_extrinsic_lock.lock().await; let transaction_nonce = self.next_account_index(extrinsic_signer).await?; let best_header = self.best_header().await?; - let best_header_id = HeaderId(*best_header.number(), best_header.hash()); + let best_header_id = best_header.id(); let subscription = self .jsonrpsee_execute(move |client| async move { let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?; - let tx_hash = C::Hasher::hash(&extrinsic.0); - let subscription = client - .subscribe( - "author_submitAndWatchExtrinsic", - Some(ParamsSer::Array(vec![jsonrpsee::core::to_json_value(extrinsic) - .map_err(|e| Error::RpcError(e.into()))?])), - "author_unwatchExtrinsic", - ) - .await?; + let signed_extrinsic = S::sign_transaction(signing_data, extrinsic)?.encode(); + let tx_hash = C::Hasher::hash(&signed_extrinsic); + let subscription = SubstrateAuthorClient::::submit_and_watch_extrinsic( + &*client, + Bytes(signed_extrinsic), + ) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); Ok(subscription) }) @@ -539,15 +503,7 @@ impl Client { /// Returns pending extrinsics from transaction pool. pub async fn pending_extrinsics(&self) -> Result> { self.jsonrpsee_execute(move |client| async move { - Ok(SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::author_pending_extrinsics(&*client) - .await?) + Ok(SubstrateAuthorClient::::pending_extrinsics(&*client).await?) }) .await } @@ -562,15 +518,8 @@ impl Client { let call = SUB_API_TXPOOL_VALIDATE_TRANSACTION.to_string(); let data = Bytes((TransactionSource::External, transaction, at_block).encode()); - let encoded_response = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_call(&*client, call, data, Some(at_block)) - .await?; + let encoded_response = + SubstrateStateClient::::call(&*client, call, data, Some(at_block)).await?; let validity = TransactionValidity::decode(&mut &encoded_response.0[..]) .map_err(Error::ResponseParseFailed)?; @@ -585,15 +534,9 @@ impl Client { transaction: Bytes, ) -> Result> { self.jsonrpsee_execute(move |client| async move { - let fee_details = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::payment_query_fee_details(&*client, transaction, None) - .await?; + let fee_details = + SubstrateTransactionPaymentClient::::fee_details(&*client, transaction, None) + .await?; let inclusion_fee = fee_details .inclusion_fee .map(|inclusion_fee| InclusionFee { @@ -625,15 +568,8 @@ impl Client { let call = SUB_API_GRANDPA_AUTHORITIES.to_string(); let data = Bytes(Vec::new()); - let encoded_response = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_call(&*client, call, data, Some(block)) - .await?; + let encoded_response = + SubstrateStateClient::::call(&*client, call, data, Some(block)).await?; let authority_list = encoded_response.0; Ok(authority_list) @@ -641,6 +577,18 @@ impl Client { .await } + /// Execute runtime call at given block, provided the input and output types. + /// It also performs the input encode and output decode. + pub async fn typed_state_call( + &self, + method_name: String, + input: Input, + at_block: Option, + ) -> Result { + let encoded_output = self.state_call(method_name, Bytes(input.encode()), at_block).await?; + Output::decode(&mut &encoded_output.0[..]).map_err(Error::ResponseParseFailed) + } + /// Execute runtime call at given block. pub async fn state_call( &self, @@ -649,16 +597,9 @@ impl Client { at_block: Option, ) -> Result { self.jsonrpsee_execute(move |client| async move { - SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_call(&*client, method, data, at_block) - .await - .map_err(Into::into) + SubstrateStateClient::::call(&*client, method, data, at_block) + .await + .map_err(Into::into) }) .await } @@ -670,19 +611,12 @@ impl Client { at_block: C::Hash, ) -> Result { self.jsonrpsee_execute(move |client| async move { - SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::state_prove_storage(&*client, keys, Some(at_block)) - .await - .map(|proof| { - StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect::>()) - }) - .map_err(Into::into) + SubstrateStateClient::::prove_storage(&*client, keys, Some(at_block)) + .await + .map(|proof| { + StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect::>()) + }) + .map_err(Into::into) }) .await } @@ -690,31 +624,17 @@ impl Client { /// Return `tokenDecimals` property from the set of chain properties. pub async fn token_decimals(&self) -> Result> { self.jsonrpsee_execute(move |client| async move { - let system_properties = SubstrateClient::< - AccountIdOf, - BlockNumberOf, - HashOf, - HeaderOf, - IndexOf, - C::SignedBlock, - >::system_properties(&*client) - .await?; + let system_properties = SubstrateSystemClient::::properties(&*client).await?; Ok(system_properties.get("tokenDecimals").and_then(|v| v.as_u64())) }) .await } - /// Return new justifications stream. - pub async fn subscribe_justifications(&self) -> Result> { + /// Return new GRANDPA justifications stream. + pub async fn subscribe_grandpa_justifications(&self) -> Result> { let subscription = self .jsonrpsee_execute(move |client| async move { - Ok(client - .subscribe( - "grandpa_subscribeJustifications", - None, - "grandpa_unsubscribeJustifications", - ) - .await?) + Ok(SubstrateGrandpaClient::::subscribe_justifications(&*client).await?) }) .await?; let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY); @@ -737,6 +657,15 @@ impl Client { let client = self.client.clone(); self.tokio.spawn(async move { make_jsonrpsee_future(client).await }).await? } + + /// Returns `true` if version guard can be started. + /// + /// There's no reason to run version guard when version mode is set to `Auto`. It can + /// lead to relay shutdown when chain is upgraded, even though we have explicitly + /// said that we don't want to shutdown. + pub fn can_start_version_guard(&self) -> bool { + !matches!(self.chain_runtime_version, ChainRuntimeVersion::Auto) + } } impl Subscription { diff --git a/relays/client-substrate/src/error.rs b/relays/client-substrate/src/error.rs index e698f2596c..016ec774be 100644 --- a/relays/client-substrate/src/error.rs +++ b/relays/client-substrate/src/error.rs @@ -45,15 +45,18 @@ pub enum Error { /// Account does not exist on the chain. #[error("Account does not exist on the chain.")] AccountDoesNotExist, - /// Runtime storage is missing mandatory ":code:" entry. - #[error("Mandatory :code: entry is missing from runtime storage.")] - MissingMandatoryCodeEntry, + /// Runtime storage is missing some mandatory value. + #[error("Mandatory storage value is missing from the runtime storage.")] + MissingMandatoryStorageValue, /// The client we're connected to is not synced, so we can't rely on its state. #[error("Substrate client is not synced {0}.")] ClientNotSynced(Health), /// The bridge pallet is halted and all transactions will be rejected. #[error("Bridge pallet is halted.")] BridgePalletIsHalted, + /// The bridge pallet is not yet initialized and all transactions will be rejected. + #[error("Bridge pallet is not initialized.")] + BridgePalletIsNotInitialized, /// An error has happened when we have tried to parse storage proof. #[error("Error when parsing storage proof: {0:?}.")] StorageProofError(bp_runtime::StorageProofError), diff --git a/relays/client-substrate/src/guard.rs b/relays/client-substrate/src/guard.rs index 359a3f69d8..bc8fd8e7d3 100644 --- a/relays/client-substrate/src/guard.rs +++ b/relays/client-substrate/src/guard.rs @@ -196,7 +196,7 @@ impl Environment for Client { #[cfg(test)] mod tests { use super::*; - use frame_support::weights::{IdentityFee, Weight}; + use crate::test_chain::TestChain; use futures::{ channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, future::FutureExt, @@ -204,49 +204,6 @@ mod tests { SinkExt, }; - #[derive(Debug, Clone)] - struct TestChain; - - impl bp_runtime::Chain for TestChain { - type BlockNumber = u32; - type Hash = sp_core::H256; - type Hasher = sp_runtime::traits::BlakeTwo256; - type Header = sp_runtime::generic::Header; - - type AccountId = u32; - type Balance = u32; - type Index = u32; - type Signature = sp_runtime::testing::TestSignature; - - fn max_extrinsic_size() -> u32 { - unreachable!() - } - fn max_extrinsic_weight() -> Weight { - unreachable!() - } - } - - impl Chain for TestChain { - const NAME: &'static str = "Test"; - const TOKEN_ID: Option<&'static str> = None; - const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "BestTestHeader"; - const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1); - const STORAGE_PROOF_OVERHEAD: u32 = 0; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0; - - type SignedBlock = sp_runtime::generic::SignedBlock< - sp_runtime::generic::Block, - >; - type Call = (); - type WeightToFee = IdentityFee; - } - - impl ChainWithBalances for TestChain { - fn account_info_storage_key(_account_id: &u32) -> sp_core::storage::StorageKey { - unreachable!() - } - } - struct TestEnvironment { runtime_version_rx: UnboundedReceiver, free_native_balance_rx: UnboundedReceiver, diff --git a/relays/client-substrate/src/lib.rs b/relays/client-substrate/src/lib.rs index b3a7ec4141..0234459f9d 100644 --- a/relays/client-substrate/src/lib.rs +++ b/relays/client-substrate/src/lib.rs @@ -26,14 +26,15 @@ mod sync_header; pub mod guard; pub mod metrics; +pub mod test_chain; use std::time::Duration; pub use crate::{ chain::{ AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances, - ChainWithGrandpa, ChainWithMessages, SignParam, TransactionSignScheme, TransactionStatusOf, - UnsignedTransaction, WeightToFeeOf, + ChainWithGrandpa, ChainWithMessages, RelayChain, SignParam, TransactionSignScheme, + TransactionStatusOf, UnsignedTransaction, WeightToFeeOf, }, client::{ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, Subscription}, error::{Error, Result}, diff --git a/relays/client-substrate/src/metrics/storage_proof_overhead.rs b/relays/client-substrate/src/metrics/storage_proof_overhead.rs index f1c770ed22..42793fe7c5 100644 --- a/relays/client-substrate/src/metrics/storage_proof_overhead.rs +++ b/relays/client-substrate/src/metrics/storage_proof_overhead.rs @@ -72,7 +72,7 @@ impl StorageProofOverheadMetric { let maybe_encoded_storage_value = storage_value_reader.read_value(CODE).map_err(Error::StorageProofError)?; let encoded_storage_value_size = - maybe_encoded_storage_value.ok_or(Error::MissingMandatoryCodeEntry)?.len(); + maybe_encoded_storage_value.ok_or(Error::MissingMandatoryStorageValue)?.len(); Ok(storage_proof_size - encoded_storage_value_size) } diff --git a/relays/client-substrate/src/rpc.rs b/relays/client-substrate/src/rpc.rs index a0172d1e55..fdba424dd9 100644 --- a/relays/client-substrate/src/rpc.rs +++ b/relays/client-substrate/src/rpc.rs @@ -16,6 +16,8 @@ //! The most generic Substrate node RPC interface. +use crate::{Chain, TransactionStatusOf}; + use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use pallet_transaction_payment_rpc_runtime_api::FeeDetails; use sc_rpc_api::{state::ReadProof, system::Health}; @@ -26,51 +28,102 @@ use sp_core::{ use sp_rpc::number::NumberOrHex; use sp_version::RuntimeVersion; -#[rpc(client)] -pub(crate) trait Substrate { - #[method(name = "system_health", param_kind = array)] - async fn system_health(&self) -> RpcResult; - #[method(name = "system_properties", param_kind = array)] - async fn system_properties(&self) -> RpcResult; - #[method(name = "chain_getHeader", param_kind = array)] - async fn chain_get_header(&self, block_hash: Option) -> RpcResult

; - #[method(name = "chain_getFinalizedHead", param_kind = array)] - async fn chain_get_finalized_head(&self) -> RpcResult; - #[method(name = "chain_getBlock", param_kind = array)] - async fn chain_get_block(&self, block_hash: Option) -> RpcResult; - #[method(name = "chain_getBlockHash", param_kind = array)] - async fn chain_get_block_hash(&self, block_number: Option) -> RpcResult; - #[method(name = "system_accountNextIndex", param_kind = array)] - async fn system_account_next_index(&self, account_id: AccountId) -> RpcResult; - #[method(name = "author_submitExtrinsic", param_kind = array)] - async fn author_submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; - #[method(name = "author_pendingExtrinsics", param_kind = array)] - async fn author_pending_extrinsics(&self) -> RpcResult>; - #[method(name = "state_call", param_kind = array)] - async fn state_call( +/// RPC methods of Substrate `system` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "system")] +pub(crate) trait SubstrateSystem { + /// Return node health. + #[method(name = "health")] + async fn health(&self) -> RpcResult; + /// Return system properties. + #[method(name = "properties")] + async fn properties(&self) -> RpcResult; +} + +/// RPC methods of Substrate `chain` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "chain")] +pub(crate) trait SubstrateChain { + /// Get block hash by its number. + #[method(name = "getBlockHash")] + async fn block_hash(&self, block_number: Option) -> RpcResult; + /// Return block header by its hash. + #[method(name = "getHeader")] + async fn header(&self, block_hash: Option) -> RpcResult; + /// Return best finalized block hash. + #[method(name = "getFinalizedHead")] + async fn finalized_head(&self) -> RpcResult; + /// Return signed block (with justifications) by its hash. + #[method(name = "getBlock")] + async fn block(&self, block_hash: Option) -> RpcResult; +} + +/// RPC methods of Substrate `author` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "author")] +pub(crate) trait SubstrateAuthor { + /// Submit extrinsic to the transaction pool. + #[method(name = "submitExtrinsic")] + async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; + /// Return vector of pending extrinsics from the transaction pool. + #[method(name = "pendingExtrinsics")] + async fn pending_extrinsics(&self) -> RpcResult>; + /// Submit and watch for extrinsic state. + #[subscription(name = "submitAndWatchExtrinsic", unsubscribe = "unwatchExtrinsic", item = TransactionStatusOf)] + fn submit_and_watch_extrinsic(&self, extrinsic: Bytes); +} + +/// RPC methods of Substrate `state` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "state")] +pub(crate) trait SubstrateState { + /// Get current runtime version. + #[method(name = "getRuntimeVersion")] + async fn runtime_version(&self) -> RpcResult; + /// Call given runtime method. + #[method(name = "call")] + async fn call( &self, method: String, data: Bytes, - at_block: Option, + at_block: Option, ) -> RpcResult; - #[method(name = "state_getStorage", param_kind = array)] - async fn state_get_storage( + /// Get value of the runtime storage. + #[method(name = "getStorage")] + async fn storage( &self, key: StorageKey, - at_block: Option, + at_block: Option, ) -> RpcResult>; - #[method(name = "state_getReadProof", param_kind = array)] - async fn state_prove_storage( + /// Get proof of the runtime storage value. + #[method(name = "getReadProof")] + async fn prove_storage( &self, keys: Vec, - hash: Option, - ) -> RpcResult>; - #[method(name = "state_getRuntimeVersion", param_kind = array)] - async fn state_runtime_version(&self) -> RpcResult; - #[method(name = "payment_queryFeeDetails", param_kind = array)] - async fn payment_query_fee_details( + hash: Option, + ) -> RpcResult>; +} + +/// RPC methods of Substrate `grandpa` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "grandpa")] +pub(crate) trait SubstrateGrandpa { + /// Subscribe to GRANDPA justifications. + #[subscription(name = "subscribeJustifications", unsubscribe = "unsubscribeJustifications", item = Bytes)] + fn subscribe_justifications(&self); +} + +/// RPC methods of Substrate `system` frame pallet, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "system")] +pub(crate) trait SubstrateFrameSystem { + /// Return index of next account transaction. + #[method(name = "accountNextIndex")] + async fn account_next_index(&self, account_id: C::AccountId) -> RpcResult; +} + +/// RPC methods of Substrate `pallet_transaction_payment` frame pallet, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "payment")] +pub(crate) trait SubstrateTransactionPayment { + /// Query transaction fee details. + #[method(name = "queryFeeDetails")] + async fn fee_details( &self, extrinsic: Bytes, - at_block: Option, + at_block: Option, ) -> RpcResult>; } diff --git a/relays/client-substrate/src/test_chain.rs b/relays/client-substrate/src/test_chain.rs new file mode 100644 index 0000000000..f9a9e2455e --- /dev/null +++ b/relays/client-substrate/src/test_chain.rs @@ -0,0 +1,70 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Pallet provides a set of guard functions that are running in background threads +//! and are aborting process if some condition fails. + +//! Test chain implementation to use in tests. + +#![cfg(any(feature = "test-helpers", test))] + +use crate::{Chain, ChainWithBalances}; +use frame_support::weights::{IdentityFee, Weight}; +use std::time::Duration; + +/// Chain that may be used in tests. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TestChain; + +impl bp_runtime::Chain for TestChain { + type BlockNumber = u32; + type Hash = sp_core::H256; + type Hasher = sp_runtime::traits::BlakeTwo256; + type Header = sp_runtime::generic::Header; + + type AccountId = u32; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl Chain for TestChain { + const NAME: &'static str = "Test"; + const TOKEN_ID: Option<&'static str> = None; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod"; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); + const STORAGE_PROOF_OVERHEAD: u32 = 0; + + type SignedBlock = sp_runtime::generic::SignedBlock< + sp_runtime::generic::Block, + >; + type Call = (); + type WeightToFee = IdentityFee; +} + +impl ChainWithBalances for TestChain { + fn account_info_storage_key(_account_id: &u32) -> sp_core::storage::StorageKey { + unreachable!() + } +} diff --git a/relays/client-westend/Cargo.toml b/relays/client-westend/Cargo.toml index d38aa16299..2ad9963406 100644 --- a/relays/client-westend/Cargo.toml +++ b/relays/client-westend/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } diff --git a/relays/client-westend/src/lib.rs b/relays/client-westend/src/lib.rs index caf0c010c5..4b27bfeb82 100644 --- a/relays/client-westend/src/lib.rs +++ b/relays/client-westend/src/lib.rs @@ -17,7 +17,7 @@ //! Types used to connect to the Westend chain. use frame_support::weights::Weight; -use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, ChainWithGrandpa}; +use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, ChainWithGrandpa, RelayChain}; use sp_core::storage::StorageKey; use std::time::Duration; @@ -58,13 +58,18 @@ impl Chain for Westend { bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_westend::SignedBlock; type Call = bp_westend::Call; type WeightToFee = bp_westend::WeightToFee; } +impl RelayChain for Westend { + const PARAS_PALLET_NAME: &'static str = bp_westend::PARAS_PALLET_NAME; + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = + bp_westend::WITH_WESTEND_BRIDGE_PARAS_PALLET_NAME; +} + impl ChainWithGrandpa for Westend { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = bp_westend::WITH_WESTEND_GRANDPA_PALLET_NAME; @@ -75,3 +80,44 @@ impl ChainWithBalances for Westend { StorageKey(bp_westend::account_info_storage_key(account_id)) } } + +/// Westmint parachain definition +#[derive(Debug, Clone, Copy)] +pub struct Westmint; + +// Westmint seems to use the same configuration as all Polkadot-like chains, so we'll use Westend +// primitives here. +impl ChainBase for Westmint { + type BlockNumber = bp_westend::BlockNumber; + type Hash = bp_westend::Hash; + type Hasher = bp_westend::Hasher; + type Header = bp_westend::Header; + + type AccountId = bp_westend::AccountId; + type Balance = bp_westend::Balance; + type Index = bp_westend::Nonce; + type Signature = bp_westend::Signature; + + fn max_extrinsic_size() -> u32 { + bp_westend::Westend::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_westend::Westend::max_extrinsic_weight() + } +} + +// Westmint seems to use the same configuration as all Polkadot-like chains, so we'll use Westend +// primitives here. +impl Chain for Westmint { + const NAME: &'static str = "Westmint"; + const TOKEN_ID: Option<&'static str> = None; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_westend::BEST_FINALIZED_WESTMINT_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; + + type SignedBlock = bp_westend::SignedBlock; + type Call = bp_westend::Call; + type WeightToFee = bp_westend::WeightToFee; +} diff --git a/relays/client-wococo/Cargo.toml b/relays/client-wococo/Cargo.toml index 6845ac34c8..5b97694af1 100644 --- a/relays/client-wococo/Cargo.toml +++ b/relays/client-wococo/Cargo.toml @@ -6,24 +6,13 @@ edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } # Bridge dependencies -bridge-runtime-common = { path = "../../bin/runtime-common" } -bp-header-chain = { path = "../../primitives/header-chain" } -bp-message-dispatch = { path = "../../primitives/message-dispatch" } -bp-messages = { path = "../../primitives/messages" } -bp-polkadot-core = { path = "../../primitives/polkadot-core" } -bp-rococo = { path = "../../primitives/chain-rococo" } -bp-runtime = { path = "../../primitives/runtime" } + bp-wococo = { path = "../../primitives/chain-wococo" } -pallet-bridge-dispatch = { path = "../../modules/dispatch" } -pallet-bridge-messages = { path = "../../modules/messages" } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-wococo/src/lib.rs b/relays/client-wococo/src/lib.rs index 485ca1bd62..06a63e7d2b 100644 --- a/relays/client-wococo/src/lib.rs +++ b/relays/client-wococo/src/lib.rs @@ -16,19 +16,11 @@ //! Types used to connect to the Wococo-Substrate chain. -use bp_messages::MessageNonce; -use codec::Encode; use frame_support::weights::Weight; -use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, ChainWithGrandpa, ChainWithMessages, - Error as SubstrateError, SignParam, TransactionSignScheme, UnsignedTransaction, -}; -use sp_core::{storage::StorageKey, Pair}; -use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use relay_substrate_client::{Chain, ChainBase, ChainWithBalances, ChainWithGrandpa}; +use sp_core::storage::StorageKey; use std::time::Duration; -pub mod runtime; - /// Wococo header id. pub type HeaderId = relay_utils::HeaderId; @@ -66,10 +58,9 @@ impl Chain for Wococo { bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_wococo::SignedBlock; - type Call = crate::runtime::Call; + type Call = (); type WeightToFee = bp_wococo::WeightToFee; } @@ -77,75 +68,8 @@ impl ChainWithGrandpa for Wococo { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = bp_wococo::WITH_WOCOCO_GRANDPA_PALLET_NAME; } -impl ChainWithMessages for Wococo { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = - bp_wococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; - const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = - bp_wococo::TO_WOCOCO_MESSAGE_DETAILS_METHOD; - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = - bp_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; - const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = - bp_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = - bp_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - type WeightInfo = (); -} - impl ChainWithBalances for Wococo { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_wococo::account_info_storage_key(account_id)) } } - -impl TransactionSignScheme for Wococo { - type Chain = Wococo; - type AccountKeyPair = sp_core::sr25519::Pair; - type SignedTransaction = crate::runtime::UncheckedExtrinsic; - - fn sign_transaction(param: SignParam) -> Result { - let raw_payload = SignedPayload::new( - param.unsigned.call.clone(), - bp_wococo::SignedExtensions::new( - param.spec_version, - param.transaction_version, - param.era, - param.genesis_hash, - param.unsigned.nonce, - param.unsigned.tip, - ), - ) - .expect("SignedExtension never fails."); - - let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); - let signer: sp_runtime::MultiSigner = param.signer.public().into(); - let (call, extra, _) = raw_payload.deconstruct(); - - Ok(bp_wococo::UncheckedExtrinsic::new_signed( - call, - sp_runtime::MultiAddress::Id(signer.into_account()), - signature.into(), - extra, - )) - } - - fn is_signed(tx: &Self::SignedTransaction) -> bool { - tx.signature.is_some() - } - - fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { - tx.signature - .as_ref() - .map(|(address, _, _)| { - *address == bp_wococo::AccountId::from(*signer.public().as_array_ref()).into() - }) - .unwrap_or(false) - } - - fn parse_transaction(tx: Self::SignedTransaction) -> Option> { - let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { call: tx.function, nonce: extra.nonce(), tip: extra.tip() }) - } -} - -/// Wococo signing params. -pub type SigningParams = sp_core::sr25519::Pair; diff --git a/relays/client-wococo/src/runtime.rs b/relays/client-wococo/src/runtime.rs deleted file mode 100644 index b28e053086..0000000000 --- a/relays/client-wococo/src/runtime.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Types that are specific to the Wococo runtime. - -use bp_messages::{LaneId, UnrewardedRelayersState}; -use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike}; -use bp_runtime::Chain; -use codec::{Compact, Decode, Encode}; -use frame_support::weights::Weight; -use scale_info::TypeInfo; - -/// Unchecked Wococo extrinsic. -pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic; - -/// Rococo account ownership digest from Wococo. -/// -/// The byte vector returned by this function should be signed with a Rococo account private key. -/// This way, the owner of `wococo_account_id` on Rococo proves that the Rococo account private key -/// is also under his control. -pub fn wococo_to_rococo_account_ownership_digest( - rococo_call: &Call, - wococo_account_id: AccountId, - rococo_spec_version: SpecVersion, -) -> Vec -where - Call: codec::Encode, - AccountId: codec::Encode, - SpecVersion: codec::Encode, -{ - pallet_bridge_dispatch::account_ownership_digest( - rococo_call, - wococo_account_id, - rococo_spec_version, - bp_runtime::WOCOCO_CHAIN_ID, - bp_runtime::ROCOCO_CHAIN_ID, - ) -} - -/// Wococo Runtime `Call` enum. -/// -/// The enum represents a subset of possible `Call`s we can send to Rococo chain. -/// Ideally this code would be auto-generated from metadata, because we want to -/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s. -/// -/// All entries here (like pretty much in the entire file) must be kept in sync with Rococo -/// `construct_runtime`, so that we maintain SCALE-compatibility. -/// -/// See: [link](https://github.com/paritytech/polkadot/blob/master/runtime/rococo/src/lib.rs) -#[allow(clippy::large_enum_variant)] -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub enum Call { - /// System pallet. - #[codec(index = 0)] - System(SystemCall), - /// Balances pallet. - #[codec(index = 4)] - Balances(BalancesCall), - /// Rococo bridge pallet. - #[codec(index = 40)] - BridgeGrandpaRococo(BridgeGrandpaRococoCall), - /// Rococo messages pallet. - #[codec(index = 43)] - BridgeRococoMessages(BridgeRococoMessagesCall), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum SystemCall { - #[codec(index = 1)] - remark(Vec), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BalancesCall { - #[codec(index = 0)] - transfer(AccountAddress, Compact), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeGrandpaRococoCall { - #[codec(index = 0)] - submit_finality_proof( - Box<::Header>, - bp_header_chain::justification::GrandpaJustification<::Header>, - ), - #[codec(index = 1)] - initialize(bp_header_chain::InitializationData<::Header>), -} - -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeRococoMessagesCall { - #[codec(index = 3)] - send_message( - LaneId, - bp_message_dispatch::MessagePayload< - bp_rococo::AccountId, - bp_wococo::AccountId, - bp_wococo::AccountPublic, - Vec, - >, - bp_rococo::Balance, - ), - #[codec(index = 5)] - receive_messages_proof( - bp_rococo::AccountId, - bridge_runtime_common::messages::target::FromBridgedChainMessagesProof, - u32, - Weight, - ), - #[codec(index = 6)] - receive_messages_delivery_proof( - bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof< - bp_rococo::Hash, - >, - UnrewardedRelayersState, - ), -} - -impl sp_runtime::traits::Dispatchable for Call { - type Origin = (); - type Config = (); - type Info = (); - type PostInfo = (); - - fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { - unimplemented!("The Call is not expected to be dispatched.") - } -} diff --git a/relays/finality/Cargo.toml b/relays/finality/Cargo.toml index cc5ae54be3..ae4be5b552 100644 --- a/relays/finality/Cargo.toml +++ b/relays/finality/Cargo.toml @@ -8,11 +8,11 @@ description = "Finality proofs relay" [dependencies] async-std = "1.6.5" -async-trait = "0.1.40" +async-trait = "0.1" backoff = "0.2" bp-header-chain = { path = "../../primitives/header-chain" } futures = "0.3.5" -log = "0.4.11" +log = "0.4.17" num-traits = "0.2" relay-utils = { path = "../utils" } diff --git a/relays/finality/src/finality_loop_tests.rs b/relays/finality/src/finality_loop_tests.rs index 478d8e1be6..b7f7bc8002 100644 --- a/relays/finality/src/finality_loop_tests.rs +++ b/relays/finality/src/finality_loop_tests.rs @@ -70,7 +70,7 @@ impl FinalitySyncPipeline for TestFinalitySyncPipeline { type FinalityProof = TestFinalityProof; } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] struct TestSourceHeader(IsMandatory, TestNumber, TestHash); impl SourceHeader for TestSourceHeader { @@ -87,7 +87,7 @@ impl SourceHeader for TestSourceHeader { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] struct TestFinalityProof(TestNumber); impl FinalityProof for TestFinalityProof { @@ -127,7 +127,7 @@ impl SourceClient for TestSourceClient { async fn best_finalized_block_number(&self) -> Result { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); Ok(data.source_best_block_number) } @@ -136,13 +136,13 @@ impl SourceClient for TestSourceClient { number: TestNumber, ) -> Result<(TestSourceHeader, Option), TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); data.source_headers.get(&number).cloned().ok_or(TestError::NonConnection) } async fn finality_proofs(&self) -> Result { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); Ok(futures::stream::iter(data.source_proofs.clone()).boxed()) } } @@ -168,7 +168,7 @@ impl TargetClient for TestTargetClient { &self, ) -> Result, TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); Ok(data.target_best_block_id) } @@ -178,7 +178,7 @@ impl TargetClient for TestTargetClient { proof: TestFinalityProof, ) -> Result<(), TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); data.target_best_block_id = HeaderId(header.number(), header.hash()); data.target_headers.push((header, proof)); Ok(()) diff --git a/relays/lib-substrate-relay/Cargo.toml b/relays/lib-substrate-relay/Cargo.toml index e2cabf52f4..bdf49d42ea 100644 --- a/relays/lib-substrate-relay/Cargo.toml +++ b/relays/lib-substrate-relay/Cargo.toml @@ -9,25 +9,29 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" anyhow = "1.0" thiserror = "1.0.26" async-std = "1.9.0" -async-trait = "0.1.42" -codec = { package = "parity-scale-codec", version = "3.0.0" } +async-trait = "0.1" +codec = { package = "parity-scale-codec", version = "3.1.5" } futures = "0.3.12" num-traits = "0.2" -log = "0.4.14" +log = "0.4.17" # Bridge dependencies bp-header-chain = { path = "../../primitives/header-chain" } +bp-parachains = { path = "../../primitives/parachains" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } bridge-runtime-common = { path = "../../bin/runtime-common" } -finality-grandpa = { version = "0.15.0" } +finality-grandpa = { version = "0.16.0" } finality-relay = { path = "../finality" } +parachains-relay = { path = "../parachains" } relay-utils = { path = "../utils" } messages-relay = { path = "../messages" } relay-substrate-client = { path = "../client-substrate" } pallet-bridge-grandpa = { path = "../../modules/grandpa" } pallet-bridge-messages = { path = "../../modules/messages" } +pallet-bridge-parachains = { path = "../../modules/parachains" } bp-runtime = { path = "../../primitives/runtime" } bp-messages = { path = "../../primitives/messages" } @@ -47,6 +51,7 @@ bp-rialto = { path = "../../primitives/chain-rialto" } bp-rococo = { path = "../../primitives/chain-rococo" } bp-wococo = { path = "../../primitives/chain-wococo" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +relay-rialto-client = { path = "../client-rialto" } relay-rococo-client = { path = "../client-rococo" } relay-wococo-client = { path = "../client-wococo" } rialto-runtime = { path = "../../bin/rialto/runtime" } diff --git a/relays/lib-substrate-relay/src/conversion_rate_update.rs b/relays/lib-substrate-relay/src/conversion_rate_update.rs index 469bc55899..ed13f4e5b3 100644 --- a/relays/lib-substrate-relay/src/conversion_rate_update.rs +++ b/relays/lib-substrate-relay/src/conversion_rate_update.rs @@ -18,13 +18,12 @@ use crate::{messages_lane::SubstrateMessageLane, TransactionParams}; -use codec::Encode; use relay_substrate_client::{ transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, CallOf, Chain, Client, SignParam, TransactionEra, TransactionSignScheme, UnsignedTransaction, }; use relay_utils::metrics::F64SharedRef; -use sp_core::{Bytes, Pair}; +use sp_core::Pair; use std::time::{Duration, Instant}; /// Duration between updater iterations. @@ -272,19 +271,19 @@ where updated_rate, )?; client - .submit_signed_extrinsic(signer_id, move |best_block_id, transaction_nonce| { - Ok(Bytes( - Sign::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: transaction_params.signer, - era: TransactionEra::new(best_block_id, transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce).into(), - })? - .encode(), - )) - }) + .submit_signed_extrinsic( + signer_id, + SignParam:: { + spec_version, + transaction_version, + genesis_hash, + signer: transaction_params.signer, + }, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) .await .map(drop) .map_err(|err| anyhow::format_err!("{:?}", err)) diff --git a/relays/lib-substrate-relay/src/error.rs b/relays/lib-substrate-relay/src/error.rs index 9402d55e37..b41870a181 100644 --- a/relays/lib-substrate-relay/src/error.rs +++ b/relays/lib-substrate-relay/src/error.rs @@ -53,9 +53,11 @@ pub enum Error { #[error("Failed to decode {0} GRANDPA authorities set at header {1}: {2:?}")] DecodeAuthorities(&'static str, Hash, codec::Error), /// Failed to retrieve header by the hash from the source chain. - #[error("Failed to retrieve {0} header with hash {1}: {:?}")] + #[error("Failed to retrieve {0} header with hash {1}: {2:?}")] RetrieveHeader(&'static str, Hash, client::Error), - /// Failed to retrieve best finalized source header hash from the target chain. - #[error("Failed to retrieve best finalized {0} header from the target chain: {1}")] - RetrieveBestFinalizedHeaderHash(&'static str, client::Error), + /// Failed to submit signed extrinsic from to the target chain. + #[error( + "Failed to retrieve `is_initialized` flag of the with-{0} finality pallet at {1}: {2:?}" + )] + IsInitializedRetrieve(&'static str, &'static str, client::Error), } diff --git a/relays/lib-substrate-relay/src/finality/engine.rs b/relays/lib-substrate-relay/src/finality/engine.rs new file mode 100644 index 0000000000..b2b72e4f2c --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/engine.rs @@ -0,0 +1,251 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Support of different finality engines, available in Substrate. + +use crate::error::Error; +use async_trait::async_trait; +use bp_header_chain::{ + find_grandpa_authorities_scheduled_change, + justification::{verify_justification, GrandpaJustification}, + FinalityProof, +}; +use bp_runtime::{BasicOperatingMode, OperatingMode}; +use codec::{Decode, Encode}; +use finality_grandpa::voter_set::VoterSet; +use num_traits::{One, Zero}; +use relay_substrate_client::{ + BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf, HeaderOf, + Subscription, +}; +use sp_core::{storage::StorageKey, Bytes}; +use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet; +use sp_runtime::{traits::Header, ConsensusEngineId}; +use std::marker::PhantomData; + +/// Finality enfine, used by the Substrate chain. +#[async_trait] +pub trait Engine: Send { + /// Unique consensus engine identifier. + const ID: ConsensusEngineId; + /// Type of finality proofs, used by consensus engine. + type FinalityProof: FinalityProof> + Decode + Encode; + /// Type of bridge pallet initialization data. + type InitializationData: std::fmt::Debug + Send + Sync + 'static; + /// Type of bridge pallet operating mode. + type OperatingMode: OperatingMode + 'static; + + /// Returns storage key at the bridged (target) chain that corresponds to the variable + /// that holds the operating mode of the pallet. + fn pallet_operating_mode_key() -> StorageKey; + /// Returns storage at the bridged (target) chain that corresponds to some value that is + /// missing from the storage until bridge pallet is initialized. + /// + /// Note that we don't care about type of the value - just if it present or not. + fn is_initialized_key() -> StorageKey; + /// A method to subscribe to encoded finality proofs, given source client. + async fn finality_proofs(client: Client) -> Result, SubstrateError>; + /// Prepare initialization data for the finality bridge pallet. + async fn prepare_initialization_data( + client: Client, + ) -> Result, BlockNumberOf>>; + + /// Returns `Ok(true)` if finality pallet at the bridged chain has already been initialized. + async fn is_initialized( + target_client: &Client, + ) -> Result { + Ok(target_client + .raw_storage_value(Self::is_initialized_key(), None) + .await? + .is_some()) + } + + /// Returns `Ok(true)` if finality pallet at the bridged chain is halted. + async fn is_halted( + target_client: &Client, + ) -> Result { + Ok(target_client + .storage_value::(Self::pallet_operating_mode_key(), None) + .await? + .map(|operating_mode| operating_mode.is_halted()) + .unwrap_or(false)) + } +} + +/// GRANDPA finality engine. +pub struct Grandpa(PhantomData); + +impl Grandpa { + /// Read header by hash from the source client. + async fn source_header( + source_client: &Client, + header_hash: C::Hash, + ) -> Result, BlockNumberOf>> { + source_client + .header_by_hash(header_hash) + .await + .map_err(|err| Error::RetrieveHeader(C::NAME, header_hash, err)) + } + + /// Read GRANDPA authorities set at given header. + async fn source_authorities_set( + source_client: &Client, + header_hash: C::Hash, + ) -> Result, BlockNumberOf>> { + let raw_authorities_set = source_client + .grandpa_authorities_set(header_hash) + .await + .map_err(|err| Error::RetrieveAuthorities(C::NAME, header_hash, err))?; + GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..]) + .map_err(|err| Error::DecodeAuthorities(C::NAME, header_hash, err)) + } +} + +#[async_trait] +impl Engine for Grandpa { + const ID: ConsensusEngineId = sp_finality_grandpa::GRANDPA_ENGINE_ID; + type FinalityProof = GrandpaJustification>; + type InitializationData = bp_header_chain::InitializationData; + type OperatingMode = BasicOperatingMode; + + fn pallet_operating_mode_key() -> StorageKey { + bp_header_chain::storage_keys::pallet_operating_mode_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) + } + + fn is_initialized_key() -> StorageKey { + bp_header_chain::storage_keys::best_finalized_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) + } + + async fn finality_proofs(client: Client) -> Result, SubstrateError> { + client.subscribe_grandpa_justifications().await + } + + /// Prepare initialization data for the GRANDPA verifier pallet. + async fn prepare_initialization_data( + source_client: Client, + ) -> Result, BlockNumberOf>> { + // In ideal world we just need to get best finalized header and then to read GRANDPA + // authorities set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at + // this header. + // + // But now there are problems with this approach - `CurrentSetId` may return invalid value. + // So here we're waiting for the next justification, read the authorities set and then try + // to figure out the set id with bruteforce. + let justifications = source_client + .subscribe_grandpa_justifications() + .await + .map_err(|err| Error::Subscribe(C::NAME, err))?; + // Read next justification - the header that it finalizes will be used as initial header. + let justification = justifications + .next() + .await + .map_err(|e| Error::ReadJustification(C::NAME, e)) + .and_then(|justification| { + justification.ok_or(Error::ReadJustificationStreamEnded(C::NAME)) + })?; + + // Read initial header. + let justification: GrandpaJustification = + Decode::decode(&mut &justification.0[..]) + .map_err(|err| Error::DecodeJustification(C::NAME, err))?; + + let (initial_header_hash, initial_header_number) = + (justification.commit.target_hash, justification.commit.target_number); + + let initial_header = Self::source_header(&source_client, initial_header_hash).await?; + log::trace!(target: "bridge", "Selected {} initial header: {}/{}", + C::NAME, + initial_header_number, + initial_header_hash, + ); + + // Read GRANDPA authorities set at initial header. + let initial_authorities_set = + Self::source_authorities_set(&source_client, initial_header_hash).await?; + log::trace!(target: "bridge", "Selected {} initial authorities set: {:?}", + C::NAME, + initial_authorities_set, + ); + + // If initial header changes the GRANDPA authorities set, then we need previous authorities + // to verify justification. + let mut authorities_for_verification = initial_authorities_set.clone(); + let scheduled_change = find_grandpa_authorities_scheduled_change(&initial_header); + assert!( + scheduled_change.as_ref().map(|c| c.delay.is_zero()).unwrap_or(true), + "GRANDPA authorities change at {} scheduled to happen in {:?} blocks. We expect\ + regular hange to have zero delay", + initial_header_hash, + scheduled_change.as_ref().map(|c| c.delay), + ); + let schedules_change = scheduled_change.is_some(); + if schedules_change { + authorities_for_verification = + Self::source_authorities_set(&source_client, *initial_header.parent_hash()).await?; + log::trace!( + target: "bridge", + "Selected {} header is scheduling GRANDPA authorities set changes. Using previous set: {:?}", + C::NAME, + authorities_for_verification, + ); + } + + // Now let's try to guess authorities set id by verifying justification. + let mut initial_authorities_set_id = 0; + let mut min_possible_block_number = C::BlockNumber::zero(); + let authorities_for_verification = VoterSet::new(authorities_for_verification.clone()) + .ok_or(Error::ReadInvalidAuthorities(C::NAME, authorities_for_verification))?; + loop { + log::trace!( + target: "bridge", "Trying {} GRANDPA authorities set id: {}", + C::NAME, + initial_authorities_set_id, + ); + + let is_valid_set_id = verify_justification::( + (initial_header_hash, initial_header_number), + initial_authorities_set_id, + &authorities_for_verification, + &justification, + ) + .is_ok(); + + if is_valid_set_id { + break + } + + initial_authorities_set_id += 1; + min_possible_block_number += One::one(); + if min_possible_block_number > initial_header_number { + // there can't be more authorities set changes than headers => if we have reached + // `initial_block_number` and still have not found correct value of + // `initial_authorities_set_id`, then something else is broken => fail + return Err(Error::GuessInitialAuthorities(C::NAME, initial_header_number)) + } + } + + Ok(bp_header_chain::InitializationData { + header: Box::new(initial_header), + authority_list: initial_authorities_set, + set_id: if schedules_change { + initial_authorities_set_id + 1 + } else { + initial_authorities_set_id + }, + operating_mode: BasicOperatingMode::Normal, + }) + } +} diff --git a/relays/lib-substrate-relay/src/finality_guards.rs b/relays/lib-substrate-relay/src/finality/guards.rs similarity index 100% rename from relays/lib-substrate-relay/src/finality_guards.rs rename to relays/lib-substrate-relay/src/finality/guards.rs diff --git a/relays/lib-substrate-relay/src/finality/initialize.rs b/relays/lib-substrate-relay/src/finality/initialize.rs new file mode 100644 index 0000000000..e25743180e --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/initialize.rs @@ -0,0 +1,137 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Initialize Substrate -> Substrate finality bridge. +//! +//! Initialization is a transaction that calls `initialize()` function of the +//! finality pallet (GRANDPA/BEEFY/...). This transaction brings initial header +//! and authorities set from source to target chain. The finality sync starts +//! with this header. + +use crate::{error::Error, finality::engine::Engine}; + +use relay_substrate_client::{ + Chain, Client, Error as SubstrateError, SignParam, TransactionSignScheme, UnsignedTransaction, +}; +use sp_runtime::traits::Header as HeaderT; + +/// Submit headers-bridge initialization transaction. +pub async fn initialize< + E: Engine, + SourceChain: Chain, + TargetChain: Chain + TransactionSignScheme, + F, +>( + source_client: Client, + target_client: Client, + target_transactions_signer: TargetChain::AccountId, + target_signing_data: SignParam, + prepare_initialize_transaction: F, +) where + F: FnOnce( + TargetChain::Index, + E::InitializationData, + ) -> Result, SubstrateError> + + Send + + 'static, +{ + let result = do_initialize::( + source_client, + target_client, + target_transactions_signer, + target_signing_data, + prepare_initialize_transaction, + ) + .await; + + match result { + Ok(Some(tx_hash)) => log::info!( + target: "bridge", + "Successfully submitted {}-headers bridge initialization transaction to {}: {:?}", + SourceChain::NAME, + TargetChain::NAME, + tx_hash, + ), + Ok(None) => (), + Err(err) => log::error!( + target: "bridge", + "Failed to submit {}-headers bridge initialization transaction to {}: {:?}", + SourceChain::NAME, + TargetChain::NAME, + err, + ), + } +} + +/// Craft and submit initialization transaction, returning any error that may occur. +async fn do_initialize< + E: Engine, + SourceChain: Chain, + TargetChain: Chain + TransactionSignScheme, + F, +>( + source_client: Client, + target_client: Client, + target_transactions_signer: TargetChain::AccountId, + target_signing_data: SignParam, + prepare_initialize_transaction: F, +) -> Result< + Option, + Error::Number>, +> +where + F: FnOnce( + TargetChain::Index, + E::InitializationData, + ) -> Result, SubstrateError> + + Send + + 'static, +{ + let is_initialized = E::is_initialized(&target_client) + .await + .map_err(|e| Error::IsInitializedRetrieve(SourceChain::NAME, TargetChain::NAME, e))?; + if is_initialized { + log::info!( + target: "bridge", + "{}-headers bridge at {} is already initialized. Skipping", + SourceChain::NAME, + TargetChain::NAME, + ); + return Ok(None) + } + + let initialization_data = E::prepare_initialization_data(source_client).await?; + log::info!( + target: "bridge", + "Prepared initialization data for {}-headers bridge at {}: {:?}", + SourceChain::NAME, + TargetChain::NAME, + initialization_data, + ); + + let initialization_tx_hash = target_client + .submit_signed_extrinsic( + target_transactions_signer, + target_signing_data, + move |_, transaction_nonce| { + prepare_initialize_transaction(transaction_nonce, initialization_data) + }, + ) + .await + .map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))?; + + Ok(Some(initialization_tx_hash)) +} diff --git a/relays/lib-substrate-relay/src/finality_pipeline.rs b/relays/lib-substrate-relay/src/finality/mod.rs similarity index 85% rename from relays/lib-substrate-relay/src/finality_pipeline.rs rename to relays/lib-substrate-relay/src/finality/mod.rs index 3daf8d1144..3144a1016e 100644 --- a/relays/lib-substrate-relay/src/finality_pipeline.rs +++ b/relays/lib-substrate-relay/src/finality/mod.rs @@ -18,7 +18,11 @@ //! finality proofs synchronization pipelines. use crate::{ - finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget, + finality::{ + engine::Engine, + source::{SubstrateFinalityProof, SubstrateFinalitySource}, + target::SubstrateFinalityTarget, + }, TransactionParams, }; @@ -27,13 +31,19 @@ use bp_header_chain::justification::GrandpaJustification; use finality_relay::FinalitySyncPipeline; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ - transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, - ChainWithGrandpa, Client, HashOf, HeaderOf, SyncHeader, TransactionSignScheme, + transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, + HashOf, HeaderOf, SyncHeader, TransactionSignScheme, }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; use std::{fmt::Debug, marker::PhantomData}; +pub mod engine; +pub mod guards; +pub mod initialize; +pub mod source; +pub mod target; + /// Default limit of recent finality proofs. /// /// Finality delay of 4096 blocks is unlikely to happen in practice in @@ -44,10 +54,12 @@ pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; #[async_trait] pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { /// Headers of this chain are submitted to the `TargetChain`. - type SourceChain: ChainWithGrandpa; + type SourceChain: Chain; /// Headers of the `SourceChain` are submitted to this chain. type TargetChain: Chain; + /// Finality engine. + type FinalityEngine: Engine; /// How submit finality proof call is built? type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder; /// Scheme used to sign target chain transactions. @@ -76,7 +88,7 @@ impl FinalitySyncPipeline for FinalitySyncPipe type Hash = HashOf; type Number = BlockNumberOf; type Header = relay_substrate_client::SyncHeader>; - type FinalityProof = GrandpaJustification>; + type FinalityProof = SubstrateFinalityProof

; } /// Different ways of building `submit_finality_proof` calls. @@ -85,23 +97,26 @@ pub trait SubmitFinalityProofCallBuilder { /// function of bridge GRANDPA module at the target chain. fn build_submit_finality_proof_call( header: SyncHeader>, - proof: GrandpaJustification>, + proof: SubstrateFinalityProof

, ) -> CallOf; } /// Building `submit_finality_proof` call when you have direct access to the target /// chain runtime. -pub struct DirectSubmitFinalityProofCallBuilder { +pub struct DirectSubmitGrandpaFinalityProofCallBuilder { _phantom: PhantomData<(P, R, I)>, } -impl SubmitFinalityProofCallBuilder

for DirectSubmitFinalityProofCallBuilder +impl SubmitFinalityProofCallBuilder

+ for DirectSubmitGrandpaFinalityProofCallBuilder where P: SubstrateFinalitySyncPipeline, R: BridgeGrandpaConfig, I: 'static, R::BridgedChain: bp_runtime::Chain

>, CallOf: From>, + P::FinalityEngine: + Engine>>, { fn build_submit_finality_proof_call( header: SyncHeader>, @@ -125,22 +140,22 @@ macro_rules! generate_mocked_submit_finality_proof_call_builder { ($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => { pub struct $mocked_builder; - impl $crate::finality_pipeline::SubmitFinalityProofCallBuilder<$pipeline> + impl $crate::finality::SubmitFinalityProofCallBuilder<$pipeline> for $mocked_builder { fn build_submit_finality_proof_call( header: relay_substrate_client::SyncHeader< relay_substrate_client::HeaderOf< - <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain + <$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::SourceChain > >, proof: bp_header_chain::justification::GrandpaJustification< relay_substrate_client::HeaderOf< - <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain + <$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::SourceChain > >, ) -> relay_substrate_client::CallOf< - <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::TargetChain + <$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::TargetChain > { $bridge_grandpa($submit_finality_proof(Box::new(header.into_inner()), proof)) } @@ -179,7 +194,7 @@ where stall_timeout: transaction_stall_timeout( transaction_params.mortality, P::TargetChain::AVERAGE_BLOCK_INTERVAL, - crate::STALL_TIMEOUT, + relay_utils::STALL_TIMEOUT, ), only_mandatory_headers, }, diff --git a/relays/lib-substrate-relay/src/finality_source.rs b/relays/lib-substrate-relay/src/finality/source.rs similarity index 86% rename from relays/lib-substrate-relay/src/finality_source.rs rename to relays/lib-substrate-relay/src/finality/source.rs index 804d321293..c8360bbddb 100644 --- a/relays/lib-substrate-relay/src/finality_source.rs +++ b/relays/lib-substrate-relay/src/finality/source.rs @@ -16,11 +16,10 @@ //! Default generic implementation of finality source for basic Substrate client. -use crate::finality_pipeline::{FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline}; +use crate::finality::{engine::Engine, FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline}; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; -use bp_header_chain::justification::GrandpaJustification; use codec::Decode; use finality_relay::SourceClient; use futures::stream::{unfold, Stream, StreamExt}; @@ -28,7 +27,6 @@ use relay_substrate_client::{ BlockNumberOf, BlockWithJustification, Chain, Client, Error, HeaderOf, }; use relay_utils::relay_loop::Client as RelayClient; -use sp_runtime::traits::Header as HeaderT; use std::pin::Pin; /// Shared updatable reference to the maximal header number that we want to sync from the source. @@ -38,13 +36,19 @@ pub type RequiredHeaderNumberRef = Arc::BlockN pub type SubstrateFinalityProofsStream

= Pin< Box< dyn Stream< - Item = GrandpaJustification< - HeaderOf<

::SourceChain>, - >, + Item = <

::FinalityEngine as Engine< +

::SourceChain, + >>::FinalityProof, > + Send, >, >; +/// Substrate finality proof. Specific to the used `FinalityEngine`. +pub type SubstrateFinalityProof

= + <

::FinalityEngine as Engine< +

::SourceChain, + >>::FinalityProof; + /// Substrate node as finality source. pub struct SubstrateFinalitySource { client: Client, @@ -71,9 +75,7 @@ impl SubstrateFinalitySource

{ ) -> Result, Error> { // we **CAN** continue to relay finality proofs if source node is out of sync, because // target node may be missing proofs that are already available at the source - let finalized_header_hash = self.client.best_finalized_header_hash().await?; - let finalized_header = self.client.header_by_hash(finalized_header_hash).await?; - Ok(*finalized_header.number()) + self.client.best_finalized_header_number().await } } @@ -120,7 +122,7 @@ impl SourceClient Result< ( relay_substrate_client::SyncHeader>, - Option>>, + Option>, ), Error, > { @@ -130,9 +132,7 @@ impl SourceClient>::decode( - &mut raw_justification.as_slice(), - ) + SubstrateFinalityProof::

::decode(&mut raw_justification.as_slice()) }) .transpose() .map_err(Error::ResponseParseFailed)?; @@ -142,7 +142,7 @@ impl SourceClient Result { Ok(unfold( - self.client.clone().subscribe_justifications().await?, + P::FinalityEngine::finality_proofs(self.client.clone()).await?, move |subscription| async move { loop { let log_error = |err| { @@ -161,7 +161,7 @@ impl SourceClient>::decode( + >::FinalityProof::decode( &mut &next_justification[..], ); diff --git a/relays/lib-substrate-relay/src/finality_target.rs b/relays/lib-substrate-relay/src/finality/target.rs similarity index 70% rename from relays/lib-substrate-relay/src/finality_target.rs rename to relays/lib-substrate-relay/src/finality/target.rs index 4c58141710..351f21cec8 100644 --- a/relays/lib-substrate-relay/src/finality_target.rs +++ b/relays/lib-substrate-relay/src/finality/target.rs @@ -14,27 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Substrate client as Substrate finality proof target. The chain we connect to should have -//! bridge GRANDPA pallet deployed and provide `FinalityApi` to allow bridging -//! with chain. +//! Substrate client as Substrate finality proof target. use crate::{ - finality_pipeline::{ - FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, + finality::{ + engine::Engine, source::SubstrateFinalityProof, FinalitySyncPipelineAdapter, + SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }, TransactionParams, }; use async_trait::async_trait; -use bp_header_chain::{justification::GrandpaJustification, storage_keys::is_halted_key}; -use codec::Encode; use finality_relay::TargetClient; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, Chain, ChainWithGrandpa, Client, Error, HeaderIdOf, HeaderOf, - SignParam, SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, + AccountIdOf, AccountKeyPairOf, Chain, Client, Error, HeaderIdOf, HeaderOf, SignParam, + SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, }; use relay_utils::relay_loop::Client as RelayClient; -use sp_core::{Bytes, Pair}; +use sp_core::Pair; /// Substrate client as Substrate finality target. pub struct SubstrateFinalityTarget { @@ -51,17 +48,19 @@ impl SubstrateFinalityTarget

{ SubstrateFinalityTarget { client, transaction_params } } - /// Ensure that the GRANDPA pallet at target chain is active. + /// Ensure that the bridge pallet at target chain is active. pub async fn ensure_pallet_active(&self) -> Result<(), Error> { - let is_halted = self - .client - .storage_value(is_halted_key(P::SourceChain::WITH_CHAIN_GRANDPA_PALLET_NAME), None) - .await?; - if is_halted.unwrap_or(false) { - Err(Error::BridgePalletIsHalted) - } else { - Ok(()) + let is_halted = P::FinalityEngine::is_halted(&self.client).await?; + if is_halted { + return Err(Error::BridgePalletIsHalted) } + + let is_initialized = P::FinalityEngine::is_initialized(&self.client).await?; + if !is_initialized { + return Err(Error::BridgePalletIsNotInitialized) + } + + Ok(()) } } @@ -94,7 +93,7 @@ where // we can't continue to relay finality if target node is out of sync, because // it may have already received (some of) headers that we're going to relay self.client.ensure_synced().await?; - // we can't relay finality if GRANDPA pallet at target chain is halted + // we can't relay finality if bridge pallet at target chain is halted self.ensure_pallet_active().await?; Ok(crate::messages_source::read_client_state::( @@ -109,7 +108,7 @@ where async fn submit_finality_proof( &self, header: SyncHeader>, - proof: GrandpaJustification>, + proof: SubstrateFinalityProof

, ) -> Result<(), Error> { let genesis_hash = *self.client.genesis_hash(); let transaction_params = self.transaction_params.clone(); @@ -119,18 +118,15 @@ where self.client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash, + signer: transaction_params.signer.clone(), + }, move |best_block_id, transaction_nonce| { - Ok(Bytes( - P::TransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: transaction_params.signer.clone(), - era: TransactionEra::new(best_block_id, transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) }, ) .await diff --git a/relays/lib-substrate-relay/src/headers_initialize.rs b/relays/lib-substrate-relay/src/headers_initialize.rs deleted file mode 100644 index 0e1371c53c..0000000000 --- a/relays/lib-substrate-relay/src/headers_initialize.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common 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. - -// Parity Bridges Common 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 Parity Bridges Common. If not, see . - -//! Initialize Substrate -> Substrate headers bridge. -//! -//! Initialization is a transaction that calls `initialize()` function of the -//! `pallet-bridge-grandpa` pallet. This transaction brings initial header -//! and authorities set from source to target chain. The headers sync starts -//! with this header. - -use crate::error::Error; - -use bp_header_chain::{ - find_grandpa_authorities_scheduled_change, - justification::{verify_justification, GrandpaJustification}, - InitializationData, -}; -use codec::Decode; -use finality_grandpa::voter_set::VoterSet; -use num_traits::{One, Zero}; -use relay_substrate_client::{ - BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf, -}; -use sp_core::Bytes; -use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet; -use sp_runtime::traits::Header as HeaderT; - -/// Submit headers-bridge initialization transaction. -pub async fn initialize( - source_client: Client, - target_client: Client, - target_transactions_signer: TargetChain::AccountId, - prepare_initialize_transaction: impl FnOnce( - TargetChain::Index, - InitializationData, - ) -> Result - + Send - + 'static, -) { - let result = do_initialize( - source_client, - target_client, - target_transactions_signer, - prepare_initialize_transaction, - ) - .await; - - match result { - Ok(Some(tx_hash)) => log::info!( - target: "bridge", - "Successfully submitted {}-headers bridge initialization transaction to {}: {:?}", - SourceChain::NAME, - TargetChain::NAME, - tx_hash, - ), - Ok(None) => (), - Err(err) => log::error!( - target: "bridge", - "Failed to submit {}-headers bridge initialization transaction to {}: {:?}", - SourceChain::NAME, - TargetChain::NAME, - err, - ), - } -} - -/// Craft and submit initialization transaction, returning any error that may occur. -async fn do_initialize( - source_client: Client, - target_client: Client, - target_transactions_signer: TargetChain::AccountId, - prepare_initialize_transaction: impl FnOnce( - TargetChain::Index, - InitializationData, - ) -> Result - + Send - + 'static, -) -> Result< - Option, - Error::Number>, -> { - let is_initialized = is_initialized::(&target_client).await?; - if is_initialized { - log::info!( - target: "bridge", - "{}-headers bridge at {} is already initialized. Skipping", - SourceChain::NAME, - TargetChain::NAME, - ); - return Ok(None) - } - - let initialization_data = prepare_initialization_data(source_client).await?; - log::info!( - target: "bridge", - "Prepared initialization data for {}-headers bridge at {}: {:?}", - SourceChain::NAME, - TargetChain::NAME, - initialization_data, - ); - - let initialization_tx_hash = target_client - .submit_signed_extrinsic(target_transactions_signer, move |_, transaction_nonce| { - prepare_initialize_transaction(transaction_nonce, initialization_data) - }) - .await - .map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))?; - Ok(Some(initialization_tx_hash)) -} - -/// Returns `Ok(true)` if bridge has already been initialized. -async fn is_initialized( - target_client: &Client, -) -> Result, BlockNumberOf>> { - Ok(target_client - .raw_storage_value( - bp_header_chain::storage_keys::best_finalized_hash_key( - SourceChain::WITH_CHAIN_GRANDPA_PALLET_NAME, - ), - None, - ) - .await - .map_err(|err| Error::RetrieveBestFinalizedHeaderHash(SourceChain::NAME, err))? - .is_some()) -} - -/// Prepare initialization data for the GRANDPA verifier pallet. -async fn prepare_initialization_data( - source_client: Client, -) -> Result< - InitializationData, - Error::Number>, -> { - // In ideal world we just need to get best finalized header and then to read GRANDPA authorities - // set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at this header. - // - // But now there are problems with this approach - `CurrentSetId` may return invalid value. So - // here we're waiting for the next justification, read the authorities set and then try to - // figure out the set id with bruteforce. - let justifications = source_client - .subscribe_justifications() - .await - .map_err(|err| Error::Subscribe(SourceChain::NAME, err))?; - // Read next justification - the header that it finalizes will be used as initial header. - let justification = justifications - .next() - .await - .map_err(|e| Error::ReadJustification(SourceChain::NAME, e)) - .and_then(|justification| { - justification.ok_or(Error::ReadJustificationStreamEnded(SourceChain::NAME)) - })?; - - // Read initial header. - let justification: GrandpaJustification = - Decode::decode(&mut &justification.0[..]) - .map_err(|err| Error::DecodeJustification(SourceChain::NAME, err))?; - - let (initial_header_hash, initial_header_number) = - (justification.commit.target_hash, justification.commit.target_number); - - let initial_header = source_header(&source_client, initial_header_hash).await?; - log::trace!(target: "bridge", "Selected {} initial header: {}/{}", - SourceChain::NAME, - initial_header_number, - initial_header_hash, - ); - - // Read GRANDPA authorities set at initial header. - let initial_authorities_set = - source_authorities_set(&source_client, initial_header_hash).await?; - log::trace!(target: "bridge", "Selected {} initial authorities set: {:?}", - SourceChain::NAME, - initial_authorities_set, - ); - - // If initial header changes the GRANDPA authorities set, then we need previous authorities - // to verify justification. - let mut authorities_for_verification = initial_authorities_set.clone(); - let scheduled_change = find_grandpa_authorities_scheduled_change(&initial_header); - assert!( - scheduled_change.as_ref().map(|c| c.delay.is_zero()).unwrap_or(true), - "GRANDPA authorities change at {} scheduled to happen in {:?} blocks. We expect\ - regular hange to have zero delay", - initial_header_hash, - scheduled_change.as_ref().map(|c| c.delay), - ); - let schedules_change = scheduled_change.is_some(); - if schedules_change { - authorities_for_verification = - source_authorities_set(&source_client, *initial_header.parent_hash()).await?; - log::trace!( - target: "bridge", - "Selected {} header is scheduling GRANDPA authorities set changes. Using previous set: {:?}", - SourceChain::NAME, - authorities_for_verification, - ); - } - - // Now let's try to guess authorities set id by verifying justification. - let mut initial_authorities_set_id = 0; - let mut min_possible_block_number = SourceChain::BlockNumber::zero(); - let authorities_for_verification = VoterSet::new(authorities_for_verification.clone()) - .ok_or(Error::ReadInvalidAuthorities(SourceChain::NAME, authorities_for_verification))?; - loop { - log::trace!( - target: "bridge", "Trying {} GRANDPA authorities set id: {}", - SourceChain::NAME, - initial_authorities_set_id, - ); - - let is_valid_set_id = verify_justification::( - (initial_header_hash, initial_header_number), - initial_authorities_set_id, - &authorities_for_verification, - &justification, - ) - .is_ok(); - - if is_valid_set_id { - break - } - - initial_authorities_set_id += 1; - min_possible_block_number += One::one(); - if min_possible_block_number > initial_header_number { - // there can't be more authorities set changes than headers => if we have reached - // `initial_block_number` and still have not found correct value of - // `initial_authorities_set_id`, then something else is broken => fail - return Err(Error::GuessInitialAuthorities(SourceChain::NAME, initial_header_number)) - } - } - - Ok(InitializationData { - header: Box::new(initial_header), - authority_list: initial_authorities_set, - set_id: if schedules_change { - initial_authorities_set_id + 1 - } else { - initial_authorities_set_id - }, - is_halted: false, - }) -} - -/// Read header by hash from the source client. -async fn source_header( - source_client: &Client, - header_hash: SourceChain::Hash, -) -> Result::Number>> -{ - source_client - .header_by_hash(header_hash) - .await - .map_err(|err| Error::RetrieveHeader(SourceChain::NAME, header_hash, err)) -} - -/// Read GRANDPA authorities set at given header. -async fn source_authorities_set( - source_client: &Client, - header_hash: SourceChain::Hash, -) -> Result::Number>> -{ - let raw_authorities_set = source_client - .grandpa_authorities_set(header_hash) - .await - .map_err(|err| Error::RetrieveAuthorities(SourceChain::NAME, header_hash, err))?; - GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..]) - .map_err(|err| Error::DecodeAuthorities(SourceChain::NAME, header_hash, err)) -} diff --git a/relays/lib-substrate-relay/src/lib.rs b/relays/lib-substrate-relay/src/lib.rs index 27d91147c2..f4f1aae9d2 100644 --- a/relays/lib-substrate-relay/src/lib.rs +++ b/relays/lib-substrate-relay/src/lib.rs @@ -18,30 +18,16 @@ #![warn(missing_docs)] -use std::time::Duration; - pub mod conversion_rate_update; pub mod error; -pub mod finality_guards; -pub mod finality_pipeline; -pub mod finality_source; -pub mod finality_target; -pub mod headers_initialize; +pub mod finality; pub mod helpers; pub mod messages_lane; pub mod messages_metrics; pub mod messages_source; pub mod messages_target; -pub mod on_demand_headers; - -/// Default relay loop stall timeout. If transactions generated by relay are immortal, then -/// this timeout is used. -/// -/// There are no any strict requirements on block time in Substrate. But we assume here that all -/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest -/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine -/// transaction, or remove it from the pool. -pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); +pub mod on_demand; +pub mod parachains; /// Transaction creation parameters. #[derive(Clone, Debug)] @@ -51,3 +37,64 @@ pub struct TransactionParams { /// Transactions mortality. pub mortality: Option, } + +/// Tagged relay account, which balance may be exposed as metrics by the relay. +#[derive(Clone, Debug)] +pub enum TaggedAccount { + /// Account, used to sign headers relay transactions from given bridged chain. + Headers { + /// Account id. + id: AccountId, + /// Name of the bridged chain, which headers are relayed. + bridged_chain: String, + }, + /// Account, used to sign parachains relay transactions from given bridged relay chain. + Parachains { + /// Account id. + id: AccountId, + /// Name of the bridged relay chain with parachain heads. + bridged_chain: String, + }, + /// Account, used to sign message relay transactions from given bridged chain. + Messages { + /// Account id. + id: AccountId, + /// Name of the bridged chain, which sends us messages or delivery confirmations. + bridged_chain: String, + }, + /// Account, used to sign messages with-bridged-chain pallet parameters update transactions. + MessagesPalletOwner { + /// Account id. + id: AccountId, + /// Name of the chain, bridged using messages pallet at our chain. + bridged_chain: String, + }, +} + +impl TaggedAccount { + /// Returns reference to the account id. + pub fn id(&self) -> &AccountId { + match *self { + TaggedAccount::Headers { ref id, .. } => id, + TaggedAccount::Parachains { ref id, .. } => id, + TaggedAccount::Messages { ref id, .. } => id, + TaggedAccount::MessagesPalletOwner { ref id, .. } => id, + } + } + + /// Returns stringified account tag. + pub fn tag(&self) -> String { + match *self { + TaggedAccount::Headers { ref bridged_chain, .. } => format!("{}Headers", bridged_chain), + TaggedAccount::Parachains { ref bridged_chain, .. } => { + format!("{}Parachains", bridged_chain) + }, + TaggedAccount::Messages { ref bridged_chain, .. } => { + format!("{}Messages", bridged_chain) + }, + TaggedAccount::MessagesPalletOwner { ref bridged_chain, .. } => { + format!("{}MessagesPalletOwner", bridged_chain) + }, + } + } +} diff --git a/relays/lib-substrate-relay/src/messages_lane.rs b/relays/lib-substrate-relay/src/messages_lane.rs index fadf5e6224..f69ebc347d 100644 --- a/relays/lib-substrate-relay/src/messages_lane.rs +++ b/relays/lib-substrate-relay/src/messages_lane.rs @@ -21,10 +21,11 @@ use crate::{ messages_metrics::StandaloneMessagesMetrics, messages_source::{SubstrateMessagesProof, SubstrateMessagesSource}, messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget}, - on_demand_headers::OnDemandHeadersRelay, - TransactionParams, STALL_TIMEOUT, + on_demand::OnDemandRelay, + TransactionParams, }; +use async_std::sync::Arc; use bp_messages::{LaneId, MessageNonce}; use bp_runtime::{AccountIdOf, Chain as _}; use bridge_runtime_common::messages::{ @@ -38,7 +39,7 @@ use relay_substrate_client::{ transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithMessages, Client, HashOf, TransactionSignScheme, }; -use relay_utils::metrics::MetricsParams; +use relay_utils::{metrics::MetricsParams, STALL_TIMEOUT}; use sp_core::Pair; use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; @@ -135,9 +136,11 @@ pub struct MessagesRelayParams { pub target_transaction_params: TransactionParams>, /// Optional on-demand source to target headers relay. - pub source_to_target_headers_relay: Option>, + pub source_to_target_headers_relay: + Option>>>, /// Optional on-demand target to source headers relay. - pub target_to_source_headers_relay: Option>, + pub target_to_source_headers_relay: + Option>>>, /// Identifier of lane that needs to be served. pub lane_id: LaneId, /// Metrics parameters. @@ -507,7 +510,7 @@ mod tests { // i.e. weight reserved for messages dispatch allows dispatch of non-trivial messages. // // Any significant change in this values should attract additional attention. - (958, 216_583_333_334), + (1024, 216_609_134_667), ); } } diff --git a/relays/lib-substrate-relay/src/messages_metrics.rs b/relays/lib-substrate-relay/src/messages_metrics.rs index b165892fda..805d002b65 100644 --- a/relays/lib-substrate-relay/src/messages_metrics.rs +++ b/relays/lib-substrate-relay/src/messages_metrics.rs @@ -16,7 +16,7 @@ //! Tools for supporting message lanes between two Substrate-based chains. -use crate::{helpers::tokens_conversion_rate, messages_lane::SubstrateMessageLane}; +use crate::{helpers::tokens_conversion_rate, messages_lane::SubstrateMessageLane, TaggedAccount}; use codec::Decode; use frame_system::AccountInfo; @@ -273,15 +273,14 @@ pub fn standalone_metrics( /// Add relay accounts balance metrics. pub async fn add_relay_balances_metrics( client: Client, - metrics: MetricsParams, - relay_account_id: Option>, - messages_pallet_owner_account_id: Option>, -) -> anyhow::Result + metrics: &mut MetricsParams, + relay_accounts: &Vec>>, +) -> anyhow::Result<()> where BalanceOf: Into + std::fmt::Debug, { - if relay_account_id.is_none() && messages_pallet_owner_account_id.is_none() { - return Ok(metrics) + if relay_accounts.is_empty() { + return Ok(()) } // if `tokenDecimals` is missing from system properties, we'll be using @@ -306,27 +305,19 @@ where e, ) })?; - if let Some(relay_account_id) = relay_account_id { + + for account in relay_accounts { let relay_account_balance_metric = FloatStorageValueMetric::new( FreeAccountBalance:: { token_decimals, _phantom: Default::default() }, client.clone(), - C::account_info_storage_key(&relay_account_id), - format!("at_{}_relay_balance", C::NAME), - format!("Balance of the relay account at the {}", C::NAME), + C::account_info_storage_key(account.id()), + format!("at_{}_relay_{}_balance", C::NAME, account.tag()), + format!("Balance of the {} relay account at the {}", account.tag(), C::NAME), )?; relay_account_balance_metric.register_and_spawn(&metrics.registry)?; } - if let Some(messages_pallet_owner_account_id) = messages_pallet_owner_account_id { - let pallet_owner_account_balance_metric = FloatStorageValueMetric::new( - FreeAccountBalance:: { token_decimals, _phantom: Default::default() }, - client.clone(), - C::account_info_storage_key(&messages_pallet_owner_account_id), - format!("at_{}_messages_pallet_owner_balance", C::NAME), - format!("Balance of the messages pallet owner at the {}", C::NAME), - )?; - pallet_owner_account_balance_metric.register_and_spawn(&metrics.registry)?; - } - Ok(metrics) + + Ok(()) } /// Adapter for `FloatStorageValueMetric` to decode account free balance. diff --git a/relays/lib-substrate-relay/src/messages_source.rs b/relays/lib-substrate-relay/src/messages_source.rs index 77dd2aed05..5de9e30dd0 100644 --- a/relays/lib-substrate-relay/src/messages_source.rs +++ b/relays/lib-substrate-relay/src/messages_source.rs @@ -23,15 +23,18 @@ use crate::{ MessageLaneAdapter, ReceiveMessagesDeliveryProofCallBuilder, SubstrateMessageLane, }, messages_target::SubstrateMessagesDeliveryProof, - on_demand_headers::OnDemandHeadersRelay, + on_demand::OnDemandRelay, TransactionParams, }; +use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ storage_keys::{operating_mode_key, outbound_lane_data_key}, - LaneId, MessageNonce, OperatingMode, OutboundLaneData, UnrewardedRelayersState, + InboundMessageDetails, LaneId, MessageData, MessageNonce, MessagePayload, + MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState, }; +use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, HeaderIdProvider}; use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; @@ -59,6 +62,7 @@ use std::ops::RangeInclusive; /// required to submit to the target node: cumulative dispatch weight of bundled messages and /// the proof itself. pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof>); +type MessagesToRefine<'a, Balance> = Vec<(MessagePayload, &'a mut OutboundMessageDetails)>; /// Substrate client as Substrate messages source. pub struct SubstrateMessagesSource { @@ -66,7 +70,7 @@ pub struct SubstrateMessagesSource { target_client: Client, lane_id: LaneId, transaction_params: TransactionParams>, - target_to_source_headers_relay: Option>, + target_to_source_headers_relay: Option>>>, } impl SubstrateMessagesSource

{ @@ -76,7 +80,9 @@ impl SubstrateMessagesSource

{ target_client: Client, lane_id: LaneId, transaction_params: TransactionParams>, - target_to_source_headers_relay: Option>, + target_to_source_headers_relay: Option< + Arc>>, + >, ) -> Self { SubstrateMessagesSource { source_client, @@ -141,7 +147,11 @@ where async fn state(&self) -> Result>, SubstrateError> { // we can't continue to deliver confirmations if source node is out of sync, because // it may have already received confirmations that we're going to deliver + // + // we can't continue to deliver messages if target node is out of sync, because + // it may have already received (some of) messages that we're going to deliver self.source_client.ensure_synced().await?; + self.target_client.ensure_synced().await?; // we can't relay confirmations if messages pallet at source chain is halted self.ensure_pallet_active().await?; @@ -183,24 +193,97 @@ where &self, id: SourceHeaderIdOf>, nonces: RangeInclusive, - ) -> Result< - MessageDetailsMap< as MessageLane>::SourceChainBalance>, - SubstrateError, - > { - let encoded_response = self + ) -> Result>, SubstrateError> { + let mut out_msgs_details = self .source_client - .state_call( + .typed_state_call::<_, Vec<_>>( P::TargetChain::TO_CHAIN_MESSAGE_DETAILS_METHOD.into(), - Bytes((self.lane_id, nonces.start(), nonces.end()).encode()), + (self.lane_id, *nonces.start(), *nonces.end()), Some(id.1), ) .await?; + validate_out_msgs_details::(&out_msgs_details, nonces)?; + + // prepare arguments of the inbound message details call (if we need it) + let mut msgs_to_refine = vec![]; + for out_msg_details in out_msgs_details.iter_mut() { + if out_msg_details.dispatch_fee_payment != DispatchFeePayment::AtTargetChain { + continue + } + + // for pay-at-target messages we may want to ask target chain for + // refined dispatch weight + let msg_key = bp_messages::storage_keys::message_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + out_msg_details.nonce, + ); + let msg_data: MessageData> = + self.source_client.storage_value(msg_key, Some(id.1)).await?.ok_or_else(|| { + SubstrateError::Custom(format!( + "Message to {} {:?}/{} is missing from runtime the storage of {} at {:?}", + P::TargetChain::NAME, + self.lane_id, + out_msg_details.nonce, + P::SourceChain::NAME, + id, + )) + })?; + + msgs_to_refine.push((msg_data.payload, out_msg_details)); + } - make_message_details_map::( - Decode::decode(&mut &encoded_response.0[..]) - .map_err(SubstrateError::ResponseParseFailed)?, - nonces, - ) + for mut msgs_to_refine_batch in + split_msgs_to_refine::(self.lane_id, msgs_to_refine)? + { + let in_msgs_details = self + .target_client + .typed_state_call::<_, Vec>( + P::SourceChain::FROM_CHAIN_MESSAGE_DETAILS_METHOD.into(), + (self.lane_id, &msgs_to_refine_batch), + None, + ) + .await?; + if in_msgs_details.len() != msgs_to_refine_batch.len() { + return Err(SubstrateError::Custom(format!( + "Call of {} at {} has returned {} entries instead of expected {}", + P::SourceChain::FROM_CHAIN_MESSAGE_DETAILS_METHOD, + P::TargetChain::NAME, + in_msgs_details.len(), + msgs_to_refine_batch.len(), + ))) + } + for ((_, out_msg_details), in_msg_details) in + msgs_to_refine_batch.iter_mut().zip(in_msgs_details) + { + log::trace!( + target: "bridge", + "Refined weight of {}->{} message {:?}/{}: at-source: {}, at-target: {}", + P::SourceChain::NAME, + P::TargetChain::NAME, + self.lane_id, + out_msg_details.nonce, + out_msg_details.dispatch_weight, + in_msg_details.dispatch_weight, + ); + out_msg_details.dispatch_weight = in_msg_details.dispatch_weight; + } + } + + let mut msgs_details_map = MessageDetailsMap::new(); + for out_msg_details in out_msgs_details { + msgs_details_map.insert( + out_msg_details.nonce, + MessageDetails { + dispatch_weight: out_msg_details.dispatch_weight, + size: out_msg_details.size as _, + reward: out_msg_details.delivery_and_dispatch_fee, + dispatch_fee_payment: out_msg_details.dispatch_fee_payment, + }, + ); + } + + Ok(msgs_details_map) } async fn prove_messages( @@ -263,11 +346,14 @@ where self.source_client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash, + signer: self.transaction_params.signer.clone(), + }, move |best_block_id, transaction_nonce| { make_messages_delivery_proof_transaction::

( - spec_version, - transaction_version, - &genesis_hash, &transaction_params, best_block_id, transaction_nonce, @@ -282,7 +368,7 @@ where async fn require_target_header_on_source(&self, id: TargetHeaderIdOf>) { if let Some(ref target_to_source_headers_relay) = self.target_to_source_headers_relay { - target_to_source_headers_relay.require_finalized_header(id).await; + target_to_source_headers_relay.require_more_headers(id.0).await; } } @@ -294,18 +380,24 @@ where Err(_) => return BalanceOf::::max_value(), }; async { - let dummy_tx = make_messages_delivery_proof_transaction::

( - runtime_version.spec_version, - runtime_version.transaction_version, - self.source_client.genesis_hash(), - &self.transaction_params, - HeaderId(Default::default(), Default::default()), - Zero::zero(), - prepare_dummy_messages_delivery_proof::(), - false, - )?; + let dummy_tx = P::SourceTransactionSignScheme::sign_transaction( + SignParam:: { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + genesis_hash: *self.source_client.genesis_hash(), + signer: self.transaction_params.signer.clone(), + }, + make_messages_delivery_proof_transaction::

( + &self.transaction_params, + HeaderId(Default::default(), Default::default()), + Zero::zero(), + prepare_dummy_messages_delivery_proof::(), + false, + )?, + )? + .encode(); self.source_client - .estimate_extrinsic_fee(dummy_tx) + .estimate_extrinsic_fee(Bytes(dummy_tx)) .await .map(|fee| fee.inclusion_fee()) } @@ -325,7 +417,8 @@ where let operating_mode = client .storage_value(operating_mode_key(WithChain::WITH_CHAIN_MESSAGES_PALLET_NAME), None) .await?; - let is_halted = operating_mode == Some(OperatingMode::Halted); + let is_halted = + operating_mode == Some(MessagesOperatingMode::Basic(BasicOperatingMode::Halted)); if is_halted { Err(SubstrateError::BridgePalletIsHalted) } else { @@ -334,17 +427,13 @@ where } /// Make messages delivery proof transaction from given proof. -#[allow(clippy::too_many_arguments)] fn make_messages_delivery_proof_transaction( - spec_version: u32, - transaction_version: u32, - source_genesis_hash: &HashOf, source_transaction_params: &TransactionParams>, source_best_block_id: HeaderIdOf, transaction_nonce: IndexOf, proof: SubstrateMessagesDeliveryProof, trace_call: bool, -) -> Result +) -> Result, SubstrateError> where P::SourceTransactionSignScheme: TransactionSignScheme, { @@ -352,17 +441,8 @@ where P::ReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call( proof, trace_call, ); - Ok(Bytes( - P::SourceTransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *source_genesis_hash, - signer: source_transaction_params.signer.clone(), - era: TransactionEra::new(source_best_block_id, source_transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(source_best_block_id, source_transaction_params.mortality))) } /// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction. @@ -371,18 +451,15 @@ where /// affect the call weight - we only care about its size. fn prepare_dummy_messages_delivery_proof( ) -> SubstrateMessagesDeliveryProof { - let single_message_confirmation_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( - SC::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); + let single_message_confirmation_size = + bp_messages::InboundLaneData::<()>::encoded_size_hint_u32(1, 1); let proof_size = TC::STORAGE_PROOF_OVERHEAD.saturating_add(single_message_confirmation_size); ( UnrewardedRelayersState { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 1, total_messages: 1, + last_delivered_nonce: 1, }, FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), @@ -415,34 +492,28 @@ where let self_best_finalized_header_hash = self_client.best_finalized_header_hash().await?; let self_best_finalized_header = self_client.header_by_hash(self_best_finalized_header_hash).await?; - let self_best_finalized_id = - HeaderId(*self_best_finalized_header.number(), self_best_finalized_header_hash); + let self_best_finalized_id = self_best_finalized_header.id(); // now let's read our best header on **this** chain let self_best_header = self_client.best_header().await?; let self_best_hash = self_best_header.hash(); - let self_best_id = HeaderId(*self_best_header.number(), self_best_hash); + let self_best_id = self_best_header.id(); // now let's read id of best finalized peer header at our best finalized block - let encoded_best_finalized_peer_on_self = self_client - .state_call( - best_finalized_header_id_method_name.into(), - Bytes(Vec::new()), - Some(self_best_hash), + let peer_on_self_best_finalized_id = + best_finalized_peer_header_at_self::( + self_client, + self_best_hash, + best_finalized_header_id_method_name, ) .await?; - let decoded_best_finalized_peer_on_self: (BlockNumberOf, HashOf) = - Decode::decode(&mut &encoded_best_finalized_peer_on_self.0[..]) - .map_err(SubstrateError::ResponseParseFailed)?; - let peer_on_self_best_finalized_id = - HeaderId(decoded_best_finalized_peer_on_self.0, decoded_best_finalized_peer_on_self.1); // read actual header, matching the `peer_on_self_best_finalized_id` from the peer chain let actual_peer_on_self_best_finalized_id = match peer_client { Some(peer_client) => { let actual_peer_on_self_best_finalized = peer_client.header_by_number(peer_on_self_best_finalized_id.0).await?; - HeaderId(peer_on_self_best_finalized_id.0, actual_peer_on_self_best_finalized.hash()) + actual_peer_on_self_best_finalized.id() }, None => peer_on_self_best_finalized_id, }; @@ -455,10 +526,39 @@ where }) } -fn make_message_details_map( - weights: Vec>, +/// Reads best `PeerChain` header known to the `SelfChain` using provided runtime API method. +/// +/// Method is supposed to be the `FinalityApi::best_finalized()` method. +pub async fn best_finalized_peer_header_at_self( + self_client: &Client, + at_self_hash: HashOf, + best_finalized_header_id_method_name: &str, +) -> Result, SubstrateError> +where + SelfChain: Chain, + PeerChain: Chain, +{ + // now let's read id of best finalized peer header at our best finalized block + let encoded_best_finalized_peer_on_self = self_client + .state_call( + best_finalized_header_id_method_name.into(), + Bytes(Vec::new()), + Some(at_self_hash), + ) + .await?; + + Option::, BlockNumberOf>>::decode( + &mut &encoded_best_finalized_peer_on_self.0[..], + ) + .map_err(SubstrateError::ResponseParseFailed)? + .map(Ok) + .unwrap_or(Err(SubstrateError::BridgePalletIsNotInitialized)) +} + +fn validate_out_msgs_details( + out_msgs_details: &[OutboundMessageDetails], nonces: RangeInclusive, -) -> Result, SubstrateError> { +) -> Result<(), SubstrateError> { let make_missing_nonce_error = |expected_nonce| { Err(SubstrateError::Custom(format!( "Missing nonce {} in message_details call result. Expected all nonces from {:?}", @@ -466,75 +566,91 @@ fn make_message_details_map( ))) }; - let mut weights_map = MessageDetailsMap::new(); - - // this is actually prevented by external logic - if nonces.is_empty() { - return Ok(weights_map) + if out_msgs_details.len() > nonces.clone().count() { + return Err(SubstrateError::Custom( + "More messages than requested returned by the message_details call.".into(), + )) } - // check if last nonce is missing - loop below is not checking this - let last_nonce_is_missing = - weights.last().map(|details| details.nonce != *nonces.end()).unwrap_or(true); - if last_nonce_is_missing { + // Check if last nonce is missing. The loop below is not checking this. + if out_msgs_details.is_empty() && !nonces.is_empty() { return make_missing_nonce_error(*nonces.end()) } - let mut expected_nonce = *nonces.start(); - let mut is_at_head = true; - - for details in weights { - match (details.nonce == expected_nonce, is_at_head) { - (true, _) => (), - (false, true) => { - // this may happen if some messages were already pruned from the source node - // - // this is not critical error and will be auto-resolved by messages lane (and target - // node) - log::info!( - target: "bridge", - "Some messages are missing from the {} node: {:?}. Target node may be out of sync?", - C::NAME, - expected_nonce..details.nonce, - ); - }, - (false, false) => { - // some nonces are missing from the middle/tail of the range - // - // this is critical error, because we can't miss any nonces - return make_missing_nonce_error(expected_nonce) - }, + let mut nonces_iter = nonces.clone().rev().peekable(); + let mut out_msgs_details_iter = out_msgs_details.iter().rev(); + while let Some((out_msg_details, &nonce)) = out_msgs_details_iter.next().zip(nonces_iter.peek()) + { + nonces_iter.next(); + if out_msg_details.nonce != nonce { + // Some nonces are missing from the middle/tail of the range. This is critical error. + return make_missing_nonce_error(nonce) } + } - weights_map.insert( - details.nonce, - MessageDetails { - dispatch_weight: details.dispatch_weight, - size: details.size as _, - reward: details.delivery_and_dispatch_fee, - dispatch_fee_payment: details.dispatch_fee_payment, - }, + // Check if some nonces from the beginning of the range are missing. This may happen if + // some messages were already pruned from the source node. This is not a critical error + // and will be auto-resolved by messages lane (and target node). + if nonces_iter.peek().is_some() { + log::info!( + target: "bridge", + "Some messages are missing from the {} node: {:?}. Target node may be out of sync?", + C::NAME, + nonces_iter.rev().collect::>(), ); - expected_nonce = details.nonce + 1; - is_at_head = false; } - Ok(weights_map) + Ok(()) +} + +fn split_msgs_to_refine( + lane_id: LaneId, + msgs_to_refine: MessagesToRefine, +) -> Result>, SubstrateError> { + let max_batch_size = Target::max_extrinsic_size() as usize; + let mut batches = vec![]; + + let mut current_msgs_batch = msgs_to_refine; + while !current_msgs_batch.is_empty() { + let mut next_msgs_batch = vec![]; + while (lane_id, ¤t_msgs_batch).encoded_size() > max_batch_size { + if current_msgs_batch.len() <= 1 { + return Err(SubstrateError::Custom(format!( + "Call of {} at {} can't be executed even if only one message is supplied. \ + max_extrinsic_size(): {}", + Source::FROM_CHAIN_MESSAGE_DETAILS_METHOD, + Target::NAME, + Target::max_extrinsic_size(), + ))) + } + + if let Some(msg) = current_msgs_batch.pop() { + next_msgs_batch.insert(0, msg); + } + } + + batches.push(current_msgs_batch); + current_msgs_batch = next_msgs_batch; + } + + Ok(batches) } #[cfg(test)] mod tests { use super::*; - use bp_runtime::messages::DispatchFeePayment; + use bp_runtime::{messages::DispatchFeePayment, Chain as ChainBase}; + use codec::MaxEncodedLen; + use relay_rialto_client::Rialto; use relay_rococo_client::Rococo; use relay_wococo_client::Wococo; fn message_details_from_rpc( nonces: RangeInclusive, - ) -> Vec> { + ) -> Vec> { nonces .into_iter() - .map(|nonce| bp_messages::MessageDetails { + .map(|nonce| bp_messages::OutboundMessageDetails { nonce, dispatch_weight: 0, size: 0, @@ -545,94 +661,49 @@ mod tests { } #[test] - fn make_message_details_map_succeeds_if_no_messages_are_missing() { - assert_eq!( - make_message_details_map::(message_details_from_rpc(1..=3), 1..=3,).unwrap(), - vec![ - ( - 1, - MessageDetails { - dispatch_weight: 0, - size: 0, - reward: 0, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - } - ), - ( - 2, - MessageDetails { - dispatch_weight: 0, - size: 0, - reward: 0, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - } - ), - ( - 3, - MessageDetails { - dispatch_weight: 0, - size: 0, - reward: 0, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - } - ), - ] - .into_iter() - .collect(), + fn validate_out_msgs_details_succeeds_if_no_messages_are_missing() { + assert!( + validate_out_msgs_details::(&message_details_from_rpc(1..=3), 1..=3,).is_ok() ); } #[test] - fn make_message_details_map_succeeds_if_head_messages_are_missing() { - assert_eq!( - make_message_details_map::(message_details_from_rpc(2..=3), 1..=3,).unwrap(), - vec![ - ( - 2, - MessageDetails { - dispatch_weight: 0, - size: 0, - reward: 0, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - } - ), - ( - 3, - MessageDetails { - dispatch_weight: 0, - size: 0, - reward: 0, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - } - ), - ] - .into_iter() - .collect(), - ); + fn validate_out_msgs_details_succeeds_if_head_messages_are_missing() { + assert!( + validate_out_msgs_details::(&message_details_from_rpc(2..=3), 1..=3,).is_ok() + ) } #[test] - fn make_message_details_map_fails_if_mid_messages_are_missing() { + fn validate_out_msgs_details_fails_if_mid_messages_are_missing() { let mut message_details_from_rpc = message_details_from_rpc(1..=3); message_details_from_rpc.remove(1); assert!(matches!( - make_message_details_map::(message_details_from_rpc, 1..=3,), + validate_out_msgs_details::(&message_details_from_rpc, 1..=3,), + Err(SubstrateError::Custom(_)) + )); + } + + #[test] + fn validate_out_msgs_details_map_fails_if_tail_messages_are_missing() { + assert!(matches!( + validate_out_msgs_details::(&message_details_from_rpc(1..=2), 1..=3,), Err(SubstrateError::Custom(_)) )); } #[test] - fn make_message_details_map_fails_if_tail_messages_are_missing() { + fn validate_out_msgs_details_fails_if_all_messages_are_missing() { assert!(matches!( - make_message_details_map::(message_details_from_rpc(1..=2), 1..=3,), + validate_out_msgs_details::(&[], 1..=3), Err(SubstrateError::Custom(_)) )); } #[test] - fn make_message_details_map_fails_if_all_messages_are_missing() { + fn validate_out_msgs_details_fails_if_more_messages_than_nonces() { assert!(matches!( - make_message_details_map::(vec![], 1..=3), + validate_out_msgs_details::(&message_details_from_rpc(1..=5), 2..=5,), Err(SubstrateError::Custom(_)) )); } @@ -640,7 +711,7 @@ mod tests { #[test] fn prepare_dummy_messages_delivery_proof_works() { let expected_minimal_size = - Wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE + Rococo::STORAGE_PROOF_OVERHEAD; + bp_wococo::AccountId::max_encoded_len() as u32 + Rococo::STORAGE_PROOF_OVERHEAD; let dummy_proof = prepare_dummy_messages_delivery_proof::(); assert!( dummy_proof.1.encode().len() as u32 > expected_minimal_size, @@ -649,4 +720,101 @@ mod tests { dummy_proof.1.encode().len(), ); } + + fn check_split_msgs_to_refine( + payload_sizes: Vec, + expected_batches: Result, ()>, + ) { + let mut out_msgs_details = vec![]; + for (idx, _) in payload_sizes.iter().enumerate() { + out_msgs_details.push(OutboundMessageDetails::> { + nonce: idx as MessageNonce, + dispatch_weight: 0, + size: 0, + delivery_and_dispatch_fee: 0, + dispatch_fee_payment: DispatchFeePayment::AtTargetChain, + }); + } + + let mut msgs_to_refine = vec![]; + for (&payload_size, out_msg_details) in + payload_sizes.iter().zip(out_msgs_details.iter_mut()) + { + let payload = vec![1u8; payload_size]; + msgs_to_refine.push((payload, out_msg_details)); + } + + let maybe_batches = split_msgs_to_refine::([0, 0, 0, 0], msgs_to_refine); + match expected_batches { + Ok(expected_batches) => { + let batches = maybe_batches.unwrap(); + let mut idx = 0; + assert_eq!(batches.len(), expected_batches.len()); + for (batch, &expected_batch_size) in batches.iter().zip(expected_batches.iter()) { + assert_eq!(batch.len(), expected_batch_size); + for msg_to_refine in batch { + assert_eq!(msg_to_refine.0.len(), payload_sizes[idx]); + idx += 1; + } + } + }, + Err(_) => { + matches!(maybe_batches, Err(SubstrateError::Custom(_))); + }, + } + } + + #[test] + fn test_split_msgs_to_refine() { + let max_extrinsic_size = Rococo::max_extrinsic_size() as usize; + + // Check that an error is returned when one of the messages is too big. + check_split_msgs_to_refine(vec![max_extrinsic_size], Err(())); + check_split_msgs_to_refine(vec![50, 100, max_extrinsic_size, 200], Err(())); + + // Otherwise check that the split is valid. + check_split_msgs_to_refine(vec![100, 200, 300, 400], Ok(vec![4])); + check_split_msgs_to_refine( + vec![ + 50, + 100, + max_extrinsic_size - 500, + 500, + 1000, + 1500, + max_extrinsic_size - 3500, + 5000, + 10000, + ], + Ok(vec![3, 4, 2]), + ); + check_split_msgs_to_refine( + vec![ + 50, + 100, + max_extrinsic_size - 150, + 500, + 1000, + 1500, + max_extrinsic_size - 3000, + 5000, + 10000, + ], + Ok(vec![2, 1, 3, 1, 2]), + ); + check_split_msgs_to_refine( + vec![ + 5000, + 10000, + max_extrinsic_size - 3500, + 500, + 1000, + 1500, + max_extrinsic_size - 500, + 50, + 100, + ], + Ok(vec![2, 4, 3]), + ); + } } diff --git a/relays/lib-substrate-relay/src/messages_target.rs b/relays/lib-substrate-relay/src/messages_target.rs index 869a1d2802..29d80bc2c5 100644 --- a/relays/lib-substrate-relay/src/messages_target.rs +++ b/relays/lib-substrate-relay/src/messages_target.rs @@ -22,10 +22,11 @@ use crate::{ messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane}, messages_metrics::StandaloneMessagesMetrics, messages_source::{ensure_messages_pallet_active, read_client_state, SubstrateMessagesProof}, - on_demand_headers::OnDemandHeadersRelay, + on_demand::OnDemandRelay, TransactionParams, }; +use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ storage_keys::inbound_lane_data_key, total_unrewarded_messages, InboundLaneData, LaneId, @@ -35,14 +36,14 @@ use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; use codec::Encode; -use frame_support::weights::{Weight, WeightToFeePolynomial}; +use frame_support::weights::{Weight, WeightToFee}; use messages_relay::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, message_lane_loop::{TargetClient, TargetClientState}, }; use num_traits::{Bounded, Zero}; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithMessages, Client, + AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages, Client, Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra, TransactionSignScheme, UnsignedTransaction, WeightToFeeOf, }; @@ -63,7 +64,7 @@ pub struct SubstrateMessagesTarget { relayer_id_at_source: AccountIdOf, transaction_params: TransactionParams>, metric_values: StandaloneMessagesMetrics, - source_to_target_headers_relay: Option>, + source_to_target_headers_relay: Option>>>, } impl SubstrateMessagesTarget

{ @@ -75,7 +76,9 @@ impl SubstrateMessagesTarget

{ relayer_id_at_source: AccountIdOf, transaction_params: TransactionParams>, metric_values: StandaloneMessagesMetrics, - source_to_target_headers_relay: Option>, + source_to_target_headers_relay: Option< + Arc>>, + >, ) -> Self { SubstrateMessagesTarget { target_client, @@ -143,8 +146,12 @@ where BalanceOf: TryFrom>, { async fn state(&self) -> Result>, SubstrateError> { + // we can't continue to deliver confirmations if source node is out of sync, because + // it may have already received confirmations that we're going to deliver + // // we can't continue to deliver messages if target node is out of sync, because // it may have already received (some of) messages that we're going to deliver + self.source_client.ensure_synced().await?; self.target_client.ensure_synced().await?; // we can't relay messages if messages pallet at target chain is halted self.ensure_pallet_active().await?; @@ -188,11 +195,10 @@ where id: TargetHeaderIdOf>, ) -> Result<(TargetHeaderIdOf>, UnrewardedRelayersState), SubstrateError> { - let relayers = self - .inbound_lane_data(id) - .await? - .map(|data| data.relayers) - .unwrap_or_else(|| VecDeque::new()); + let inbound_lane_data = self.inbound_lane_data(id).await?; + let last_delivered_nonce = + inbound_lane_data.as_ref().map(|data| data.last_delivered_nonce()).unwrap_or(0); + let relayers = inbound_lane_data.map(|data| data.relayers).unwrap_or_else(VecDeque::new); let unrewarded_relayers_state = bp_messages::UnrewardedRelayersState { unrewarded_relayer_entries: relayers.len() as _, messages_in_oldest_entry: relayers @@ -200,6 +206,7 @@ where .map(|entry| 1 + entry.messages.end - entry.messages.begin) .unwrap_or(0), total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX), + last_delivered_nonce, }; Ok((id, unrewarded_relayers_state)) } @@ -248,11 +255,14 @@ where self.target_client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash, + signer: self.transaction_params.signer.clone(), + }, move |best_block_id, transaction_nonce| { make_messages_delivery_transaction::

( - spec_version, - transaction_version, - &genesis_hash, &transaction_params, best_block_id, transaction_nonce, @@ -269,7 +279,7 @@ where async fn require_source_header_on_target(&self, id: SourceHeaderIdOf>) { if let Some(ref source_to_target_headers_relay) = self.source_to_target_headers_relay { - source_to_target_headers_relay.require_finalized_header(id).await; + source_to_target_headers_relay.require_more_headers(id.0).await; } } @@ -292,23 +302,29 @@ where let (spec_version, transaction_version) = self.target_client.simple_runtime_version().await?; // Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight. - let delivery_tx = make_messages_delivery_transaction::

( - spec_version, - transaction_version, - self.target_client.genesis_hash(), - &self.transaction_params, - HeaderId(Default::default(), Default::default()), - Zero::zero(), - self.relayer_id_at_source.clone(), - nonces.clone(), - prepare_dummy_messages_proof::( + let delivery_tx = P::TargetTransactionSignScheme::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: Default::default(), + signer: self.transaction_params.signer.clone(), + }, + make_messages_delivery_transaction::

( + &self.transaction_params, + HeaderId(Default::default(), Default::default()), + Zero::zero(), + self.relayer_id_at_source.clone(), nonces.clone(), - total_dispatch_weight, - total_size, - ), - false, - )?; - let delivery_tx_fee = self.target_client.estimate_extrinsic_fee(delivery_tx).await?; + prepare_dummy_messages_proof::( + nonces.clone(), + total_dispatch_weight, + total_size, + ), + false, + )?, + )? + .encode(); + let delivery_tx_fee = self.target_client.estimate_extrinsic_fee(Bytes(delivery_tx)).await?; let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee(); // The pre-dispatch cost of delivery transaction includes additional fee to cover dispatch @@ -333,24 +349,30 @@ where let (spec_version, transaction_version) = self.target_client.simple_runtime_version().await?; let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE); - let dummy_tx = make_messages_delivery_transaction::

( - spec_version, - transaction_version, - self.target_client.genesis_hash(), - &self.transaction_params, - HeaderId(Default::default(), Default::default()), - Zero::zero(), - self.relayer_id_at_source.clone(), - nonces.clone(), - prepare_dummy_messages_proof::( + let dummy_tx = P::TargetTransactionSignScheme::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: Default::default(), + signer: self.transaction_params.signer.clone(), + }, + make_messages_delivery_transaction::

( + &self.transaction_params, + HeaderId(Default::default(), Default::default()), + Zero::zero(), + self.relayer_id_at_source.clone(), nonces.clone(), - larger_dispatch_weight, - total_size, - ), - false, - )?; + prepare_dummy_messages_proof::( + nonces.clone(), + larger_dispatch_weight, + total_size, + ), + false, + )?, + )? + .encode(); let larger_delivery_tx_fee = - self.target_client.estimate_extrinsic_fee(dummy_tx).await?; + self.target_client.estimate_extrinsic_fee(Bytes(dummy_tx)).await?; compute_prepaid_messages_refund::( total_prepaid_nonces, @@ -399,11 +421,7 @@ where } /// Make messages delivery transaction from given proof. -#[allow(clippy::too_many_arguments)] fn make_messages_delivery_transaction( - spec_version: u32, - transaction_version: u32, - target_genesis_hash: &HashOf, target_transaction_params: &TransactionParams>, target_best_block_id: HeaderIdOf, transaction_nonce: IndexOf, @@ -411,7 +429,7 @@ fn make_messages_delivery_transaction( nonces: RangeInclusive, proof: SubstrateMessagesProof, trace_call: bool, -) -> Result +) -> Result, SubstrateError> where P::TargetTransactionSignScheme: TransactionSignScheme, { @@ -424,17 +442,8 @@ where dispatch_weight, trace_call, ); - Ok(Bytes( - P::TargetTransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *target_genesis_hash, - signer: target_transaction_params.signer.clone(), - era: TransactionEra::new(target_best_block_id, target_transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(target_best_block_id, target_transaction_params.mortality))) } /// Prepare 'dummy' messages proof that will compose the delivery transaction. @@ -493,8 +502,8 @@ fn compute_fee_multiplier( ) -> FixedU128 { let adjusted_weight_fee_difference = larger_adjusted_weight_fee.saturating_sub(smaller_adjusted_weight_fee); - let smaller_tx_unadjusted_weight_fee = WeightToFeeOf::::calc(&smaller_tx_weight); - let larger_tx_unadjusted_weight_fee = WeightToFeeOf::::calc(&larger_tx_weight); + let smaller_tx_unadjusted_weight_fee = WeightToFeeOf::::weight_to_fee(&smaller_tx_weight); + let larger_tx_unadjusted_weight_fee = WeightToFeeOf::::weight_to_fee(&larger_tx_weight); FixedU128::saturating_from_rational( adjusted_weight_fee_difference, larger_tx_unadjusted_weight_fee.saturating_sub(smaller_tx_unadjusted_weight_fee), @@ -507,7 +516,7 @@ fn compute_prepaid_messages_refund( total_prepaid_nonces: MessageNonce, fee_multiplier: FixedU128, ) -> BalanceOf { - fee_multiplier.saturating_mul_int(WeightToFeeOf::::calc( + fee_multiplier.saturating_mul_int(WeightToFeeOf::::weight_to_fee( &C::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN.saturating_mul(total_prepaid_nonces), )) } @@ -515,6 +524,7 @@ fn compute_prepaid_messages_refund( #[cfg(test)] mod tests { use super::*; + use relay_rialto_client::Rialto; use relay_rococo_client::Rococo; use relay_wococo_client::Wococo; @@ -550,16 +560,15 @@ mod tests { #[test] fn compute_fee_multiplier_returns_sane_results() { - let multiplier = FixedU128::saturating_from_rational(1, 1000); + let multiplier: FixedU128 = bp_rococo::WeightToFee::weight_to_fee(&1).into(); let smaller_weight = 1_000_000; let smaller_adjusted_weight_fee = - multiplier.saturating_mul_int(WeightToFeeOf::::calc(&smaller_weight)); + multiplier.saturating_mul_int(WeightToFeeOf::::weight_to_fee(&smaller_weight)); let larger_weight = smaller_weight + 200_000; let larger_adjusted_weight_fee = - multiplier.saturating_mul_int(WeightToFeeOf::::calc(&larger_weight)); - + multiplier.saturating_mul_int(WeightToFeeOf::::weight_to_fee(&larger_weight)); assert_eq!( compute_fee_multiplier::( smaller_adjusted_weight_fee, @@ -574,10 +583,10 @@ mod tests { #[test] fn compute_prepaid_messages_refund_returns_sane_results() { assert!( - compute_prepaid_messages_refund::( + compute_prepaid_messages_refund::( 10, FixedU128::saturating_from_rational(110, 100), - ) > (10 * Wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN).into() + ) > (10 * Rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN).into() ); } } diff --git a/relays/lib-substrate-relay/src/on_demand_headers.rs b/relays/lib-substrate-relay/src/on_demand/headers.rs similarity index 91% rename from relays/lib-substrate-relay/src/on_demand_headers.rs rename to relays/lib-substrate-relay/src/on_demand/headers.rs index c1401a28a6..09e7a41a0c 100644 --- a/relays/lib-substrate-relay/src/on_demand_headers.rs +++ b/relays/lib-substrate-relay/src/on_demand/headers.rs @@ -14,29 +14,34 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! On-demand Substrate -> Substrate headers relay. +//! On-demand Substrate -> Substrate header finality relay. use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; use futures::{select, FutureExt}; use num_traits::{One, Zero}; use finality_relay::{FinalitySyncParams, SourceHeader, TargetClient as FinalityTargetClient}; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, HeaderIdOf, HeaderOf, SyncHeader, + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, HeaderOf, SyncHeader, TransactionSignScheme, }; use relay_utils::{ metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, MaybeConnectionError, + STALL_TIMEOUT, }; use crate::{ - finality_pipeline::{SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT}, - finality_source::{RequiredHeaderNumberRef, SubstrateFinalitySource}, - finality_target::SubstrateFinalityTarget, - TransactionParams, STALL_TIMEOUT, + finality::{ + source::{RequiredHeaderNumberRef, SubstrateFinalitySource}, + target::SubstrateFinalityTarget, + SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT, + }, + on_demand::OnDemandRelay, + TransactionParams, }; -/// On-demand Substrate <-> Substrate headers relay. +/// On-demand Substrate <-> Substrate header finality relay. /// /// This relay may be requested to sync more headers, whenever some other relay (e.g. messages /// relay) needs it to continue its regular work. When enough headers are relayed, on-demand stops @@ -80,20 +85,24 @@ impl OnDemandHeadersRelay { this } +} - /// Someone is asking us to relay given finalized header. - pub async fn require_finalized_header(&self, header_id: HeaderIdOf) { +#[async_trait] +impl OnDemandRelay> + for OnDemandHeadersRelay +{ + async fn require_more_headers(&self, required_header: BlockNumberOf) { let mut required_header_number = self.required_header_number.lock().await; - if header_id.0 > *required_header_number { + if required_header > *required_header_number { log::trace!( target: "bridge", - "More {} headers required in {} relay. Going to sync up to the {}", - SourceChain::NAME, + "[{}] More {} headers required. Going to sync up to the {}", self.relay_task_name, - header_id.0, + SourceChain::NAME, + required_header, ); - *required_header_number = header_id.0; + *required_header_number = required_header; } } } @@ -176,7 +185,7 @@ async fn background_task( log::trace!( target: "bridge", - "Mandatory headers scan range in {}: ({:?}, {:?}, {:?}) -> {:?}", + "[{}] Mandatory headers scan range: ({:?}, {:?}, {:?}) -> {:?}", relay_task_name, required_header_number_value, best_finalized_source_header_at_source_fmt, @@ -205,18 +214,18 @@ async fn background_task( log::trace!( target: "bridge", - "No mandatory {} headers in the range {:?} of {} relay", + "[{}] No mandatory {} headers in the range {:?}", + relay_task_name, P::SourceChain::NAME, mandatory_scan_range, - relay_task_name, ); }, Err(e) => { log::warn!( target: "bridge", - "Failed to scan mandatory {} headers range in {} relay (range: {:?}): {:?}", - P::SourceChain::NAME, + "[{}] Failed to scan mandatory {} headers range ({:?}): {:?}", relay_task_name, + P::SourceChain::NAME, mandatory_scan_range, e, ); @@ -245,7 +254,7 @@ async fn background_task( log::info!( target: "bridge", - "Starting {} relay\n\t\ + "[{}] Starting on-demand headers relay task\n\t\ Only mandatory headers: {}\n\t\ Tx mortality: {:?} (~{}m)\n\t\ Stall timeout: {:?}", @@ -339,9 +348,9 @@ async fn relay_mandatory_header_from_range( log::trace!( target: "bridge", - "Too many {} headers missing at target in {} relay ({} vs {}). Going to sync up to the mandatory {}", - P::SourceChain::NAME, + "[{}] Too many {} headers missing at target ({} vs {}). Going to sync up to the mandatory {}", relay_task_name, + P::SourceChain::NAME, best_finalized_source_header_at_target, range.1, mandatory_source_header_number, @@ -361,7 +370,7 @@ async fn best_finalized_source_header_at_source( /// On-demand headers relay task name. fn on_demand_headers_relay_name() -> String { - format!("on-demand-{}-to-{}", SourceChain::NAME, TargetChain::NAME) + format!("{}-to-{}-on-demand-headers", SourceChain::NAME, TargetChain::NAME) } #[cfg(test)] diff --git a/relays/lib-substrate-relay/src/on_demand/mod.rs b/relays/lib-substrate-relay/src/on_demand/mod.rs new file mode 100644 index 0000000000..7a2dfc9c15 --- /dev/null +++ b/relays/lib-substrate-relay/src/on_demand/mod.rs @@ -0,0 +1,35 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! on-demand pipelines. + +use async_trait::async_trait; + +pub mod headers; +pub mod parachains; + +/// On-demand headers relay that is relaying finalizing headers only when requested. +#[async_trait] +pub trait OnDemandRelay: Send + Sync { + /// Ask relay to relay source header with given number to the target chain. + /// + /// Depending on implementation, on-demand relay may also relay `required_header` ancestors + /// (e.g. if they're mandatory), or its descendants. The request is considered complete if + /// the best avbailable header at the target chain has number that is larger than or equal + /// to the `required_header`. + async fn require_more_headers(&self, required_header: SourceHeaderNumber); +} diff --git a/relays/lib-substrate-relay/src/on_demand/parachains.rs b/relays/lib-substrate-relay/src/on_demand/parachains.rs new file mode 100644 index 0000000000..577312e16c --- /dev/null +++ b/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -0,0 +1,708 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! On-demand Substrate -> Substrate parachain finality relay. + +use crate::{ + messages_source::best_finalized_peer_header_at_self, + on_demand::OnDemandRelay, + parachains::{ + source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter, + SubstrateParachainsPipeline, + }, + TransactionParams, +}; + +use async_std::{ + channel::{unbounded, Receiver, Sender}, + sync::{Arc, Mutex}, +}; +use async_trait::async_trait; +use bp_polkadot_core::parachains::ParaHash; +use bp_runtime::HeaderIdProvider; +use futures::{select, FutureExt}; +use num_traits::Zero; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use parachains_relay::parachains_loop::{AvailableHeader, ParachainSyncParams, TargetClient}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, + TransactionSignScheme, +}; +use relay_utils::{ + metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, HeaderId, +}; +use std::fmt::Debug; + +/// On-demand Substrate <-> Substrate parachain finality relay. +/// +/// This relay may be requested to sync more parachain headers, whenever some other relay +/// (e.g. messages relay) needs it to continue its regular work. When enough parachain headers +/// are relayed, on-demand stops syncing headers. +#[derive(Clone)] +pub struct OnDemandParachainsRelay { + /// Relay task name. + relay_task_name: String, + /// Channel used to communicate with background task and ask for relay of parachain heads. + required_header_number_sender: Sender>, +} + +impl OnDemandParachainsRelay { + /// Create new on-demand parachains relay. + /// + /// Note that the argument is the source relay chain client, not the parachain client. + /// That's because parachain finality is determined by the relay chain and we don't + /// need to connect to the parachain itself here. + pub fn new>( + source_relay_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + on_demand_source_relay_to_target_headers: Arc< + dyn OnDemandRelay>, + >, + ) -> Self + where + P::SourceParachain: Chain, + P::SourceRelayChain: + Chain, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, + { + let (required_header_number_sender, required_header_number_receiver) = unbounded(); + let this = OnDemandParachainsRelay { + relay_task_name: on_demand_parachains_relay_name::(), + required_header_number_sender, + }; + async_std::task::spawn(async move { + background_task::

( + source_relay_client, + target_client, + target_transaction_params, + on_demand_source_relay_to_target_headers, + required_header_number_receiver, + ) + .await; + }); + + this + } +} + +#[async_trait] +impl OnDemandRelay> + for OnDemandParachainsRelay +where + SourceParachain: Chain, +{ + async fn require_more_headers(&self, required_header: BlockNumberOf) { + if let Err(e) = self.required_header_number_sender.send(required_header).await { + log::trace!( + target: "bridge", + "[{}] Failed to request {} header {:?}: {:?}", + self.relay_task_name, + SourceParachain::NAME, + required_header, + e, + ); + } + } +} + +/// Background task that is responsible for starting parachain headers relay. +async fn background_task( + source_relay_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + on_demand_source_relay_to_target_headers: Arc< + dyn OnDemandRelay>, + >, + required_parachain_header_number_receiver: Receiver>, +) where + P::SourceParachain: Chain, + P::SourceRelayChain: + Chain, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, +{ + let relay_task_name = on_demand_parachains_relay_name::(); + let target_transactions_mortality = target_transaction_params.mortality; + + let mut relay_state = RelayState::Idle; + let mut required_parachain_header_number = Zero::zero(); + let required_para_header_number_ref = Arc::new(Mutex::new(AvailableHeader::Unavailable)); + + let mut restart_relay = true; + let parachains_relay_task = futures::future::Fuse::terminated(); + futures::pin_mut!(parachains_relay_task); + + let mut parachains_source = ParachainsSource::

::new( + source_relay_client.clone(), + required_para_header_number_ref.clone(), + ); + let mut parachains_target = + ParachainsTarget::

::new(target_client.clone(), target_transaction_params.clone()); + + loop { + select! { + new_required_parachain_header_number = required_parachain_header_number_receiver.recv().fuse() => { + let new_required_parachain_header_number = match new_required_parachain_header_number { + Ok(new_required_parachain_header_number) => new_required_parachain_header_number, + Err(e) => { + log::error!( + target: "bridge", + "[{}] Background task has exited with error: {:?}", + relay_task_name, + e, + ); + + return; + }, + }; + + // keep in mind that we are not updating `required_para_header_number_ref` here, because + // then we'll be submitting all previous headers as well (while required relay headers are + // delivered) and we want to avoid that (to reduce cost) + required_parachain_header_number = std::cmp::max( + required_parachain_header_number, + new_required_parachain_header_number, + ); + }, + _ = async_std::task::sleep(P::TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, + _ = parachains_relay_task => { + // this should never happen in practice given the current code + restart_relay = true; + }, + } + + // the workflow of the on-demand parachains relay is: + // + // 1) message relay (or any other dependent relay) sees new message at parachain header + // `PH`; + // + // 2) it sees that the target chain does not know `PH`; + // + // 3) it asks on-demand parachains relay to relay `PH` to the target chain; + // + // Phase#1: relaying relay chain header + // + // 4) on-demand parachains relay waits for GRANDPA-finalized block of the source relay chain + // `RH` that is storing `PH` or its descendant. Let it be `PH'`; + // 5) it asks on-demand headers relay to relay `RH` to the target chain; + // 6) it waits until `RH` (or its descendant) is relayed to the target chain; + // + // Phase#2: relaying parachain header + // + // 7) on-demand parachains relay sets `ParachainsSource::maximal_header_number` to the + // `PH'.number()`. + // 8) parachains finality relay sees that the parachain head has been + // updated and relays `PH'` to the target chain. + + // select headers to relay + let relay_data = read_relay_data( + ¶chains_source, + ¶chains_target, + required_parachain_header_number, + ) + .await; + match relay_data { + Ok(relay_data) => { + let prev_relay_state = relay_state; + relay_state = select_headers_to_relay(&relay_data, relay_state); + log::trace!( + target: "bridge", + "[{}] Selected new relay state: {:?} using old state {:?} and data {:?}", + relay_task_name, + relay_state, + prev_relay_state, + relay_data, + ); + }, + Err(failed_client) => { + relay_utils::relay_loop::reconnect_failed_client( + failed_client, + relay_utils::relay_loop::RECONNECT_DELAY, + &mut parachains_source, + &mut parachains_target, + ) + .await; + continue + }, + } + + // we have selected our new 'state' => let's notify our source clients about our new + // requirements + match relay_state { + RelayState::Idle => (), + RelayState::RelayingRelayHeader(required_relay_header) => { + on_demand_source_relay_to_target_headers + .require_more_headers(required_relay_header) + .await; + }, + RelayState::RelayingParaHeader(required_para_header) => { + *required_para_header_number_ref.lock().await = + AvailableHeader::Available(required_para_header); + }, + } + + // start/restart relay + if restart_relay { + let stall_timeout = relay_substrate_client::transaction_stall_timeout( + target_transactions_mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + relay_utils::STALL_TIMEOUT, + ); + + log::info!( + target: "bridge", + "[{}] Starting on-demand-parachains relay task\n\t\ + Tx mortality: {:?} (~{}m)\n\t\ + Stall timeout: {:?}", + relay_task_name, + target_transactions_mortality, + stall_timeout.as_secs_f64() / 60.0f64, + stall_timeout, + ); + + parachains_relay_task.set( + parachains_relay::parachains_loop::run( + parachains_source.clone(), + parachains_target.clone(), + ParachainSyncParams { + parachains: vec![P::SOURCE_PARACHAIN_PARA_ID.into()], + stall_timeout: std::time::Duration::from_secs(60), + strategy: parachains_relay::parachains_loop::ParachainSyncStrategy::Any, + }, + MetricsParams::disabled(), + futures::future::pending(), + ) + .fuse(), + ); + + restart_relay = false; + } + } +} + +/// On-demand parachains relay task name. +fn on_demand_parachains_relay_name() -> String { + format!("{}-to-{}-on-demand-parachain", SourceChain::NAME, TargetChain::NAME) +} + +/// On-demand relay state. +#[derive(Clone, Copy, Debug, PartialEq)] +enum RelayState { + /// On-demand relay is not doing anything. + Idle, + /// Relaying given relay header to relay given parachain header later. + RelayingRelayHeader(RelayNumber), + /// Relaying given parachain header. + RelayingParaHeader(HeaderId), +} + +/// Data gathered from source and target clients, used by on-demand relay. +#[derive(Debug)] +struct RelayData { + /// Parachain header number that is required at the target chain. + pub required_para_header: ParaNumber, + /// Parachain header number, known to the target chain. + pub para_header_at_target: Option, + /// Parachain header id, known to the source (relay) chain. + pub para_header_at_source: Option>, + /// Parachain header, that is available at the source relay chain at `relay_header_at_target` + /// block. + pub para_header_at_relay_header_at_target: Option>, + /// Relay header number at the source chain. + pub relay_header_at_source: RelayNumber, + /// Relay header number at the target chain. + pub relay_header_at_target: RelayNumber, +} + +/// Read required data from source and target clients. +async fn read_relay_data( + source: &ParachainsSource

, + target: &ParachainsTarget

, + required_header_number: BlockNumberOf, +) -> Result< + RelayData< + HashOf, + BlockNumberOf, + BlockNumberOf, + >, + FailedClient, +> +where + ParachainsTarget

: + TargetClient> + RelayClient, +{ + let map_target_err = |e| { + log::error!( + target: "bridge", + "[{}] Failed to read relay data from {} client: {:?}", + on_demand_parachains_relay_name::(), + P::TargetChain::NAME, + e, + ); + FailedClient::Target + }; + let map_source_err = |e| { + log::error!( + target: "bridge", + "[{}] Failed to read relay data from {} client: {:?}", + on_demand_parachains_relay_name::(), + P::SourceRelayChain::NAME, + e, + ); + FailedClient::Source + }; + + let best_target_block_hash = target.best_block().await.map_err(map_target_err)?.1; + let para_header_at_target = + best_finalized_peer_header_at_self::( + target.client(), + best_target_block_hash, + P::SourceParachain::BEST_FINALIZED_HEADER_ID_METHOD, + ) + .await; + // if there are no parachain heads at the target (`BridgePalletIsNotInitialized`), we'll need + // to submit at least one. Otherwise the pallet will be treated as uninitialized and messages + // sync will stall. + let para_header_at_target = match para_header_at_target { + Ok(para_header_at_target) => Some(para_header_at_target.0), + Err(SubstrateError::BridgePalletIsNotInitialized) => None, + Err(e) => return Err(map_target_err(e)), + }; + + let best_finalized_relay_header = + source.client().best_finalized_header().await.map_err(map_source_err)?; + let best_finalized_relay_block_id = best_finalized_relay_header.id(); + let para_header_at_source = source + .on_chain_para_head_id(best_finalized_relay_block_id, P::SOURCE_PARACHAIN_PARA_ID.into()) + .await + .map_err(map_source_err)?; + + let relay_header_at_source = best_finalized_relay_block_id.0; + let relay_header_at_target = + best_finalized_peer_header_at_self::( + target.client(), + best_target_block_hash, + P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD, + ) + .await + .map_err(map_target_err)?; + + let para_header_at_relay_header_at_target = source + .on_chain_para_head_id(relay_header_at_target, P::SOURCE_PARACHAIN_PARA_ID.into()) + .await + .map_err(map_source_err)?; + + Ok(RelayData { + required_para_header: required_header_number, + para_header_at_target, + para_header_at_source, + relay_header_at_source, + relay_header_at_target: relay_header_at_target.0, + para_header_at_relay_header_at_target, + }) +} + +/// Select relay and parachain headers that need to be relayed. +fn select_headers_to_relay( + data: &RelayData, + mut state: RelayState, +) -> RelayState +where + ParaHash: Clone, + ParaNumber: Copy + PartialOrd + Zero, + RelayNumber: Copy + Debug + Ord, +{ + // Process the `RelayingRelayHeader` state. + if let &RelayState::RelayingRelayHeader(relay_header_number) = &state { + if data.relay_header_at_target < relay_header_number { + // The required relay header hasn't yet been relayed. Ask / wait for it. + return state + } + + // We may switch to `RelayingParaHeader` if parachain head is available. + state = data + .para_header_at_relay_header_at_target + .clone() + .map_or(RelayState::Idle, RelayState::RelayingParaHeader); + } + + // Process the `RelayingParaHeader` state. + if let RelayState::RelayingParaHeader(para_header_id) = &state { + let para_header_at_target_or_zero = data.para_header_at_target.unwrap_or_else(Zero::zero); + if para_header_at_target_or_zero < para_header_id.0 { + // The required parachain header hasn't yet been relayed. Ask / wait for it. + return state + } + } + + // if we haven't read para head from the source, we can't yet do anything + let para_header_at_source = match data.para_header_at_source { + Some(ref para_header_at_source) => para_header_at_source.clone(), + None => return RelayState::Idle, + }; + + // if we have parachain head at the source, but no parachain heads at the target, we'll need + // to deliver at least one parachain head + let (required_para_header, para_header_at_target) = match data.para_header_at_target { + Some(para_header_at_target) => (data.required_para_header, para_header_at_target), + None => (para_header_at_source.0, Zero::zero()), + }; + + // if we have already satisfied our "customer", do nothing + if required_para_header <= para_header_at_target { + return RelayState::Idle + } + + // if required header is not available even at the source chain, let's wait + if required_para_header > para_header_at_source.0 { + return RelayState::Idle + } + + // we will always try to sync latest parachain/relay header, even if we've been asked for some + // its ancestor + + // we need relay chain header first + if data.relay_header_at_target < data.relay_header_at_source { + return RelayState::RelayingRelayHeader(data.relay_header_at_source) + } + + // if all relay headers synced, we may start directly with parachain header + RelayState::RelayingParaHeader(para_header_at_source) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn relay_waits_for_relay_header_to_be_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: 700, + para_header_at_relay_header_at_target: Some(HeaderId(100, 100)), + }, + RelayState::RelayingRelayHeader(750), + ), + RelayState::RelayingRelayHeader(750), + ); + } + + #[test] + fn relay_starts_relaying_requested_para_header_after_relay_header_is_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: 750, + para_header_at_relay_header_at_target: Some(HeaderId(100, 100)), + }, + RelayState::RelayingRelayHeader(750), + ), + RelayState::RelayingParaHeader(HeaderId(100, 100)), + ); + } + + #[test] + fn relay_selects_better_para_header_after_better_relay_header_is_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: 780, + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::RelayingRelayHeader(750), + ), + RelayState::RelayingParaHeader(HeaderId(105, 105)), + ); + } + #[test] + fn relay_waits_for_para_header_to_be_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: 780, + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::RelayingParaHeader(HeaderId(105, 105)), + ), + RelayState::RelayingParaHeader(HeaderId(105, 105)), + ); + } + + #[test] + fn relay_stays_idle_if_required_para_header_is_already_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: 780, + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_waits_for_required_para_header_to_appear_at_source_1() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: None, + relay_header_at_source: 800, + relay_header_at_target: 780, + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_waits_for_required_para_header_to_appear_at_source_2() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: 780, + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_starts_relaying_relay_header_when_new_para_header_is_requested() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: 780, + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::RelayingRelayHeader(800), + ); + } + + #[test] + fn relay_starts_relaying_para_header_when_new_para_header_is_requested() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: 800, + para_header_at_relay_header_at_target: Some(HeaderId(125, 125)), + }, + RelayState::Idle, + ), + RelayState::RelayingParaHeader(HeaderId(125, 125)), + ); + } + + #[test] + fn relay_goes_idle_when_parachain_is_deregistered() { + assert_eq!( + select_headers_to_relay::( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: None, + relay_header_at_source: 800, + relay_header_at_target: 800, + para_header_at_relay_header_at_target: None, + }, + RelayState::RelayingRelayHeader(800), + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_starts_relaying_first_parachain_header() { + assert_eq!( + select_headers_to_relay::( + &RelayData { + required_para_header: 0, + para_header_at_target: None, + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: 800, + para_header_at_relay_header_at_target: Some(HeaderId(125, 125)), + }, + RelayState::Idle, + ), + RelayState::RelayingParaHeader(HeaderId(125, 125)), + ); + } + + #[test] + fn relay_starts_relaying_relay_header_to_relay_first_parachain_header() { + assert_eq!( + select_headers_to_relay::( + &RelayData { + required_para_header: 0, + para_header_at_target: None, + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: 700, + para_header_at_relay_header_at_target: Some(HeaderId(125, 125)), + }, + RelayState::Idle, + ), + RelayState::RelayingRelayHeader(800), + ); + } +} diff --git a/relays/lib-substrate-relay/src/parachains/mod.rs b/relays/lib-substrate-relay/src/parachains/mod.rs new file mode 100644 index 0000000000..f201476aa1 --- /dev/null +++ b/relays/lib-substrate-relay/src/parachains/mod.rs @@ -0,0 +1,110 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! parachain finality proofs synchronization pipelines. + +use async_trait::async_trait; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use pallet_bridge_parachains::{ + Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, + RelayBlockHasher, RelayBlockNumber, +}; +use parachains_relay::ParachainsPipeline; +use relay_substrate_client::{CallOf, Chain, HeaderIdOf, RelayChain, TransactionSignScheme}; +use std::{fmt::Debug, marker::PhantomData}; + +pub mod source; +pub mod target; + +/// Substrate -> Substrate parachain finality proofs synchronization pipeline. +/// +/// This is currently restricted to the single parachain, because it is how it +/// will be used (at least) initially. +#[async_trait] +pub trait SubstrateParachainsPipeline: 'static + Clone + Debug + Send + Sync { + /// Headers of this parachain are submitted to the `Self::TargetChain`. + type SourceParachain: Chain; + /// Relay chain that is storing headers of `Self::SourceParachain`. + type SourceRelayChain: RelayChain; + /// Target chain where `Self::SourceParachain` headers are submitted. + type TargetChain: Chain; + + /// How submit parachains heads call is built? + type SubmitParachainHeadsCallBuilder: SubmitParachainHeadsCallBuilder; + /// Scheme used to sign target chain transactions. + type TransactionSignScheme: TransactionSignScheme; + + /// Id of the `Self::SourceParachain`, used for registration in `Self::SourceRelayChain`. + const SOURCE_PARACHAIN_PARA_ID: u32; +} + +/// Adapter that allows all `SubstrateParachainsPipeline` to act as `ParachainsPipeline`. +#[derive(Clone, Debug)] +pub struct ParachainsPipelineAdapter { + _phantom: PhantomData

, +} + +impl ParachainsPipeline for ParachainsPipelineAdapter

{ + type SourceChain = P::SourceRelayChain; + type TargetChain = P::TargetChain; +} + +/// Different ways of building `submit_parachain_heads` calls. +pub trait SubmitParachainHeadsCallBuilder: + 'static + Send + Sync +{ + /// Given parachains and their heads proof, build call of `submit_parachain_heads` + /// function of bridge parachains module at the target chain. + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf; +} + +/// Building `submit_parachain_heads` call when you have direct access to the target +/// chain runtime. +pub struct DirectSubmitParachainHeadsCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl SubmitParachainHeadsCallBuilder

for DirectSubmitParachainHeadsCallBuilder +where + P: SubstrateParachainsPipeline, + P::SourceRelayChain: Chain, + R: BridgeParachainsConfig + Send + Sync, + I: 'static + Send + Sync, + R::BridgedChain: bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, + CallOf: From>, +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf { + BridgeParachainsCall::::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + } + .into() + } +} diff --git a/relays/lib-substrate-relay/src/parachains/source.rs b/relays/lib-substrate-relay/src/parachains/source.rs new file mode 100644 index 0000000000..c23ac87947 --- /dev/null +++ b/relays/lib-substrate-relay/src/parachains/source.rs @@ -0,0 +1,188 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Parachain heads source. + +use crate::parachains::{ParachainsPipelineAdapter, SubstrateParachainsPipeline}; + +use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; +use bp_parachains::parachain_head_storage_key_at_source; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use bp_runtime::HeaderIdProvider; +use codec::Decode; +use parachains_relay::{ + parachains_loop::{AvailableHeader, SourceClient}, + parachains_loop_metrics::ParachainsLoopMetrics, +}; +use relay_substrate_client::{ + Chain, Client, Error as SubstrateError, HeaderIdOf, HeaderOf, RelayChain, +}; +use relay_utils::relay_loop::Client as RelayClient; + +/// Shared updatable reference to the maximal parachain header id that we want to sync from the +/// source. +pub type RequiredHeaderIdRef = Arc>>>; + +/// Substrate client as parachain heads source. +#[derive(Clone)] +pub struct ParachainsSource { + client: Client, + max_head_id: RequiredHeaderIdRef, +} + +impl ParachainsSource

{ + /// Creates new parachains source client. + pub fn new( + client: Client, + max_head_id: RequiredHeaderIdRef, + ) -> Self { + ParachainsSource { client, max_head_id } + } + + /// Returns reference to the underlying RPC client. + pub fn client(&self) -> &Client { + &self.client + } + + /// Return decoded head of given parachain. + pub async fn on_chain_para_head_id( + &self, + at_block: HeaderIdOf, + para_id: ParaId, + ) -> Result>, SubstrateError> { + let storage_key = + parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, para_id); + let para_head = self.client.raw_storage_value(storage_key, Some(at_block.1)).await?; + let para_head = para_head.map(|h| ParaHead::decode(&mut &h.0[..])).transpose()?; + let para_head = match para_head { + Some(para_head) => para_head, + None => return Ok(None), + }; + let para_head: HeaderOf = Decode::decode(&mut ¶_head.0[..])?; + Ok(Some(para_head.id())) + } +} + +#[async_trait] +impl RelayClient for ParachainsSource

{ + type Error = SubstrateError; + + async fn reconnect(&mut self) -> Result<(), SubstrateError> { + self.client.reconnect().await + } +} + +#[async_trait] +impl SourceClient> + for ParachainsSource

+where + P::SourceParachain: Chain, +{ + async fn ensure_synced(&self) -> Result { + match self.client.ensure_synced().await { + Ok(_) => Ok(true), + Err(SubstrateError::ClientNotSynced(_)) => Ok(false), + Err(e) => Err(e), + } + } + + async fn parachain_head( + &self, + at_block: HeaderIdOf, + metrics: Option<&ParachainsLoopMetrics>, + para_id: ParaId, + ) -> Result, Self::Error> { + // we don't need to support many parachains now + if para_id.0 != P::SOURCE_PARACHAIN_PARA_ID { + return Err(SubstrateError::Custom(format!( + "Parachain id {} is not matching expected {}", + para_id.0, + P::SOURCE_PARACHAIN_PARA_ID, + ))) + } + + let mut para_head_id = AvailableHeader::Missing; + if let Some(on_chain_para_head_id) = self.on_chain_para_head_id(at_block, para_id).await? { + // Never return head that is larger than requested. This way we'll never sync + // headers past `max_header_id`. + para_head_id = match *self.max_head_id.lock().await { + AvailableHeader::Unavailable => AvailableHeader::Unavailable, + AvailableHeader::Missing => { + // `max_header_id` is not set. There is no limit. + AvailableHeader::Available(on_chain_para_head_id) + }, + AvailableHeader::Available(max_head_id) => { + // We report at most `max_header_id`. + AvailableHeader::Available(std::cmp::min(on_chain_para_head_id, max_head_id)) + }, + } + } + + if let (Some(metrics), AvailableHeader::Available(para_head_id)) = (metrics, para_head_id) { + metrics.update_best_parachain_block_at_source(para_id, para_head_id.0); + } + + Ok(para_head_id.map(|para_head_id| para_head_id.1)) + } + + async fn prove_parachain_heads( + &self, + at_block: HeaderIdOf, + parachains: &[ParaId], + ) -> Result<(ParaHeadsProof, Vec), Self::Error> { + let parachain = ParaId(P::SOURCE_PARACHAIN_PARA_ID); + if parachains != [parachain] { + return Err(SubstrateError::Custom(format!( + "Trying to prove unexpected parachains {:?}. Expected {:?}", + parachains, parachain, + ))) + } + + let parachain = parachains[0]; + let storage_key = + parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, parachain); + let parachain_heads_proof = self + .client + .prove_storage(vec![storage_key.clone()], at_block.1) + .await? + .iter_nodes() + .collect(); + + // why we're reading parachain head here once again (it has already been read at the + // `parachain_head`)? that's because `parachain_head` sometimes returns obsolete parachain + // head and loop sometimes asks to prove this obsolete head and gets other (actual) head + // instead + // + // => since we want to provide proper hashes in our `submit_parachain_heads` call, we're + // rereading actual value here + let parachain_head = self + .client + .raw_storage_value(storage_key, Some(at_block.1)) + .await? + .map(|h| ParaHead::decode(&mut &h.0[..])) + .transpose()? + .ok_or_else(|| { + SubstrateError::Custom(format!( + "Failed to read expected parachain {:?} head at {:?}", + parachain, at_block + )) + })?; + let parachain_head_hash = parachain_head.hash(); + + Ok((ParaHeadsProof(parachain_heads_proof), vec![parachain_head_hash])) + } +} diff --git a/relays/lib-substrate-relay/src/parachains/target.rs b/relays/lib-substrate-relay/src/parachains/target.rs new file mode 100644 index 0000000000..fa159cdeb7 --- /dev/null +++ b/relays/lib-substrate-relay/src/parachains/target.rs @@ -0,0 +1,201 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Parachain heads target. + +use crate::{ + parachains::{ + ParachainsPipelineAdapter, SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, + }, + TransactionParams, +}; + +use async_trait::async_trait; +use bp_parachains::{BestParaHeadHash, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use bp_runtime::HeaderIdProvider; +use codec::Decode; +use parachains_relay::{ + parachains_loop::TargetClient, parachains_loop_metrics::ParachainsLoopMetrics, +}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, + HeaderIdOf, HeaderOf, RelayChain, SignParam, TransactionEra, TransactionSignScheme, + UnsignedTransaction, +}; +use relay_utils::{relay_loop::Client as RelayClient, HeaderId}; +use sp_core::{Bytes, Pair}; +use sp_runtime::traits::Header as HeaderT; + +/// Substrate client as parachain heads source. +pub struct ParachainsTarget { + client: Client, + transaction_params: TransactionParams>, +} + +impl ParachainsTarget

{ + /// Creates new parachains target client. + pub fn new( + client: Client, + transaction_params: TransactionParams>, + ) -> Self { + ParachainsTarget { client, transaction_params } + } + + /// Returns reference to the underlying RPC client. + pub fn client(&self) -> &Client { + &self.client + } +} + +impl Clone for ParachainsTarget

{ + fn clone(&self) -> Self { + ParachainsTarget { + client: self.client.clone(), + transaction_params: self.transaction_params.clone(), + } + } +} + +#[async_trait] +impl RelayClient for ParachainsTarget

{ + type Error = SubstrateError; + + async fn reconnect(&mut self) -> Result<(), SubstrateError> { + self.client.reconnect().await + } +} + +#[async_trait] +impl

TargetClient> for ParachainsTarget

+where + P: SubstrateParachainsPipeline, + P::TransactionSignScheme: TransactionSignScheme, + AccountIdOf: From< as Pair>::Public>, +{ + async fn best_block(&self) -> Result, Self::Error> { + let best_header = self.client.best_header().await?; + let best_id = best_header.id(); + + Ok(best_id) + } + + async fn best_finalized_source_block( + &self, + at_block: &HeaderIdOf, + ) -> Result, Self::Error> { + let encoded_best_finalized_source_block = self + .client + .state_call( + P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), + Bytes(Vec::new()), + Some(at_block.1), + ) + .await?; + + Option::, BlockNumberOf>>::decode( + &mut &encoded_best_finalized_source_block.0[..], + ) + .map_err(SubstrateError::ResponseParseFailed)? + .map(Ok) + .unwrap_or(Err(SubstrateError::BridgePalletIsNotInitialized)) + } + + async fn parachain_head( + &self, + at_block: HeaderIdOf, + metrics: Option<&ParachainsLoopMetrics>, + para_id: ParaId, + ) -> Result, Self::Error> { + let best_para_head_hash: Option = self + .client + .storage_map_value::( + P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME, + ¶_id, + Some(at_block.1), + ) + .await? + .map(|para_info| para_info.best_head_hash); + + if let (Some(metrics), &Some(ref best_para_head_hash)) = (metrics, &best_para_head_hash) { + let imported_para_head = self + .client + .storage_double_map_value::( + P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME, + ¶_id, + &best_para_head_hash.head_hash, + Some(at_block.1), + ) + .await + .and_then(|maybe_encoded_head| match maybe_encoded_head { + Some(encoded_head) => + HeaderOf::::decode(&mut &encoded_head.0[..]) + .map(Some) + .map_err(Self::Error::ResponseParseFailed), + None => Ok(None), + }) + .map_err(|e| { + log::error!( + target: "bridge-metrics", + "Failed to read or decode {} parachain header at {}: {:?}. Metric will have obsolete value", + P::SourceParachain::NAME, + P::TargetChain::NAME, + e, + ); + e + }) + .unwrap_or(None); + if let Some(imported_para_head) = imported_para_head { + metrics + .update_best_parachain_block_at_target(para_id, *imported_para_head.number()); + } + } + + Ok(best_para_head_hash) + } + + async fn submit_parachain_heads_proof( + &self, + at_relay_block: HeaderIdOf, + updated_parachains: Vec<(ParaId, ParaHash)>, + proof: ParaHeadsProof, + ) -> Result<(), Self::Error> { + let genesis_hash = *self.client.genesis_hash(); + let transaction_params = self.transaction_params.clone(); + let (spec_version, transaction_version) = self.client.simple_runtime_version().await?; + let call = P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call( + at_relay_block, + updated_parachains, + proof, + ); + self.client + .submit_signed_extrinsic( + self.transaction_params.signer.public().into(), + SignParam:: { + spec_version, + transaction_version, + genesis_hash, + signer: transaction_params.signer, + }, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) + .await + .map(drop) + } +} diff --git a/relays/messages/Cargo.toml b/relays/messages/Cargo.toml index b3357994b1..02e453b1c3 100644 --- a/relays/messages/Cargo.toml +++ b/relays/messages/Cargo.toml @@ -7,10 +7,10 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-std = { version = "1.6.5", features = ["attributes"] } -async-trait = "0.1.40" +async-trait = "0.1" futures = "0.3.5" hex = "0.4" -log = "0.4.11" +log = "0.4.17" num-traits = "0.2" parking_lot = "0.11.0" diff --git a/relays/messages/src/message_lane_loop.rs b/relays/messages/src/message_lane_loop.rs index c1778d5d11..bd7a7de829 100644 --- a/relays/messages/src/message_lane_loop.rs +++ b/relays/messages/src/message_lane_loop.rs @@ -62,7 +62,7 @@ pub struct Params { } /// Relayer operating mode. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RelayerMode { /// The relayer doesn't care about rewards. Altruistic, @@ -94,7 +94,7 @@ pub struct MessageDeliveryParams { } /// Message details. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MessageDetails { /// Message dispatch weight. pub dispatch_weight: Weight, @@ -111,7 +111,7 @@ pub type MessageDetailsMap = BTreeMap>; /// Message delivery race proof parameters. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct MessageProofParameters { /// Include outbound lane state proof? pub outbound_state_proof_required: bool, @@ -224,7 +224,7 @@ pub trait TargetClient: RelayClient { } /// State of the client. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct ClientState { /// The best header id of this chain. pub best_self: SelfHeaderId, @@ -271,7 +271,11 @@ pub async fn run( relay_utils::relay_loop(source_client, target_client) .reconnect_delay(params.reconnect_delay) .with_metrics(metrics_params) - .loop_metric(MessageLaneLoopMetrics::new(Some(&metrics_prefix::

(¶ms.lane)))?)? + .loop_metric(MessageLaneLoopMetrics::new( + Some(&metrics_prefix::

(¶ms.lane)), + P::SOURCE_NAME, + P::TARGET_NAME, + )?)? .expose() .await? .run(metrics_prefix::

(¶ms.lane), move |source_client, target_client, metrics| { @@ -556,7 +560,7 @@ pub(crate) mod tests { async fn reconnect(&mut self) -> Result<(), TestError> { { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); data.is_source_reconnected = true; } Ok(()) @@ -567,7 +571,7 @@ pub(crate) mod tests { impl SourceClient for TestSourceClient { async fn state(&self) -> Result, TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_source_fails { return Err(TestError) } @@ -579,7 +583,7 @@ pub(crate) mod tests { id: SourceHeaderIdOf, ) -> Result<(SourceHeaderIdOf, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_source_fails { return Err(TestError) } @@ -591,7 +595,7 @@ pub(crate) mod tests { id: SourceHeaderIdOf, ) -> Result<(SourceHeaderIdOf, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); Ok((id, data.source_latest_confirmed_received_nonce)) } @@ -625,7 +629,7 @@ pub(crate) mod tests { TestError, > { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); Ok(( id, nonces.clone(), @@ -646,7 +650,7 @@ pub(crate) mod tests { proof: TestMessagesReceivingProof, ) -> Result<(), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); data.source_state.best_self = HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); data.source_state.best_finalized_self = data.source_state.best_self; @@ -659,7 +663,7 @@ pub(crate) mod tests { let mut data = self.data.lock(); data.target_to_source_header_required = Some(id); data.target_to_source_header_requirements.push(id); - (self.tick)(&mut *data); + (self.tick)(&mut data); } async fn estimate_confirmation_transaction(&self) -> TestSourceChainBalance { @@ -689,7 +693,7 @@ pub(crate) mod tests { async fn reconnect(&mut self) -> Result<(), TestError> { { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); data.is_target_reconnected = true; } Ok(()) @@ -700,7 +704,7 @@ pub(crate) mod tests { impl TargetClient for TestTargetClient { async fn state(&self) -> Result, TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -712,7 +716,7 @@ pub(crate) mod tests { id: TargetHeaderIdOf, ) -> Result<(TargetHeaderIdOf, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -729,6 +733,7 @@ pub(crate) mod tests { unrewarded_relayer_entries: 0, messages_in_oldest_entry: 0, total_messages: 0, + last_delivered_nonce: 0, }, )) } @@ -738,7 +743,7 @@ pub(crate) mod tests { id: TargetHeaderIdOf, ) -> Result<(TargetHeaderIdOf, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -759,7 +764,7 @@ pub(crate) mod tests { proof: TestMessagesProof, ) -> Result, TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -779,7 +784,7 @@ pub(crate) mod tests { let mut data = self.data.lock(); data.source_to_target_header_required = Some(id); data.source_to_target_header_requirements.push(id); - (self.tick)(&mut *data); + (self.tick)(&mut data); } async fn estimate_delivery_transaction_in_source_tokens( diff --git a/relays/messages/src/message_race_delivery.rs b/relays/messages/src/message_race_delivery.rs index dc994364f1..85f6d955e7 100644 --- a/relays/messages/src/message_race_delivery.rs +++ b/relays/messages/src/message_race_delivery.rs @@ -56,7 +56,7 @@ pub async fn run( source_state_updates, MessageDeliveryRaceTarget { client: target_client.clone(), - metrics_msg, + metrics_msg: metrics_msg.clone(), _phantom: Default::default(), }, target_state_updates, @@ -74,6 +74,7 @@ pub async fn run( latest_confirmed_nonces_at_source: VecDeque::new(), target_nonces: None, strategy: BasicStrategy::new(), + metrics_msg, }, ) .await @@ -255,6 +256,8 @@ struct MessageDeliveryStrategy target_nonces: Option>, /// Basic delivery strategy. strategy: MessageDeliveryStrategyBase

, + /// Message lane metrics. + metrics_msg: Option, } type MessageDeliveryStrategyBase

= BasicStrategy< @@ -519,6 +522,7 @@ where lane_target_client: lane_target_client.clone(), nonces_queue: source_queue.clone(), nonces_queue_range: 0..maximal_source_queue_index + 1, + metrics: self.metrics_msg.clone(), }; let mut strategy = EnforcementStrategy::new(self.relay_strategy.clone()); @@ -631,6 +635,7 @@ mod tests { latest_confirmed_nonces_at_source: vec![(header_id(1), 19)].into_iter().collect(), lane_source_client: TestSourceClient::default(), lane_target_client: TestTargetClient::default(), + metrics_msg: None, target_nonces: Some(TargetClientNonces { latest_nonce: 19, nonces_data: DeliveryRaceTargetNoncesData { @@ -639,6 +644,7 @@ mod tests { unrewarded_relayer_entries: 0, messages_in_oldest_entry: 0, total_messages: 0, + last_delivered_nonce: 0, }, }, }), @@ -954,6 +960,7 @@ mod tests { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 2, total_messages: 2, + last_delivered_nonce: 19, }, }, }, diff --git a/relays/messages/src/metrics.rs b/relays/messages/src/metrics.rs index 4decb7e092..f5cc8831c0 100644 --- a/relays/messages/src/metrics.rs +++ b/relays/messages/src/metrics.rs @@ -24,7 +24,7 @@ use crate::{ use bp_messages::MessageNonce; use finality_relay::SyncLoopMetrics; use relay_utils::metrics::{ - metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, + metric_name, register, Counter, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, }; /// Message lane relay metrics. @@ -39,11 +39,17 @@ pub struct MessageLaneLoopMetrics { /// Lane state nonces: "source_latest_generated", "source_latest_confirmed", /// "target_latest_received", "target_latest_confirmed". lane_state_nonces: GaugeVec, + /// Count of unprofitable message delivery transactions that we have submitted so far. + unprofitable_delivery_transactions: Counter, } impl MessageLaneLoopMetrics { /// Create and register messages loop metrics. - pub fn new(prefix: Option<&str>) -> Result { + pub fn new( + prefix: Option<&str>, + source_name: &str, + target_name: &str, + ) -> Result { Ok(MessageLaneLoopMetrics { source_to_target_finality_metrics: SyncLoopMetrics::new( prefix, @@ -59,6 +65,13 @@ impl MessageLaneLoopMetrics { Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"), &["type"], )?, + unprofitable_delivery_transactions: Counter::new( + metric_name(prefix, "unprofitable_delivery_transactions"), + format!( + "Count of unprofitable message delivery transactions from {} to {}", + source_name, target_name + ), + )?, }) } @@ -127,6 +140,11 @@ impl MessageLaneLoopMetrics { .with_label_values(&["target_latest_confirmed"]) .set(target_latest_confirmed_nonce); } + + /// Note unprofitable delivery transaction. + pub fn note_unprofitable_delivery_transactions(&self) { + self.unprofitable_delivery_transactions.inc() + } } impl Metric for MessageLaneLoopMetrics { @@ -134,6 +152,7 @@ impl Metric for MessageLaneLoopMetrics { self.source_to_target_finality_metrics.register(registry)?; self.target_to_source_finality_metrics.register(registry)?; register(self.lane_state_nonces.clone(), registry)?; + register(self.unprofitable_delivery_transactions.clone(), registry)?; Ok(()) } } diff --git a/relays/messages/src/relay_strategy/altruistic_strategy.rs b/relays/messages/src/relay_strategy/altruistic_strategy.rs index d6fec7f129..7e00678e13 100644 --- a/relays/messages/src/relay_strategy/altruistic_strategy.rs +++ b/relays/messages/src/relay_strategy/altruistic_strategy.rs @@ -38,8 +38,44 @@ impl RelayStrategy for AltruisticStrategy { TargetClient: MessageLaneTargetClient

, >( &mut self, - _reference: &mut RelayReference, + reference: &mut RelayReference, ) -> bool { + // We don't care about costs and rewards, but we want to report unprofitable transactions. + if let Err(e) = reference.update_cost_and_reward().await { + log::debug!( + target: "bridge", + "Failed to update transaction cost and reward: {:?}. \ + The `unprofitable_delivery_transactions` metric will be inaccurate", + e, + ); + } + true } + + fn on_final_decision< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, + >( + &self, + reference: &RelayReference, + ) { + if let Some(ref metrics) = reference.metrics { + if !reference.is_profitable() { + log::debug!( + target: "bridge", + "The relayer has submitted unprofitable {} -> {} message delivery transaction \ + with {} messages: total cost = {:?}, total reward = {:?}", + P::SOURCE_NAME, + P::TARGET_NAME, + reference.index + 1, + reference.total_cost, + reference.total_reward, + ); + + metrics.note_unprofitable_delivery_transactions(); + } + } + } } diff --git a/relays/messages/src/relay_strategy/enforcement_strategy.rs b/relays/messages/src/relay_strategy/enforcement_strategy.rs index 1e9ef5bdbf..bb4192d45a 100644 --- a/relays/messages/src/relay_strategy/enforcement_strategy.rs +++ b/relays/messages/src/relay_strategy/enforcement_strategy.rs @@ -65,6 +65,7 @@ impl EnforcementStrategy { let mut relay_reference = RelayReference { lane_source_client: reference.lane_source_client.clone(), lane_target_client: reference.lane_target_client.clone(), + metrics: reference.metrics.clone(), selected_reward: P::SourceChainBalance::zero(), selected_cost: P::SourceChainBalance::zero(), @@ -211,7 +212,10 @@ impl EnforcementStrategy { ); } - Some(hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1) + let selected_max_nonce = + hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1; + self.strategy.on_final_decision(&relay_reference); + Some(selected_max_nonce) } else { None } diff --git a/relays/messages/src/relay_strategy/mix_strategy.rs b/relays/messages/src/relay_strategy/mix_strategy.rs index 4ac7fe1d0e..331f77b012 100644 --- a/relays/messages/src/relay_strategy/mix_strategy.rs +++ b/relays/messages/src/relay_strategy/mix_strategy.rs @@ -55,4 +55,18 @@ impl RelayStrategy for MixStrategy { RelayerMode::Rational => RationalStrategy.decide(reference).await, } } + + fn on_final_decision< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, + >( + &self, + reference: &RelayReference, + ) { + match self.relayer_mode { + RelayerMode::Altruistic => AltruisticStrategy.on_final_decision(reference), + RelayerMode::Rational => RationalStrategy.on_final_decision(reference), + } + } } diff --git a/relays/messages/src/relay_strategy/mod.rs b/relays/messages/src/relay_strategy/mod.rs index d902bd93e5..7bfd74c479 100644 --- a/relays/messages/src/relay_strategy/mod.rs +++ b/relays/messages/src/relay_strategy/mod.rs @@ -16,11 +16,10 @@ //! Relayer strategy -use std::ops::Range; - use async_trait::async_trait; - use bp_messages::{MessageNonce, Weight}; +use sp_arithmetic::traits::Saturating; +use std::ops::Range; use crate::{ message_lane::MessageLane, @@ -29,6 +28,7 @@ use crate::{ TargetClient as MessageLaneTargetClient, }, message_race_strategy::SourceRangesQueue, + metrics::MessageLaneLoopMetrics, }; pub(crate) use self::enforcement_strategy::*; @@ -55,6 +55,24 @@ pub trait RelayStrategy: 'static + Clone + Send + Sync { &mut self, reference: &mut RelayReference, ) -> bool; + + /// Notification that the following maximal nonce has been selected for the delivery. + fn on_final_decision< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, + >( + &self, + reference: &RelayReference, + ); +} + +/// Total cost of mesage delivery and confirmation. +struct MessagesDeliveryCost { + /// Cost of message delivery transaction. + pub delivery_transaction_cost: SourceChainBalance, + /// Cost of confirmation delivery transaction. + pub confirmation_transaction_cost: SourceChainBalance, } /// Reference data for participating in relay @@ -67,6 +85,8 @@ pub struct RelayReference< pub lane_source_client: SourceClient, /// The client that is connected to the message lane target node. pub lane_target_client: TargetClient, + /// Metrics reference. + pub metrics: Option, /// Current block reward summary pub selected_reward: P::SourceChainBalance, /// Current block cost summary @@ -96,6 +116,85 @@ pub struct RelayReference< pub details: MessageDetails, } +impl< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, + > RelayReference +{ + /// Returns whether the current `RelayReference` is profitable. + pub fn is_profitable(&self) -> bool { + self.total_reward >= self.total_cost + } + + async fn estimate_messages_delivery_cost( + &self, + ) -> Result, TargetClient::Error> { + // technically, multiple confirmations will be delivered in a single transaction, + // meaning less loses for relayer. But here we don't know the final relayer yet, so + // we're adding a separate transaction for every message. Normally, this cost is covered + // by the message sender. Probably reconsider this? + let confirmation_transaction_cost = + self.lane_source_client.estimate_confirmation_transaction().await; + + let delivery_transaction_cost = self + .lane_target_client + .estimate_delivery_transaction_in_source_tokens( + self.hard_selected_begin_nonce..= + (self.hard_selected_begin_nonce + self.index as MessageNonce), + self.selected_prepaid_nonces, + self.selected_unpaid_weight, + self.selected_size as u32, + ) + .await?; + + Ok(MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost }) + } + + async fn update_cost_and_reward(&mut self) -> Result<(), TargetClient::Error> { + let prev_is_profitable = self.is_profitable(); + let prev_total_cost = self.total_cost; + let prev_total_reward = self.total_reward; + + let MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost } = + self.estimate_messages_delivery_cost().await?; + self.total_confirmations_cost = + self.total_confirmations_cost.saturating_add(confirmation_transaction_cost); + self.total_reward = self.total_reward.saturating_add(self.details.reward); + self.total_cost = self.total_confirmations_cost.saturating_add(delivery_transaction_cost); + + if prev_is_profitable && !self.is_profitable() { + // if it is the first message that makes reward less than cost, let's log it + log::debug!( + target: "bridge", + "Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it larger than \ + total reward {:?}->{:?}", + self.nonce, + self.details.reward, + prev_total_cost, + self.total_cost, + prev_total_reward, + self.total_reward, + ); + } else if !prev_is_profitable && self.is_profitable() { + // if this message makes batch profitable again, let's log it + log::debug!( + target: "bridge", + "Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it less than or \ + equal to the total reward {:?}->{:?} (again)", + self.nonce, + self.details.reward, + prev_total_cost, + self.total_cost, + prev_total_reward, + self.total_reward, + ); + } + + Ok(()) + } +} + /// Relay reference data pub struct RelayMessagesBatchReference< P: MessageLane, @@ -112,6 +211,8 @@ pub struct RelayMessagesBatchReference< pub lane_source_client: SourceClient, /// The client that is connected to the message lane target node. pub lane_target_client: TargetClient, + /// Metrics reference. + pub metrics: Option, /// Source queue. pub nonces_queue: SourceRangesQueue< P::SourceHeaderHash, diff --git a/relays/messages/src/relay_strategy/rational_strategy.rs b/relays/messages/src/relay_strategy/rational_strategy.rs index fd0a1ffafc..1791670fa4 100644 --- a/relays/messages/src/relay_strategy/rational_strategy.rs +++ b/relays/messages/src/relay_strategy/rational_strategy.rs @@ -17,9 +17,6 @@ //! Rational relay strategy use async_trait::async_trait; -use num_traits::SaturatingAdd; - -use bp_messages::MessageNonce; use crate::{ message_lane::MessageLane, @@ -44,74 +41,18 @@ impl RelayStrategy for RationalStrategy { &mut self, reference: &mut RelayReference, ) -> bool { - // technically, multiple confirmations will be delivered in a single transaction, - // meaning less loses for relayer. But here we don't know the final relayer yet, so - // we're adding a separate transaction for every message. Normally, this cost is covered - // by the message sender. Probably reconsider this? - let confirmation_transaction_cost = - reference.lane_source_client.estimate_confirmation_transaction().await; - - let delivery_transaction_cost = match reference - .lane_target_client - .estimate_delivery_transaction_in_source_tokens( - reference.hard_selected_begin_nonce..= - (reference.hard_selected_begin_nonce + reference.index as MessageNonce), - reference.selected_prepaid_nonces, - reference.selected_unpaid_weight, - reference.selected_size as u32, - ) - .await - { - Ok(v) => v, - Err(err) => { - log::debug!( - target: "bridge", - "Failed to estimate delivery transaction cost: {:?}. No nonces selected for delivery", - err, - ); - return false - }, - }; - - // if it is the first message that makes reward less than cost, let's log it - // if this message makes batch profitable again, let's log it - let is_total_reward_less_than_cost = reference.total_reward < reference.total_cost; - let prev_total_cost = reference.total_cost; - let prev_total_reward = reference.total_reward; - reference.total_confirmations_cost = reference - .total_confirmations_cost - .saturating_add(&confirmation_transaction_cost); - reference.total_reward = reference.total_reward.saturating_add(&reference.details.reward); - reference.total_cost = - reference.total_confirmations_cost.saturating_add(&delivery_transaction_cost); - if !is_total_reward_less_than_cost && reference.total_reward < reference.total_cost { + if let Err(e) = reference.update_cost_and_reward().await { log::debug!( target: "bridge", - "Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it larger than \ - total reward {:?}->{:?}", - reference.nonce, - reference.details.reward, - prev_total_cost, - reference.total_cost, - prev_total_reward, - reference.total_reward, - ); - } else if is_total_reward_less_than_cost && reference.total_reward >= reference.total_cost { - log::debug!( - target: "bridge", - "Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it less than or \ - equal to the total reward {:?}->{:?} (again)", - reference.nonce, - reference.details.reward, - prev_total_cost, - reference.total_cost, - prev_total_reward, - reference.total_reward, + "Failed to update transaction cost and reward: {:?}. No nonces selected for delivery", + e, ); + + return false } - // Rational relayer never want to lose his funds - if reference.total_reward >= reference.total_cost { + // Rational relayer never wants to lose his funds. + if reference.is_profitable() { reference.selected_reward = reference.total_reward; reference.selected_cost = reference.total_cost; return true @@ -119,4 +60,16 @@ impl RelayStrategy for RationalStrategy { false } + + fn on_final_decision< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, + >( + &self, + _reference: &RelayReference, + ) { + // rational relayer would never submit unprofitable transactions, so we don't need to do + // anything here + } } diff --git a/relays/parachains/Cargo.toml b/relays/parachains/Cargo.toml new file mode 100644 index 0000000000..60ac120d7b --- /dev/null +++ b/relays/parachains/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "parachains-relay" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +async-std = "1.6.5" +async-trait = "0.1.40" +backoff = "0.2" +futures = "0.3.5" +linked-hash-map = "0.5.3" +log = "0.4.17" +num-traits = "0.2" +parking_lot = "0.11.0" +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-parachains = { path = "../../primitives/parachains" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +relay-substrate-client = { path = "../client-substrate" } + +[dev-dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5" } +relay-substrate-client = { path = "../client-substrate", features = ["test-helpers"] } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/parachains/src/lib.rs b/relays/parachains/src/lib.rs new file mode 100644 index 0000000000..94b3ce3ec7 --- /dev/null +++ b/relays/parachains/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use std::fmt::Debug; + +use relay_substrate_client::Chain; + +pub mod parachains_loop; +pub mod parachains_loop_metrics; + +/// Finality proofs synchronization pipeline. +pub trait ParachainsPipeline: 'static + Clone + Debug + Send + Sync { + /// Relay chain which is storing parachain heads in its `paras` module. + type SourceChain: Chain; + /// Target chain (either relay or para) which wants to know about new parachain heads. + type TargetChain: Chain; +} diff --git a/relays/parachains/src/parachains_loop.rs b/relays/parachains/src/parachains_loop.rs new file mode 100644 index 0000000000..f44f986d63 --- /dev/null +++ b/relays/parachains/src/parachains_loop.rs @@ -0,0 +1,1128 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use crate::{parachains_loop_metrics::ParachainsLoopMetrics, ParachainsPipeline}; + +use async_trait::async_trait; +use bp_parachains::BestParaHeadHash; +use bp_polkadot_core::{ + parachains::{ParaHash, ParaHeadsProof, ParaId}, + BlockNumber as RelayBlockNumber, +}; +use futures::{future::FutureExt, select}; +use relay_substrate_client::{BlockNumberOf, Chain, HeaderIdOf}; +use relay_utils::{metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient}; +use std::{ + collections::{BTreeMap, BTreeSet}, + future::Future, + time::{Duration, Instant}, +}; + +/// Parachain heads synchronization params. +#[derive(Clone, Debug)] +pub struct ParachainSyncParams { + /// Parachains that we're relaying here. + pub parachains: Vec, + /// Parachain heads update strategy. + pub strategy: ParachainSyncStrategy, + /// Stall timeout. If we have submitted transaction and we see no state updates for this + /// period, we consider our transaction lost. + pub stall_timeout: Duration, +} + +/// Parachain heads update strategy. +#[derive(Clone, Copy, Debug)] +pub enum ParachainSyncStrategy { + /// Update whenever any parachain head is updated. + Any, + /// Wait till all parachain heads are updated. + All, +} + +/// Parachain header availability at a certain chain. +#[derive(Clone, Copy, Debug)] +pub enum AvailableHeader { + /// The client refuses to report parachain head at this moment. + /// + /// It is a "mild" error, which may appear when e.g. on-demand parachains relay is used. + /// This variant must be treated as "we don't want to update parachain head value at the + /// target chain at this moment". + Unavailable, + /// There's no parachain header at the relay chain. + /// + /// Normally it means that the parachain is not registered there. + Missing, + /// Parachain head with given hash is available at the source chain. + Available(T), +} + +impl AvailableHeader { + /// Transform contained value. + pub fn map(self, f: F) -> AvailableHeader + where + F: FnOnce(T) -> U, + { + match self { + AvailableHeader::Unavailable => AvailableHeader::Unavailable, + AvailableHeader::Missing => AvailableHeader::Missing, + AvailableHeader::Available(val) => AvailableHeader::Available(f(val)), + } + } +} + +/// Source client used in parachain heads synchronization loop. +#[async_trait] +pub trait SourceClient: RelayClient { + /// Returns `Ok(true)` if client is in synced state. + async fn ensure_synced(&self) -> Result; + + /// Get parachain head hash at given block. + /// + /// The implementation may call `ParachainsLoopMetrics::update_best_parachain_block_at_source` + /// on provided `metrics` object to update corresponding metric value. + async fn parachain_head( + &self, + at_block: HeaderIdOf, + metrics: Option<&ParachainsLoopMetrics>, + para_id: ParaId, + ) -> Result, Self::Error>; + + /// Get parachain heads proof. + /// + /// The number and order of entries in the resulting parachain head hashes vector must match the + /// number and order of parachains in the `parachains` vector. The incorrect implementation will + /// result in panic. + async fn prove_parachain_heads( + &self, + at_block: HeaderIdOf, + parachains: &[ParaId], + ) -> Result<(ParaHeadsProof, Vec), Self::Error>; +} + +/// Target client used in parachain heads synchronization loop. +#[async_trait] +pub trait TargetClient: RelayClient { + /// Get best block id. + async fn best_block(&self) -> Result, Self::Error>; + + /// Get best finalized source block id. + async fn best_finalized_source_block( + &self, + at_block: &HeaderIdOf, + ) -> Result, Self::Error>; + + /// Get parachain head hash at given block. + /// + /// The implementation may call `ParachainsLoopMetrics::update_best_parachain_block_at_target` + /// on provided `metrics` object to update corresponding metric value. + async fn parachain_head( + &self, + at_block: HeaderIdOf, + metrics: Option<&ParachainsLoopMetrics>, + para_id: ParaId, + ) -> Result, Self::Error>; + + /// Submit parachain heads proof. + async fn submit_parachain_heads_proof( + &self, + at_source_block: HeaderIdOf, + updated_parachains: Vec<(ParaId, ParaHash)>, + proof: ParaHeadsProof, + ) -> Result<(), Self::Error>; +} + +/// Return prefix that will be used by default to expose Prometheus metrics of the parachains +/// sync loop. +pub fn metrics_prefix() -> String { + format!("{}_to_{}_Parachains", P::SourceChain::NAME, P::TargetChain::NAME) +} + +/// Run parachain heads synchronization. +pub async fn run( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + sync_params: ParachainSyncParams, + metrics_params: MetricsParams, + exit_signal: impl Future + 'static + Send, +) -> Result<(), relay_utils::Error> +where + P::SourceChain: Chain, +{ + let exit_signal = exit_signal.shared(); + relay_utils::relay_loop(source_client, target_client) + .with_metrics(metrics_params) + .loop_metric(ParachainsLoopMetrics::new(Some(&metrics_prefix::

()))?)? + .expose() + .await? + .run(metrics_prefix::

(), move |source_client, target_client, metrics| { + run_until_connection_lost( + source_client, + target_client, + sync_params.clone(), + metrics, + exit_signal.clone(), + ) + }) + .await +} + +/// Run parachain heads synchronization. +async fn run_until_connection_lost( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + sync_params: ParachainSyncParams, + metrics: Option, + exit_signal: impl Future + Send, +) -> Result<(), FailedClient> +where + P::SourceChain: Chain, +{ + let exit_signal = exit_signal.fuse(); + let min_block_interval = std::cmp::min( + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + ); + + let mut tx_tracker: Option> = None; + + futures::pin_mut!(exit_signal); + + // Note that the internal loop breaks with `FailedClient` error even if error is non-connection. + // It is Ok for now, but it may need to be fixed in the future to use exponential backoff for + // regular errors. + + loop { + // either wait for new block, or exit signal + select! { + _ = async_std::task::sleep(min_block_interval).fuse() => {}, + _ = exit_signal => return Ok(()), + } + + // if source client is not yet synced, we'll need to sleep. Otherwise we risk submitting too + // much redundant transactions + match source_client.ensure_synced().await { + Ok(true) => (), + Ok(false) => { + log::warn!( + target: "bridge", + "{} client is syncing. Won't do anything until it is synced", + P::SourceChain::NAME, + ); + continue + }, + Err(e) => { + log::warn!( + target: "bridge", + "{} client has failed to return its sync status: {:?}", + P::SourceChain::NAME, + e, + ); + return Err(FailedClient::Target) + }, + } + + // if we have active transaction, we'll need to wait until it is mined or dropped + let best_target_block = target_client.best_block().await.map_err(|e| { + log::warn!(target: "bridge", "Failed to read best {} block: {:?}", P::SourceChain::NAME, e); + FailedClient::Target + })?; + let heads_at_target = read_heads_at_target( + &target_client, + metrics.as_ref(), + &best_target_block, + &sync_params.parachains, + ) + .await?; + tx_tracker = tx_tracker.take().and_then(|tx_tracker| tx_tracker.update(&heads_at_target)); + if tx_tracker.is_some() { + continue + } + + // we have no active transaction and may need to update heads, but do we have something for + // update? + let best_finalized_relay_block = target_client + .best_finalized_source_block(&best_target_block) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to read best finalized {} block from {}: {:?}", + P::SourceChain::NAME, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + })?; + let heads_at_source = read_heads_at_source( + &source_client, + metrics.as_ref(), + &best_finalized_relay_block, + &sync_params.parachains, + ) + .await?; + let updated_ids = select_parachains_to_update::

( + heads_at_source, + heads_at_target, + best_finalized_relay_block, + ); + let is_update_required = is_update_required(&sync_params, &updated_ids); + + log::info!( + target: "bridge", + "Total {} parachains: {}. Up-to-date at {}: {}. Needs update at {}: {}.", + P::SourceChain::NAME, + sync_params.parachains.len(), + P::TargetChain::NAME, + sync_params.parachains.len() - updated_ids.len(), + P::TargetChain::NAME, + updated_ids.len(), + ); + + if is_update_required { + let (heads_proofs, head_hashes) = source_client + .prove_parachain_heads(best_finalized_relay_block, &updated_ids) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to prove {} parachain heads: {:?}", + P::SourceChain::NAME, + e, + ); + FailedClient::Source + })?; + log::info!( + target: "bridge", + "Submitting {} parachain heads update transaction to {}", + P::SourceChain::NAME, + P::TargetChain::NAME, + ); + + assert_eq!( + head_hashes.len(), + updated_ids.len(), + "Incorrect parachains SourceClient implementation" + ); + + target_client + .submit_parachain_heads_proof( + best_finalized_relay_block, + updated_ids.iter().cloned().zip(head_hashes).collect(), + heads_proofs, + ) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to submit {} parachain heads proof to {}: {:?}", + P::SourceChain::NAME, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + })?; + + tx_tracker = Some(TransactionTracker::

::new( + updated_ids, + best_finalized_relay_block.0, + sync_params.stall_timeout, + )); + } + } +} + +/// Given heads at source and target clients, returns set of heads that are out of sync. +fn select_parachains_to_update( + heads_at_source: BTreeMap>, + heads_at_target: BTreeMap>, + best_finalized_relay_block: HeaderIdOf, +) -> Vec +where + P::SourceChain: Chain, +{ + log::trace!( + target: "bridge", + "Selecting {} parachains to update at {} (relay block: {:?}):\n\t\ + At {}: {:?}\n\t\ + At {}: {:?}", + P::SourceChain::NAME, + P::TargetChain::NAME, + best_finalized_relay_block, + P::SourceChain::NAME, + heads_at_source, + P::TargetChain::NAME, + heads_at_target, + ); + + heads_at_source + .into_iter() + .zip(heads_at_target.into_iter()) + .filter(|((para, head_at_source), (_, head_at_target))| { + let needs_update = match (head_at_source, head_at_target) { + (AvailableHeader::Unavailable, _) => { + // source client has politely asked us not to update current parachain head + // at the target chain + false + }, + (AvailableHeader::Available(head_at_source), Some(head_at_target)) + if head_at_target.at_relay_block_number < best_finalized_relay_block.0 && + head_at_target.head_hash != *head_at_source => + { + // source client knows head that is better than the head known to the target + // client + true + }, + (AvailableHeader::Available(_), Some(_)) => { + // this is normal case when relay has recently updated heads, when parachain is + // not progressing, or when our source client is still syncing + false + }, + (AvailableHeader::Available(_), None) => { + // parachain is not yet known to the target client. This is true when parachain + // or bridge has been just onboarded/started + true + }, + (AvailableHeader::Missing, Some(_)) => { + // parachain/parathread has been offboarded removed from the system. It needs to + // be propageted to the target client + true + }, + (AvailableHeader::Missing, None) => { + // all's good - parachain is unknown to both clients + false + }, + }; + if needs_update { + log::trace!( + target: "bridge", + "{} parachain {:?} needs update at {}: {:?} vs {:?}", + P::SourceChain::NAME, + para, + P::TargetChain::NAME, + head_at_source, + head_at_target, + ); + } + + needs_update + }) + .map(|((para, _), _)| para) + .collect() +} + +/// Returns true if we need to submit update transactions to the target node. +fn is_update_required(sync_params: &ParachainSyncParams, updated_ids: &[ParaId]) -> bool { + match sync_params.strategy { + ParachainSyncStrategy::All => updated_ids.len() == sync_params.parachains.len(), + ParachainSyncStrategy::Any => !updated_ids.is_empty(), + } +} + +/// Reads given parachains heads from the source client. +/// +/// Guarantees that the returning map will have an entry for every parachain from `parachains`. +async fn read_heads_at_source( + source_client: &impl SourceClient

, + metrics: Option<&ParachainsLoopMetrics>, + at_relay_block: &HeaderIdOf, + parachains: &[ParaId], +) -> Result>, FailedClient> { + let mut para_head_hashes = BTreeMap::new(); + for para in parachains { + let para_head = source_client.parachain_head(*at_relay_block, metrics, *para).await; + match para_head { + Ok(para_head) => { + para_head_hashes.insert(*para, para_head); + }, + Err(e) => { + log::warn!( + target: "bridge", + "Failed to read head of {} parachain {:?}: {:?}", + P::SourceChain::NAME, + para, + e, + ); + return Err(FailedClient::Source) + }, + } + } + Ok(para_head_hashes) +} + +/// Reads given parachains heads from the source client. +/// +/// Guarantees that the returning map will have an entry for every parachain from `parachains`. +async fn read_heads_at_target( + target_client: &impl TargetClient

, + metrics: Option<&ParachainsLoopMetrics>, + at_block: &HeaderIdOf, + parachains: &[ParaId], +) -> Result>, FailedClient> { + let mut para_best_head_hashes = BTreeMap::new(); + for para in parachains { + let para_best_head = target_client.parachain_head(*at_block, metrics, *para).await; + match para_best_head { + Ok(para_best_head) => { + para_best_head_hashes.insert(*para, para_best_head); + }, + Err(e) => { + log::warn!( + target: "bridge", + "Failed to read head of {} parachain {:?} at {}: {:?}", + P::SourceChain::NAME, + para, + P::TargetChain::NAME, + e, + ); + return Err(FailedClient::Target) + }, + } + } + Ok(para_best_head_hashes) +} + +/// Parachain heads transaction tracker. +struct TransactionTracker { + /// Ids of parachains which heads were updated in the tracked transaction. + awaiting_update: BTreeSet, + /// Number of relay chain block that has been used to craft parachain heads proof. + relay_block_number: BlockNumberOf, + /// Transaction submit time. + submitted_at: Instant, + /// Transaction death time. + death_time: Instant, +} + +impl TransactionTracker

+where + P::SourceChain: Chain, +{ + /// Creates new parachain heads transaction tracker. + pub fn new( + awaiting_update: impl IntoIterator, + relay_block_number: BlockNumberOf, + stall_timeout: Duration, + ) -> Self { + let now = Instant::now(); + TransactionTracker { + awaiting_update: awaiting_update.into_iter().collect(), + relay_block_number, + submitted_at: now, + death_time: now + stall_timeout, + } + } + + /// Returns `None` if all parachain heads have been updated or we consider our transaction dead. + pub fn update( + mut self, + heads_at_target: &BTreeMap>, + ) -> Option { + // remove all pending heads that were synced + for (para, best_para_head) in heads_at_target { + if best_para_head + .as_ref() + .map(|best_para_head| { + best_para_head.at_relay_block_number >= self.relay_block_number + }) + .unwrap_or(false) + { + self.awaiting_update.remove(para); + + log::trace!( + target: "bridge", + "Head of parachain {:?} has been updated at {}: {:?}. Outdated parachains remaining: {}", + para, + P::TargetChain::NAME, + best_para_head, + self.awaiting_update.len(), + ); + } + } + + // if we have synced all required heads, we are done + if self.awaiting_update.is_empty() { + return None + } + + // if our transaction is dead now, we may start over again + let now = Instant::now(); + if now >= self.death_time { + log::warn!( + target: "bridge", + "Parachain heads update transaction {} has been lost: no updates for {}s", + P::TargetChain::NAME, + (now - self.submitted_at).as_secs(), + ); + + return None + } + + Some(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use async_std::sync::{Arc, Mutex}; + use codec::Encode; + use futures::{SinkExt, StreamExt}; + use relay_substrate_client::test_chain::TestChain; + use relay_utils::{HeaderId, MaybeConnectionError}; + use sp_core::H256; + + const PARA_ID: u32 = 0; + const PARA_0_HASH: ParaHash = H256([1u8; 32]); + const PARA_1_HASH: ParaHash = H256([2u8; 32]); + + #[derive(Clone, Debug)] + enum TestError { + Error, + MissingParachainHeadProof, + } + + impl MaybeConnectionError for TestError { + fn is_connection_error(&self) -> bool { + false + } + } + + #[derive(Clone, Debug, PartialEq, Eq)] + struct TestParachainsPipeline; + + impl ParachainsPipeline for TestParachainsPipeline { + type SourceChain = TestChain; + type TargetChain = TestChain; + } + + #[derive(Clone, Debug)] + struct TestClient { + data: Arc>, + } + + #[derive(Clone, Debug)] + struct TestClientData { + source_sync_status: Result, + source_heads: BTreeMap, TestError>>, + source_proofs: BTreeMap, TestError>>, + + target_best_block: Result, TestError>, + target_best_finalized_source_block: Result, TestError>, + target_heads: BTreeMap>, + target_submit_result: Result<(), TestError>, + + exit_signal_sender: Option>>, + } + + impl TestClientData { + pub fn minimal() -> Self { + TestClientData { + source_sync_status: Ok(true), + source_heads: vec![(PARA_ID, Ok(AvailableHeader::Available(PARA_0_HASH)))] + .into_iter() + .collect(), + source_proofs: vec![(PARA_ID, Ok(PARA_0_HASH.encode()))].into_iter().collect(), + + target_best_block: Ok(HeaderId(0, Default::default())), + target_best_finalized_source_block: Ok(HeaderId(0, Default::default())), + target_heads: BTreeMap::new(), + target_submit_result: Ok(()), + + exit_signal_sender: None, + } + } + + pub fn with_exit_signal_sender( + sender: futures::channel::mpsc::UnboundedSender<()>, + ) -> Self { + let mut client = Self::minimal(); + client.exit_signal_sender = Some(Box::new(sender)); + client + } + } + + impl From for TestClient { + fn from(data: TestClientData) -> TestClient { + TestClient { data: Arc::new(Mutex::new(data)) } + } + } + + #[async_trait] + impl RelayClient for TestClient { + type Error = TestError; + + async fn reconnect(&mut self) -> Result<(), TestError> { + unimplemented!() + } + } + + #[async_trait] + impl SourceClient for TestClient { + async fn ensure_synced(&self) -> Result { + self.data.lock().await.source_sync_status.clone() + } + + async fn parachain_head( + &self, + _at_block: HeaderIdOf, + _metrics: Option<&ParachainsLoopMetrics>, + para_id: ParaId, + ) -> Result, TestError> { + match self.data.lock().await.source_heads.get(¶_id.0).cloned() { + Some(result) => result, + None => Ok(AvailableHeader::Missing), + } + } + + async fn prove_parachain_heads( + &self, + _at_block: HeaderIdOf, + parachains: &[ParaId], + ) -> Result<(ParaHeadsProof, Vec), TestError> { + let mut proofs = Vec::new(); + for para_id in parachains { + proofs.push( + self.data + .lock() + .await + .source_proofs + .get(¶_id.0) + .cloned() + .transpose()? + .ok_or(TestError::MissingParachainHeadProof)?, + ); + } + Ok((ParaHeadsProof(proofs), vec![Default::default(); parachains.len()])) + } + } + + #[async_trait] + impl TargetClient for TestClient { + async fn best_block(&self) -> Result, TestError> { + self.data.lock().await.target_best_block.clone() + } + + async fn best_finalized_source_block( + &self, + _at_block: &HeaderIdOf, + ) -> Result, TestError> { + self.data.lock().await.target_best_finalized_source_block.clone() + } + + async fn parachain_head( + &self, + _at_block: HeaderIdOf, + _metrics: Option<&ParachainsLoopMetrics>, + para_id: ParaId, + ) -> Result, TestError> { + self.data.lock().await.target_heads.get(¶_id.0).cloned().transpose() + } + + async fn submit_parachain_heads_proof( + &self, + _at_source_block: HeaderIdOf, + _updated_parachains: Vec<(ParaId, ParaHash)>, + _proof: ParaHeadsProof, + ) -> Result<(), Self::Error> { + self.data.lock().await.target_submit_result.clone()?; + + if let Some(mut exit_signal_sender) = self.data.lock().await.exit_signal_sender.take() { + exit_signal_sender.send(()).await.unwrap(); + } + Ok(()) + } + } + + fn default_sync_params() -> ParachainSyncParams { + ParachainSyncParams { + parachains: vec![ParaId(PARA_ID)], + strategy: ParachainSyncStrategy::Any, + stall_timeout: Duration::from_secs(60), + } + } + + #[test] + fn when_source_client_fails_to_return_sync_state() { + let mut test_source_client = TestClientData::minimal(); + test_source_client.source_sync_status = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(test_source_client), + TestClient::from(TestClientData::minimal()), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_target_client_fails_to_return_best_block() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_best_block = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_target_client_fails_to_read_heads() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_heads.insert(PARA_ID, Err(TestError::Error)); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_target_client_fails_to_read_best_finalized_source_block() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_best_finalized_source_block = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_source_client_fails_to_read_heads() { + let mut test_source_client = TestClientData::minimal(); + test_source_client.source_heads.insert(PARA_ID, Err(TestError::Error)); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(test_source_client), + TestClient::from(TestClientData::minimal()), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Source), + ); + } + + #[test] + fn when_source_client_fails_to_prove_heads() { + let mut test_source_client = TestClientData::minimal(); + test_source_client.source_proofs.insert(PARA_ID, Err(TestError::Error)); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(test_source_client), + TestClient::from(TestClientData::minimal()), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Source), + ); + } + + #[test] + fn when_target_client_rejects_update_transaction() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_submit_result = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + default_sync_params(), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn minimal_working_case() { + let (exit_signal_sender, exit_signal) = futures::channel::mpsc::unbounded(); + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(TestClientData::with_exit_signal_sender(exit_signal_sender)), + default_sync_params(), + None, + exit_signal.into_future().map(|(_, _)| ()), + )), + Ok(()), + ); + } + + const PARA_1_ID: u32 = PARA_ID + 1; + const SOURCE_BLOCK_NUMBER: u32 = 100; + + fn test_tx_tracker() -> TransactionTracker { + TransactionTracker::new( + vec![ParaId(PARA_ID), ParaId(PARA_1_ID)], + SOURCE_BLOCK_NUMBER, + Duration::from_secs(1), + ) + } + + #[test] + fn tx_tracker_update_when_nothing_is_updated() { + assert_eq!( + test_tx_tracker() + .update(&vec![].into_iter().collect()) + .map(|t| t.awaiting_update), + Some(test_tx_tracker().awaiting_update), + ); + } + + #[test] + fn tx_tracker_update_when_one_of_heads_is_updated_to_previous_value() { + assert_eq!( + test_tx_tracker() + .update( + &vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { + at_relay_block_number: SOURCE_BLOCK_NUMBER - 1, + head_hash: PARA_0_HASH, + }) + )] + .into_iter() + .collect() + ) + .map(|t| t.awaiting_update), + Some(test_tx_tracker().awaiting_update), + ); + } + + #[test] + fn tx_tracker_update_when_one_of_heads_is_updated() { + assert_eq!( + test_tx_tracker() + .update( + &vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { + at_relay_block_number: SOURCE_BLOCK_NUMBER, + head_hash: PARA_0_HASH, + }) + )] + .into_iter() + .collect() + ) + .map(|t| t.awaiting_update), + Some(vec![ParaId(PARA_1_ID)].into_iter().collect()), + ); + } + + #[test] + fn tx_tracker_update_when_all_heads_are_updated() { + assert_eq!( + test_tx_tracker() + .update( + &vec![ + ( + ParaId(PARA_ID), + Some(BestParaHeadHash { + at_relay_block_number: SOURCE_BLOCK_NUMBER, + head_hash: PARA_0_HASH, + }) + ), + ( + ParaId(PARA_1_ID), + Some(BestParaHeadHash { + at_relay_block_number: SOURCE_BLOCK_NUMBER, + head_hash: PARA_0_HASH, + }) + ), + ] + .into_iter() + .collect() + ) + .map(|t| t.awaiting_update), + None, + ); + } + + #[test] + fn tx_tracker_update_when_tx_is_stalled() { + let mut tx_tracker = test_tx_tracker(); + tx_tracker.death_time = Instant::now(); + assert_eq!( + tx_tracker.update(&vec![].into_iter().collect()).map(|t| t.awaiting_update), + None, + ); + } + + #[test] + fn parachain_is_not_updated_if_it_is_unknown_to_both_clients() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Missing)].into_iter().collect(), + vec![(ParaId(PARA_ID), None)].into_iter().collect(), + HeaderId(10, Default::default()), + ), + Vec::::new(), + ); + } + + #[test] + fn parachain_is_not_updated_if_it_has_been_updated_at_better_relay_block() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Available(PARA_0_HASH))] + .into_iter() + .collect(), + vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { at_relay_block_number: 20, head_hash: PARA_1_HASH }) + )] + .into_iter() + .collect(), + HeaderId(10, Default::default()), + ), + Vec::::new(), + ); + } + + #[test] + fn parachain_is_not_updated_if_hash_is_the_same_at_next_relay_block() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Available(PARA_0_HASH))] + .into_iter() + .collect(), + vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { at_relay_block_number: 0, head_hash: PARA_0_HASH }) + )] + .into_iter() + .collect(), + HeaderId(10, Default::default()), + ), + Vec::::new(), + ); + } + + #[test] + fn parachain_is_updated_after_offboarding() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Missing)].into_iter().collect(), + vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { + at_relay_block_number: 0, + head_hash: Default::default(), + }) + )] + .into_iter() + .collect(), + HeaderId(10, Default::default()), + ), + vec![ParaId(PARA_ID)], + ); + } + + #[test] + fn parachain_is_updated_after_onboarding() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Available(PARA_0_HASH))] + .into_iter() + .collect(), + vec![(ParaId(PARA_ID), None)].into_iter().collect(), + HeaderId(10, Default::default()), + ), + vec![ParaId(PARA_ID)], + ); + } + + #[test] + fn parachain_is_updated_if_newer_head_is_known() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Available(PARA_1_HASH))] + .into_iter() + .collect(), + vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { at_relay_block_number: 0, head_hash: PARA_0_HASH }) + )] + .into_iter() + .collect(), + HeaderId(10, Default::default()), + ), + vec![ParaId(PARA_ID)], + ); + } + + #[test] + fn parachain_is_not_updated_if_source_head_is_unavailable() { + assert_eq!( + select_parachains_to_update::( + vec![(ParaId(PARA_ID), AvailableHeader::Unavailable)].into_iter().collect(), + vec![( + ParaId(PARA_ID), + Some(BestParaHeadHash { at_relay_block_number: 0, head_hash: PARA_0_HASH }) + )] + .into_iter() + .collect(), + HeaderId(10, Default::default()), + ), + vec![], + ); + } + + #[test] + fn is_update_required_works() { + let mut sync_params = ParachainSyncParams { + parachains: vec![ParaId(PARA_ID), ParaId(PARA_1_ID)], + strategy: ParachainSyncStrategy::Any, + stall_timeout: Duration::from_secs(60), + }; + + assert!(!is_update_required(&sync_params, &[])); + assert!(is_update_required(&sync_params, &[ParaId(PARA_ID)])); + assert!(is_update_required(&sync_params, &[ParaId(PARA_ID), ParaId(PARA_1_ID)])); + + sync_params.strategy = ParachainSyncStrategy::All; + assert!(!is_update_required(&sync_params, &[])); + assert!(!is_update_required(&sync_params, &[ParaId(PARA_ID)])); + assert!(is_update_required(&sync_params, &[ParaId(PARA_ID), ParaId(PARA_1_ID)])); + } +} diff --git a/relays/parachains/src/parachains_loop_metrics.rs b/relays/parachains/src/parachains_loop_metrics.rs new file mode 100644 index 0000000000..ff8bace274 --- /dev/null +++ b/relays/parachains/src/parachains_loop_metrics.rs @@ -0,0 +1,98 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +use bp_polkadot_core::parachains::ParaId; +use relay_utils::metrics::{ + metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, +}; + +/// Parachains sync metrics. +#[derive(Clone)] +pub struct ParachainsLoopMetrics { + /// Best parachains header numbers at the source. + best_source_block_numbers: GaugeVec, + /// Best parachains header numbers at the target. + best_target_block_numbers: GaugeVec, +} + +impl ParachainsLoopMetrics { + /// Create and register parachains loop metrics. + pub fn new(prefix: Option<&str>) -> Result { + Ok(ParachainsLoopMetrics { + best_source_block_numbers: GaugeVec::new( + Opts::new( + metric_name(prefix, "best_parachain_block_number_at_source"), + "Best parachain block numbers at the source relay chain".to_string(), + ), + &["parachain"], + )?, + best_target_block_numbers: GaugeVec::new( + Opts::new( + metric_name(prefix, "best_parachain_block_number_at_target"), + "Best parachain block numbers at the target chain".to_string(), + ), + &["parachain"], + )?, + }) + } + + /// Update best block number at source. + pub fn update_best_parachain_block_at_source>( + &self, + parachain: ParaId, + block_number: Number, + ) { + let block_number = block_number.into(); + let label = parachain_label(¶chain); + log::trace!( + target: "bridge-metrics", + "Updated value of metric 'best_parachain_block_number_at_source[{}]': {:?}", + label, + block_number, + ); + self.best_source_block_numbers.with_label_values(&[&label]).set(block_number); + } + + /// Update best block number at target. + pub fn update_best_parachain_block_at_target>( + &self, + parachain: ParaId, + block_number: Number, + ) { + let block_number = block_number.into(); + let label = parachain_label(¶chain); + log::trace!( + target: "bridge-metrics", + "Updated value of metric 'best_parachain_block_number_at_target[{}]': {:?}", + label, + block_number, + ); + self.best_target_block_numbers.with_label_values(&[&label]).set(block_number); + } +} + +impl Metric for ParachainsLoopMetrics { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + register(self.best_source_block_numbers.clone(), registry)?; + register(self.best_target_block_numbers.clone(), registry)?; + Ok(()) + } +} + +/// Return metric label for the parachain. +fn parachain_label(parachain: &ParaId) -> String { + format!("para_{}", parachain.0) +} diff --git a/relays/utils/Cargo.toml b/relays/utils/Cargo.toml index bb69849da2..ebbfa74c6f 100644 --- a/relays/utils/Cargo.toml +++ b/relays/utils/Cargo.toml @@ -9,13 +9,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" ansi_term = "0.12" anyhow = "1.0" async-std = "1.6.5" -async-trait = "0.1.40" +async-trait = "0.1" backoff = "0.2" isahc = "1.2" env_logger = "0.8.2" futures = "0.3.5" jsonpath_lib = "0.2" -log = "0.4.11" +log = "0.4.17" num-traits = "0.2" serde_json = "1.0" sysinfo = "0.15" diff --git a/relays/utils/src/lib.rs b/relays/utils/src/lib.rs index a335be7912..8e8870ac18 100644 --- a/relays/utils/src/lib.rs +++ b/relays/utils/src/lib.rs @@ -25,6 +25,15 @@ use futures::future::FutureExt; use std::time::Duration; use thiserror::Error; +/// Default relay loop stall timeout. If transactions generated by relay are immortal, then +/// this timeout is used. +/// +/// There are no any strict requirements on block time in Substrate. But we assume here that all +/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest +/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine +/// transaction, or remove it from the pool. +pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); + /// Max delay after connection-unrelated error happened before we'll try the /// same request again. pub const MAX_BACKOFF_INTERVAL: Duration = Duration::from_secs(60); @@ -179,7 +188,7 @@ pub fn interval(timeout: Duration) -> impl futures::Stream { } /// Which client has caused error. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Eq, Clone, Copy, PartialEq)] pub enum FailedClient { /// It is the source client who has caused error. Source, diff --git a/relays/utils/src/metrics.rs b/relays/utils/src/metrics.rs index 084f72e795..b5225fca0e 100644 --- a/relays/utils/src/metrics.rs +++ b/relays/utils/src/metrics.rs @@ -105,6 +105,7 @@ impl MetricsParams { } /// Do not expose metrics. + #[must_use] pub fn disable(mut self) -> Self { self.address = None; self diff --git a/relays/utils/src/metrics/float_json_value.rs b/relays/utils/src/metrics/float_json_value.rs index 7535cbef98..17b09e0509 100644 --- a/relays/utils/src/metrics/float_json_value.rs +++ b/relays/utils/src/metrics/float_json_value.rs @@ -27,7 +27,7 @@ use async_trait::async_trait; use std::time::Duration; /// Value update interval. -const UPDATE_INTERVAL: Duration = Duration::from_secs(60); +const UPDATE_INTERVAL: Duration = Duration::from_secs(300); /// Metric that represents float value received from HTTP service as float gauge. /// diff --git a/relays/utils/src/relay_loop.rs b/relays/utils/src/relay_loop.rs index 521a6345d3..11e14744a0 100644 --- a/relays/utils/src/relay_loop.rs +++ b/relays/utils/src/relay_loop.rs @@ -85,6 +85,7 @@ pub struct LoopMetrics { impl Loop { /// Customize delay between reconnect attempts. + #[must_use] pub fn reconnect_delay(mut self, reconnect_delay: Duration) -> Self { self.reconnect_delay = reconnect_delay; self @@ -200,7 +201,7 @@ impl LoopMetrics { }, }; - let _ = runtime.block_on(async move { + runtime.block_on(async move { log::trace!( target: "bridge-metrics", "Starting prometheus endpoint at: {:?}", diff --git a/scripts/dump-logs.sh b/scripts/dump-logs.sh index e5a3a403ad..51e8518872 100755 --- a/scripts/dump-logs.sh +++ b/scripts/dump-logs.sh @@ -18,11 +18,22 @@ SERVICES=(\ deployments_relay-messages-millau-to-rialto-lane-00000001_1 \ deployments_relay-messages-rialto-to-millau-lane-00000001_1 \ deployments_relay-millau-rialto_1 \ - deployments_relay-headers-westend-to-millau_1 \ + deployments_relay-headers-westend-to-millau-1_1 \ + deployments_relay-headers-westend-to-millau-2_1 \ + deployments_relay-parachains-westend-to-millau-1_1 \ + deployments_relay-parachains-westend-to-millau-1_2 \ + deployments_relay-messages-millau-to-rialto-parachain-generator_1 \ + deployments_relay-messages-rialto-parachain-to-millau-generator_1 \ + deployments_relay-millau-rialto-parachain-1_1 \ + deployments_relay-millau-rialto-parachain-2_1 \ deployments_rialto-node-alice_1 \ deployments_rialto-node-bob_1 \ deployments_millau-node-alice_1 \ deployments_millau-node-bob_1 \ + deployments_rialto-parachain-collator-alice_1 \ + deployments_rialto-parachain-collator-bob_1 \ + deployments_relay-messages-millau-to-rialto-resubmitter_1 \ + deployments_relay-messages-millau-to-rialto-parachain-resubmitter_1 \ ) for SVC in ${SERVICES[*]} diff --git a/scripts/update-weights.sh b/scripts/update-weights.sh index b772386e75..ac24da62b3 100755 --- a/scripts/update-weights.sh +++ b/scripts/update-weights.sh @@ -6,7 +6,7 @@ set -eux -time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark \ +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ --chain=dev \ --steps=50 \ --repeat=20 \ @@ -18,7 +18,7 @@ time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- --output=./modules/messages/src/weights.rs \ --template=./.maintain/millau-weight-template.hbs -time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark \ +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ --chain=dev \ --steps=50 \ --repeat=20 \ @@ -30,14 +30,26 @@ time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- --output=./modules/grandpa/src/weights.rs \ --template=./.maintain/millau-weight-template.hbs -time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark \ +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ --chain=dev \ --steps=50 \ --repeat=20 \ - --pallet=pallet_bridge_token_swap \ + --pallet=pallet_bridge_parachains \ --extrinsic=* \ --execution=wasm \ --wasm-execution=Compiled \ --heap-pages=4096 \ - --output=./modules/token-swap/src/weights.rs \ + --output=./modules/parachains/src/weights.rs \ + --template=./.maintain/millau-weight-template.hbs + +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet=pallet_bridge_relayers \ + --extrinsic=* \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --output=./modules/relayers/src/weights.rs \ --template=./.maintain/millau-weight-template.hbs