From 5abf22b901e8537c28ec6277ad993f91ef611501 Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Thu, 15 Apr 2021 12:26:36 -0400 Subject: [PATCH] Squashed 'bridges/' changes from 746a4027..5330d84e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 5330d84e CLI: naming clean-up. (#897) f99f2225 Westend<>Rococo Headers Relay (#875) 72c9117b Use complex headers+messages relay in test deployments (#905) 48423d5b Stop recursing when creating test headers (#906) f8586fd4 Fix outstanding bridge names. (#901) 54b683b3 Complex headers+messages Millau<->Rialto relay (#878) c0e77ca1 fix message generator scripts (#900) debf3a82 Use Substrate state_getReadProof RPC method to get storage proofs (#893) c3fa7216 Support more than `u8::max_value` GRANDPA validators (#896) e5cb87f9 Grandpa Pallet Pruning (#890) 0b6a8920 RestartNeeded is a connection error (#894) 2cf5fa26 CLI: Estimate Fee (#888) 7dace624 CLI: Send Message (#886) f8eaecfa CLI: Encode Message (#889) 1610f868 Bump `jsonrpsee` to Alpha.3 (#892) d665b531 Use new Cargo feature resolver (#891) ce2ee6ed Rialto Millau Maintenance Dashboard (#881) 7c585ce8 Revert to older nightly. (#887) 73a0470e Adding GrandpaJustification custom type (#882) b9ccea9c Install CA certificates in relay images (#880) ec7841a2 fix widget names (#879) REVERT: 746a4027 Accidentally committed `cargo-expand`ed code 🤦 REVERT: 1a5d09c5 Add note to more closely match `initialize` Call variant REVERT: fdd6e6b3 Add `submit_finality_proof` mock Call variant REVERT: 768b053e Simplify the Rococo and Westend signing params REVERT: 62aca80e Add Westend<>Rococo variants to `relay_headers` REVERT: 0bcb0f51 Add Westend<>Rococo variants to `init_bridge` REVERT: 01d1305f Use mock Westend and Rococo finaltiy tx calls REVERT: fb34b9dd Add modules for Rococo<>Westend header sync git-subtree-dir: bridges git-subtree-split: 5330d84e9511e38cf9d9ec765bee865fedd4b260 --- .github/workflows/rust.yml | 52 +- Cargo.lock | 51 +- Cargo.toml | 1 + Dockerfile | 5 +- bin/millau/node/Cargo.toml | 1 - bin/millau/node/src/service.rs | 38 +- bin/millau/runtime/Cargo.toml | 3 + bin/millau/runtime/src/lib.rs | 13 +- bin/millau/runtime/src/rialto_messages.rs | 29 +- bin/rialto/node/Cargo.toml | 1 - bin/rialto/node/src/service.rs | 38 +- bin/rialto/runtime/src/lib.rs | 13 +- bin/rialto/runtime/src/millau_messages.rs | 27 +- deployments/README.md | 12 +- ...relay-poa-to-rialto-headers-dashboard.json | 2 +- ...relay-rialto-to-poa-headers-dashboard.json | 2 +- ...ay-millau-to-rialto-headers-dashboard.json | 694 ----- ...y-millau-to-rialto-messages-dashboard.json | 2376 +++++++++-------- ...y-rialto-to-millau-messages-dashboard.json | 2367 ++++++++-------- ... rialto-millau-maintenance-dashboard.json} | 422 +-- .../dashboard/prometheus/targets.yml | 7 +- .../bridges/rialto-millau/docker-compose.yml | 42 +- ...lay-headers-rialto-to-millau-entrypoint.sh | 23 - ...messages-to-millau-generator-entrypoint.sh | 11 +- ...messages-to-rialto-generator-entrypoint.sh | 11 +- ...t.sh => relay-millau-rialto-entrypoint.sh} | 22 +- ...y-westend-to-millau-headers-dashboard.json | 2 +- ...ay-headers-westend-to-millau-entrypoint.sh | 2 +- deployments/types-millau.json | 21 + deployments/types-rialto.json | 21 + deployments/types/common.json | 21 + docs/send-message.md | 12 +- modules/dispatch/src/lib.rs | 2 + modules/grandpa/src/benchmarking.rs | 12 +- modules/grandpa/src/lib.rs | 74 +- modules/grandpa/src/mock.rs | 2 + modules/messages/rpc/Cargo.toml | 29 - modules/messages/rpc/src/error.rs | 59 - modules/messages/rpc/src/lib.rs | 202 -- primitives/chain-rococo/src/lib.rs | 23 +- primitives/chain-westend/src/lib.rs | 24 +- primitives/header-chain/src/lib.rs | 16 + primitives/test-utils/Cargo.toml | 6 +- primitives/test-utils/src/keyring.rs | 10 +- primitives/test-utils/src/lib.rs | 19 +- relays/bin-ethereum/src/rialto_client.rs | 4 +- relays/bin-substrate/Cargo.toml | 3 +- relays/bin-substrate/src/chains/millau.rs | 101 + .../millau_headers_to_rialto.rs | 2 +- .../millau_messages_to_rialto.rs | 106 +- relays/bin-substrate/src/chains/mod.rs | 331 +++ relays/bin-substrate/src/chains/rialto.rs | 98 + .../rialto_headers_to_millau.rs | 2 +- .../rialto_messages_to_millau.rs | 106 +- relays/bin-substrate/src/chains/rococo.rs | 39 + .../rococo_headers_to_westend.rs | 36 +- relays/bin-substrate/src/chains/westend.rs | 41 + .../westend_headers_to_millau.rs | 25 +- .../westend_headers_to_rococo.rs | 37 +- relays/bin-substrate/src/cli/bridge.rs | 27 +- relays/bin-substrate/src/cli/encode_call.rs | 2 +- .../bin-substrate/src/cli/encode_message.rs | 106 + relays/bin-substrate/src/cli/estimate_fee.rs | 128 + relays/bin-substrate/src/cli/init_bridge.rs | 18 +- relays/bin-substrate/src/cli/mod.rs | 101 +- relays/bin-substrate/src/cli/relay_headers.rs | 16 +- .../src/cli/relay_headers_and_messages.rs | 183 ++ .../bin-substrate/src/cli/relay_messages.rs | 20 +- relays/bin-substrate/src/cli/send_message.rs | 317 +++ .../bin-substrate/src/headers_initialize.rs | 2 +- relays/bin-substrate/src/main.rs | 4 +- relays/bin-substrate/src/messages_lane.rs | 25 +- relays/bin-substrate/src/messages_source.rs | 66 +- relays/bin-substrate/src/messages_target.rs | 51 +- relays/bin-substrate/src/on_demand_headers.rs | 255 ++ relays/bin-substrate/src/rialto_millau/cli.rs | 175 -- relays/bin-substrate/src/rialto_millau/mod.rs | 769 ------ relays/client-ethereum/Cargo.toml | 6 +- relays/client-substrate/Cargo.toml | 7 +- relays/client-substrate/src/client.rs | 87 +- relays/client-substrate/src/error.rs | 5 + .../src/metrics/float_storage_value.rs | 23 +- .../src/metrics/storage_proof_overhead.rs | 75 +- relays/client-substrate/src/rpc.rs | 29 +- relays/exchange/src/exchange_loop.rs | 14 +- relays/exchange/src/exchange_loop_metrics.rs | 61 +- relays/finality/src/finality_loop.rs | 6 +- relays/headers/src/sync_loop.rs | 13 +- relays/headers/src/sync_loop_metrics.rs | 49 +- relays/messages/src/message_lane_loop.rs | 44 +- relays/messages/src/message_race_delivery.rs | 8 +- relays/messages/src/message_race_loop.rs | 24 +- relays/messages/src/message_race_receiving.rs | 4 +- relays/messages/src/message_race_strategy.rs | 9 + relays/messages/src/metrics.rs | 43 +- relays/utils/src/metrics.rs | 34 +- relays/utils/src/metrics/float_json_value.rs | 28 +- relays/utils/src/metrics/global.rs | 51 +- relays/utils/src/relay_loop.rs | 61 +- scripts/send-message-from-millau-rialto.sh | 4 +- scripts/send-message-from-rialto-millau.sh | 4 +- scripts/update-weights.sh | 22 +- 102 files changed, 5441 insertions(+), 5286 deletions(-) delete mode 100644 deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-headers-dashboard.json rename deployments/bridges/rialto-millau/dashboard/grafana/{relay-rialto-to-millau-headers-dashboard.json => rialto-millau-maintenance-dashboard.json} (50%) delete mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-headers-rialto-to-millau-entrypoint.sh rename deployments/bridges/rialto-millau/entrypoints/{relay-headers-millau-to-rialto-entrypoint.sh => relay-millau-rialto-entrypoint.sh} (53%) delete mode 100644 modules/messages/rpc/Cargo.toml delete mode 100644 modules/messages/rpc/src/error.rs delete mode 100644 modules/messages/rpc/src/lib.rs create mode 100644 relays/bin-substrate/src/chains/millau.rs rename relays/bin-substrate/src/{rialto_millau => chains}/millau_headers_to_rialto.rs (97%) rename relays/bin-substrate/src/{rialto_millau => chains}/millau_messages_to_rialto.rs (74%) create mode 100644 relays/bin-substrate/src/chains/mod.rs create mode 100644 relays/bin-substrate/src/chains/rialto.rs rename relays/bin-substrate/src/{rialto_millau => chains}/rialto_headers_to_millau.rs (97%) rename relays/bin-substrate/src/{rialto_millau => chains}/rialto_messages_to_millau.rs (74%) create mode 100644 relays/bin-substrate/src/chains/rococo.rs rename relays/bin-substrate/src/{rialto_millau => chains}/rococo_headers_to_westend.rs (62%) create mode 100644 relays/bin-substrate/src/chains/westend.rs rename relays/bin-substrate/src/{rialto_millau => chains}/westend_headers_to_millau.rs (70%) rename relays/bin-substrate/src/{rialto_millau => chains}/westend_headers_to_rococo.rs (62%) create mode 100644 relays/bin-substrate/src/cli/encode_message.rs create mode 100644 relays/bin-substrate/src/cli/estimate_fee.rs create mode 100644 relays/bin-substrate/src/cli/relay_headers_and_messages.rs create mode 100644 relays/bin-substrate/src/cli/send_message.rs create mode 100644 relays/bin-substrate/src/on_demand_headers.rs delete mode 100644 relays/bin-substrate/src/rialto_millau/cli.rs delete mode 100644 relays/bin-substrate/src/rialto_millau/mod.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9c4596d5ec57..e6f7939efbcf 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -23,30 +23,30 @@ jobs: toolchain: - stable #- beta - - nightly + - nightly-2021-04-10 runs-on: ubuntu-latest env: RUST_BACKTRACE: full - NIGHTLY: nightly #if necessary, specify the version, nightly-2020-10-04, etc. + NIGHTLY: nightly-2021-04-10 #if necessary, specify the version, nightly-2020-10-04, etc. steps: - + - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.4.1 with: access_token: ${{ github.token }} - + - name: Checkout sources & submodules uses: actions/checkout@master with: fetch-depth: 5 submodules: recursive - + - name: Install Toolchain run: rustup toolchain add $NIGHTLY - + - name: Add WASM Utilities run: rustup target add wasm32-unknown-unknown --toolchain $NIGHTLY - + - name: Checking rust-${{ matrix.toolchain }} uses: actions-rs/cargo@master with: @@ -69,14 +69,14 @@ jobs: with: command: check toolchain: ${{ matrix.toolchain }} - args: --manifest-path ./bin/rialto/node/Cargo.toml --no-default-features --features runtime-benchmarks --verbose - + args: -p rialto-runtime --features runtime-benchmarks --verbose + - name: Check Millau benchmarks runtime ${{ matrix.platform }} rust-${{ matrix.toolchain }} uses: actions-rs/cargo@master with: command: check toolchain: ${{ matrix.toolchain }} - args: --manifest-path ./bin/millau/node/Cargo.toml --no-default-features --features runtime-benchmarks --verbose + args: -p millau-runtime --features runtime-benchmarks --verbose ## Build Stage build: @@ -90,26 +90,26 @@ jobs: runs-on: ubuntu-latest env: RUST_BACKTRACE: full - NIGHTLY: nightly #if necessary, specify the version, nightly-2020-10-04, etc. + NIGHTLY: nightly-2021-04-10 #if necessary, specify the version, nightly-2020-10-04, etc. steps: - + - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.4.1 with: access_token: ${{ github.token }} - + - name: Checkout sources & submodules uses: actions/checkout@master with: fetch-depth: 5 submodules: recursive - + - name: Install Toolchain run: rustup toolchain add $NIGHTLY - + - name: Add WASM Utilities run: rustup target add wasm32-unknown-unknown --toolchain $NIGHTLY - + - name: Building rust-${{ matrix.toolchain }} uses: actions-rs/cargo@master if: github.ref == 'refs/heads/master' @@ -117,7 +117,7 @@ jobs: command: build toolchain: ${{ matrix.toolchain }} args: --all --verbose - + - name: Prepare artifacts if: github.ref == 'refs/heads/master' run: | @@ -127,7 +127,7 @@ jobs: mv -v target/debug/ethereum-poa-relay ./artifacts/; mv -v target/debug/substrate-relay ./artifacts/; shell: bash - + - name: Upload artifacts if: github.ref == 'refs/heads/master' uses: actions/upload-artifact@v1 @@ -141,35 +141,35 @@ jobs: runs-on: ubuntu-latest env: RUST_BACKTRACE: full - NIGHTLY: nightly #if necessary, specify the version, nightly-2020-10-04, etc. + NIGHTLY: nightly-2021-04-10 #if necessary, specify the version, nightly-2020-10-04, etc. steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.4.1 with: access_token: ${{ github.token }} - + - name: Checkout sources & submodules uses: actions/checkout@master with: fetch-depth: 5 submodules: recursive - + - name: Install Toolchain run: rustup toolchain add $NIGHTLY - + - name: Add WASM Utilities run: rustup target add wasm32-unknown-unknown --toolchain $NIGHTLY - + - name: Add clippy run: rustup component add clippy --toolchain $NIGHTLY - + - name: Rust Cache uses: Swatinem/rust-cache@v1.2.0 - + - name: Clippy uses: actions-rs/cargo@master with: command: clippy - toolchain: nightly #if necessary, specify the version, nightly-2020-10-04, etc. + toolchain: nightly-2021-04-10 #if necessary, specify the version, nightly-2020-10-04, etc. args: --all-targets -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 1c39f90452c5..bcd8e5ace296 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -827,6 +827,7 @@ dependencies = [ "bp-header-chain", "ed25519-dalek", "finality-grandpa 0.14.0", + "parity-scale-codec 2.0.1", "sp-application-crypto", "sp-finality-grandpa", "sp-runtime", @@ -3237,9 +3238,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.2.0-alpha.2" +version = "0.2.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb3f732ccbeafd15cefb59c7c7b5ac6c553c2653613b63e5e7feb7f06a219e9" +checksum = "6bb4afbda476e2ee11cc6245055c498c116fc8002d2d60fe8338b6ee15d84c3a" dependencies = [ "Inflector", "proc-macro2", @@ -3249,9 +3250,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.2.0-alpha.2" +version = "0.2.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8cd20c190e75dc56f7543b9d5713c3186351b301b5507ea6b85d8c403aac78" +checksum = "c42a82588b5f7830e94341bb7e79d15f46070ab6f64dde1e3b3719721b61c5bf" dependencies = [ "async-trait", "futures 0.3.13", @@ -3264,9 +3265,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.2.0-alpha.2" +version = "0.2.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afdfa266a6ba3655f464f2e63abddbf3d599226dabd5851928edc817c58867d" +checksum = "0398a066fe036d198e5fea8f3dd092b7bcd0e155d1784ef9e467afc332d4c783" dependencies = [ "async-std", "async-tls", @@ -4093,7 +4094,6 @@ dependencies = [ "millau-runtime", "node-inspect", "pallet-bridge-messages", - "pallet-bridge-messages-rpc", "pallet-transaction-payment-rpc", "sc-basic-authorship", "sc-cli", @@ -4463,6 +4463,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", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -4709,26 +4719,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-bridge-messages-rpc" -version = "0.1.0" -dependencies = [ - "bp-messages", - "bp-runtime", - "derive_more", - "futures 0.3.13", - "jsonrpc-core 15.1.0", - "jsonrpc-core-client", - "jsonrpc-derive", - "log", - "sc-client-api", - "sp-blockchain", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-trie", -] - [[package]] name = "pallet-grandpa" version = "3.0.0" @@ -5985,6 +5975,7 @@ dependencies = [ "sp-finality-grandpa", "sp-runtime", "sp-std", + "sp-storage", "sp-trie", "sp-version", ] @@ -6063,7 +6054,6 @@ dependencies = [ "jsonrpc-core 15.1.0", "node-inspect", "pallet-bridge-messages", - "pallet-bridge-messages-rpc", "pallet-transaction-payment-rpc", "rialto-runtime", "sc-basic-authorship", @@ -8448,12 +8438,13 @@ dependencies = [ "futures 0.3.13", "headers-relay", "hex", + "hex-literal 0.3.1", "log", "messages-relay", "millau-runtime", + "num-format", "num-traits", "pallet-bridge-dispatch", - "pallet-bridge-grandpa", "pallet-bridge-messages", "parity-scale-codec 2.0.1", "paste 1.0.4", @@ -9164,7 +9155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" dependencies = [ "cfg-if 0.1.10", - "rand 0.7.3", + "rand 0.3.23", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index 5ca3c70aa601..1090a0fe5ba8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "bin/*/node", diff --git a/Dockerfile b/Dockerfile index be3338b09d11..b3c4a7b4ba7e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,8 +27,9 @@ ENV DEBIAN_FRONTEND=noninteractive RUN set -eux; \ apt-get update && \ - apt-get install -y --no-install-recommends \ - libssl-dev curl && \ + apt-get install -y curl ca-certificates && \ + apt-get install -y --no-install-recommends libssl-dev && \ + update-ca-certificates && \ groupadd -g 1000 user && \ useradd -u 1000 -g user -s /bin/sh -m user && \ # apt clean up diff --git a/bin/millau/node/Cargo.toml b/bin/millau/node/Cargo.toml index 076e282bae36..e31e2c871a50 100644 --- a/bin/millau/node/Cargo.toml +++ b/bin/millau/node/Cargo.toml @@ -20,7 +20,6 @@ bp-millau= { path = "../../../primitives/chain-millau" } bp-runtime = { path = "../../../primitives/runtime" } millau-runtime = { path = "../runtime" } pallet-bridge-messages = { path = "../../../modules/messages" } -pallet-bridge-messages-rpc = { path = "../../../modules/messages/rpc" } # Substrate Dependencies diff --git a/bin/millau/node/src/service.rs b/bin/millau/node/src/service.rs index b3834ff68a72..8677ec2e70df 100644 --- a/bin/millau/node/src/service.rs +++ b/bin/millau/node/src/service.rs @@ -211,40 +211,8 @@ pub fn new_full(mut config: Configuration) -> Result let prometheus_registry = config.prometheus_registry().cloned(); let rpc_extensions_builder = { - use bp_messages::{LaneId, MessageNonce}; - use bp_runtime::{InstanceId, RIALTO_BRIDGE_INSTANCE}; use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider; - use sp_core::storage::StorageKey; - // This struct is here to ease update process. - - /// Millau runtime from messages RPC point of view. - struct MillauMessagesKeys; - - impl pallet_bridge_messages_rpc::Runtime for MillauMessagesKeys { - fn message_key(&self, instance: &InstanceId, lane: &LaneId, nonce: MessageNonce) -> Option { - match *instance { - RIALTO_BRIDGE_INSTANCE => Some(millau_runtime::rialto_messages::message_key(lane, nonce)), - _ => None, - } - } - - fn outbound_lane_data_key(&self, instance: &InstanceId, lane: &LaneId) -> Option { - match *instance { - RIALTO_BRIDGE_INSTANCE => Some(millau_runtime::rialto_messages::outbound_lane_data_key(lane)), - _ => None, - } - } - - fn inbound_lane_data_key(&self, instance: &InstanceId, lane: &LaneId) -> Option { - match *instance { - RIALTO_BRIDGE_INSTANCE => Some(millau_runtime::rialto_messages::inbound_lane_data_key(lane)), - _ => None, - } - } - } - - use pallet_bridge_messages_rpc::{MessagesApi, MessagesRpcHandler}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; use sc_finality_grandpa_rpc::{GrandpaApi, GrandpaRpcHandler}; use sc_rpc::DenyUnsafe; @@ -259,7 +227,7 @@ pub fn new_full(mut config: Configuration) -> Result let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty(); let finality_proof_provider = - GrandpaFinalityProofProvider::new_for_service(backend.clone(), Some(shared_authority_set.clone())); + GrandpaFinalityProofProvider::new_for_service(backend, Some(shared_authority_set.clone())); Box::new(move |_, subscription_executor| { let mut io = jsonrpc_core::IoHandler::default(); @@ -278,10 +246,6 @@ pub fn new_full(mut config: Configuration) -> Result subscription_executor, finality_proof_provider.clone(), ))); - io.extend_with(MessagesApi::to_delegate(MessagesRpcHandler::new( - backend.clone(), - Arc::new(MillauMessagesKeys), - ))); io }) }; diff --git a/bin/millau/runtime/Cargo.toml b/bin/millau/runtime/Cargo.toml index 411835ab6fec..e1f7ed10c63e 100644 --- a/bin/millau/runtime/Cargo.toml +++ b/bin/millau/runtime/Cargo.toml @@ -101,3 +101,6 @@ std = [ "sp-trie/std", "sp-version/std", ] +# TODO: https://github.com/paritytech/parity-bridges-common/issues/390 +# I've left the feature flag here to test our CI configuration +runtime-benchmarks = [] diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index 437c9ff36f59..30cf1bd87cd8 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -309,12 +309,19 @@ parameter_types! { // call per block. pub const MaxRequests: u32 = 50; pub const WestendValidatorCount: u32 = 255; + + // Number of headers to keep. + // + // Assuming the worst case of every header being finalized, we will keep headers for at least a + // week. + pub const HeadersToKeep: u32 = 7 * bp_millau::DAYS as u32; } pub type RialtoGrandpaInstance = (); impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_rialto::Rialto; type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; // TODO [#391]: Use weights generated for the Millau runtime instead of Rialto ones. type WeightInfo = pallet_bridge_grandpa::weights::RialtoWeight; @@ -324,6 +331,7 @@ pub type WestendGrandpaInstance = pallet_bridge_grandpa::Instance1; impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_westend::Westend; type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; // TODO [#391]: Use weights generated for the Millau runtime instead of Rialto ones. type WeightInfo = pallet_bridge_grandpa::weights::RialtoWeight; @@ -343,7 +351,10 @@ parameter_types! { pub const RootAccountForPayments: Option = None; } -impl pallet_bridge_messages::Config for Runtime { +/// Instance of the messages pallet used to relay messages to/from Rialto chain. +pub type WithRialtoMessagesInstance = pallet_bridge_messages::DefaultInstance; + +impl pallet_bridge_messages::Config for Runtime { type Event = Event; // TODO: https://github.com/paritytech/parity-bridges-common/issues/390 type WeightInfo = pallet_bridge_messages::weights::RialtoWeight; diff --git a/bin/millau/runtime/src/rialto_messages.rs b/bin/millau/runtime/src/rialto_messages.rs index 9162596e7c96..a800117dc551 100644 --- a/bin/millau/runtime/src/rialto_messages.rs +++ b/bin/millau/runtime/src/rialto_messages.rs @@ -24,14 +24,13 @@ use bp_messages::{ InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, }; use bp_runtime::{InstanceId, RIALTO_BRIDGE_INSTANCE}; -use bridge_runtime_common::messages::{self, ChainWithMessages, MessageBridge, MessageTransaction}; +use bridge_runtime_common::messages::{self, MessageBridge, MessageTransaction}; use codec::{Decode, Encode}; use frame_support::{ parameter_types, weights::{DispatchClass, Weight}, RuntimeDebug, }; -use sp_core::storage::StorageKey; use sp_runtime::{FixedPointNumber, FixedU128}; use sp_std::{convert::TryFrom, ops::RangeInclusive}; @@ -43,28 +42,6 @@ parameter_types! { pub storage RialtoToMillauConversionRate: FixedU128 = INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE; } -/// Storage key of the Millau -> Rialto message in the runtime storage. -pub fn message_key(lane: &LaneId, nonce: MessageNonce) -> StorageKey { - pallet_bridge_messages::storage_keys::message_key::::MessagesInstance>( - lane, nonce, - ) -} - -/// Storage key of the Millau -> Rialto message lane state in the runtime storage. -pub fn outbound_lane_data_key(lane: &LaneId) -> StorageKey { - pallet_bridge_messages::storage_keys::outbound_lane_data_key::<::MessagesInstance>( - lane, - ) -} - -/// Storage key of the Rialto -> Millau message lane state in the runtime storage. -pub fn inbound_lane_data_key(lane: &LaneId) -> StorageKey { - pallet_bridge_messages::storage_keys::inbound_lane_data_key::< - Runtime, - ::MessagesInstance, - >(lane) -} - /// Message payload for Millau -> Rialto messages. pub type ToRialtoMessagePayload = messages::source::FromThisChainMessagePayload; @@ -120,14 +97,14 @@ impl messages::ChainWithMessages for Millau { type Weight = Weight; type Balance = bp_millau::Balance; - type MessagesInstance = pallet_bridge_messages::DefaultInstance; + type MessagesInstance = crate::WithRialtoMessagesInstance; } impl messages::ThisChainWithMessages for Millau { type Call = crate::Call; fn is_outbound_lane_enabled(lane: &LaneId) -> bool { - *lane == LaneId::default() + *lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1] } fn maximal_pending_messages_at_outbound_lane() -> MessageNonce { diff --git a/bin/rialto/node/Cargo.toml b/bin/rialto/node/Cargo.toml index fffbe9655a4a..a51ee7a5ab5f 100644 --- a/bin/rialto/node/Cargo.toml +++ b/bin/rialto/node/Cargo.toml @@ -19,7 +19,6 @@ bp-messages = { path = "../../../primitives/messages" } bp-runtime = { path = "../../../primitives/runtime" } bp-rialto = { path = "../../../primitives/chain-rialto" } pallet-bridge-messages = { path = "../../../modules/messages" } -pallet-bridge-messages-rpc = { path = "../../../modules/messages/rpc" } rialto-runtime = { path = "../runtime" } # Substrate Dependencies diff --git a/bin/rialto/node/src/service.rs b/bin/rialto/node/src/service.rs index 380b0cc8171c..841202ac7bfa 100644 --- a/bin/rialto/node/src/service.rs +++ b/bin/rialto/node/src/service.rs @@ -211,40 +211,8 @@ pub fn new_full(mut config: Configuration) -> Result let prometheus_registry = config.prometheus_registry().cloned(); let rpc_extensions_builder = { - use bp_messages::{LaneId, MessageNonce}; - use bp_runtime::{InstanceId, MILLAU_BRIDGE_INSTANCE}; use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider; - use sp_core::storage::StorageKey; - // This struct is here to ease update process. - - /// Rialto runtime from messages RPC point of view. - struct RialtoMessagesKeys; - - impl pallet_bridge_messages_rpc::Runtime for RialtoMessagesKeys { - fn message_key(&self, instance: &InstanceId, lane: &LaneId, nonce: MessageNonce) -> Option { - match *instance { - MILLAU_BRIDGE_INSTANCE => Some(rialto_runtime::millau_messages::message_key(lane, nonce)), - _ => None, - } - } - - fn outbound_lane_data_key(&self, instance: &InstanceId, lane: &LaneId) -> Option { - match *instance { - MILLAU_BRIDGE_INSTANCE => Some(rialto_runtime::millau_messages::outbound_lane_data_key(lane)), - _ => None, - } - } - - fn inbound_lane_data_key(&self, instance: &InstanceId, lane: &LaneId) -> Option { - match *instance { - MILLAU_BRIDGE_INSTANCE => Some(rialto_runtime::millau_messages::inbound_lane_data_key(lane)), - _ => None, - } - } - } - - use pallet_bridge_messages_rpc::{MessagesApi, MessagesRpcHandler}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; use sc_finality_grandpa_rpc::{GrandpaApi, GrandpaRpcHandler}; use sc_rpc::DenyUnsafe; @@ -259,7 +227,7 @@ pub fn new_full(mut config: Configuration) -> Result let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty(); let finality_proof_provider = - GrandpaFinalityProofProvider::new_for_service(backend.clone(), Some(shared_authority_set.clone())); + GrandpaFinalityProofProvider::new_for_service(backend, Some(shared_authority_set.clone())); Box::new(move |_, subscription_executor| { let mut io = jsonrpc_core::IoHandler::default(); @@ -278,10 +246,6 @@ pub fn new_full(mut config: Configuration) -> Result subscription_executor, finality_proof_provider.clone(), ))); - io.extend_with(MessagesApi::to_delegate(MessagesRpcHandler::new( - backend.clone(), - Arc::new(RialtoMessagesKeys), - ))); io }) diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs index 4db3101810a1..4e81d3efb1fb 100644 --- a/bin/rialto/runtime/src/lib.rs +++ b/bin/rialto/runtime/src/lib.rs @@ -414,11 +414,18 @@ parameter_types! { // 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_rialto::DAYS as u32; } impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_millau::Millau; type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; type WeightInfo = pallet_bridge_grandpa::weights::RialtoWeight; } @@ -436,8 +443,10 @@ parameter_types! { pub const RootAccountForPayments: Option = None; } -pub(crate) type WithMillauMessagesInstance = pallet_bridge_messages::DefaultInstance; -impl pallet_bridge_messages::Config for Runtime { +/// Instance of the messages pallet used to relay messages to/from Millau chain. +pub type WithMillauMessagesInstance = pallet_bridge_messages::DefaultInstance; + +impl pallet_bridge_messages::Config for Runtime { type Event = Event; type WeightInfo = pallet_bridge_messages::weights::RialtoWeight; type Parameter = millau_messages::RialtoToMillauMessagesParameter; diff --git a/bin/rialto/runtime/src/millau_messages.rs b/bin/rialto/runtime/src/millau_messages.rs index 62f4ec714747..8ee2094660c1 100644 --- a/bin/rialto/runtime/src/millau_messages.rs +++ b/bin/rialto/runtime/src/millau_messages.rs @@ -24,14 +24,13 @@ use bp_messages::{ InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, }; use bp_runtime::{InstanceId, MILLAU_BRIDGE_INSTANCE}; -use bridge_runtime_common::messages::{self, ChainWithMessages, MessageBridge, MessageTransaction}; +use bridge_runtime_common::messages::{self, MessageBridge, MessageTransaction}; use codec::{Decode, Encode}; use frame_support::{ parameter_types, weights::{DispatchClass, Weight}, RuntimeDebug, }; -use sp_core::storage::StorageKey; use sp_runtime::{FixedPointNumber, FixedU128}; use sp_std::{convert::TryFrom, ops::RangeInclusive}; @@ -43,28 +42,6 @@ parameter_types! { pub storage MillauToRialtoConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE; } -/// Storage key of the Rialto -> Millau message in the runtime storage. -pub fn message_key(lane: &LaneId, nonce: MessageNonce) -> StorageKey { - pallet_bridge_messages::storage_keys::message_key::::MessagesInstance>( - lane, nonce, - ) -} - -/// Storage key of the Rialto -> Millau message lane state in the runtime storage. -pub fn outbound_lane_data_key(lane: &LaneId) -> StorageKey { - pallet_bridge_messages::storage_keys::outbound_lane_data_key::<::MessagesInstance>( - lane, - ) -} - -/// Storage key of the Millau -> Rialto message lane state in the runtime storage. -pub fn inbound_lane_data_key(lane: &LaneId) -> StorageKey { - pallet_bridge_messages::storage_keys::inbound_lane_data_key::< - Runtime, - ::MessagesInstance, - >(lane) -} - /// Message payload for Rialto -> Millau messages. pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload; @@ -127,7 +104,7 @@ impl messages::ThisChainWithMessages for Rialto { type Call = crate::Call; fn is_outbound_lane_enabled(lane: &LaneId) -> bool { - *lane == LaneId::default() + *lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1] } fn maximal_pending_messages_at_outbound_lane() -> MessageNonce { diff --git a/deployments/README.md b/deployments/README.md index 5d656eef2ff4..d553fca611a6 100644 --- a/deployments/README.md +++ b/deployments/README.md @@ -114,14 +114,14 @@ Following accounts are used when `poa-rialto` bridge is running: Following accounts are used when `rialto-millau` bridge is running: -- Millau's `Charlie` signs relay transactions with new Rialto headers; -- Rialto's `Charlie` signs relay transactions with new Millau headers; +- 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 from Rialto to Millau; -- Rialto's `Eve` signs relay transactions with messages from Millau to Rialto; -- Millau's `Ferdie` signs relay transactions with messages from Rialto to Millau; -- Rialto's `Ferdie` signs relay transactions with message delivery confirmations from Millau to Rialto. +- 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. Following accounts are used when `westend-millau` bridge is running: diff --git a/deployments/bridges/poa-rialto/dashboard/grafana/relay-poa-to-rialto-headers-dashboard.json b/deployments/bridges/poa-rialto/dashboard/grafana/relay-poa-to-rialto-headers-dashboard.json index 36c2ab94692a..05d06e949819 100644 --- a/deployments/bridges/poa-rialto/dashboard/grafana/relay-poa-to-rialto-headers-dashboard.json +++ b/deployments/bridges/poa-rialto/dashboard/grafana/relay-poa-to-rialto-headers-dashboard.json @@ -239,7 +239,7 @@ { "expr": "max_over_time(Ethereum_to_Substrate_Sync_best_block_numbers{node=\"source\"}[2m])-min_over_time(Ethereum_to_Substrate_Sync_best_block_numbers{node=\"source\"}[2m])", "interval": "", - "legendFormat": "Number of Ethereum PoA Headers Synced on Rialto", + "legendFormat": "Number of new Headers on Ethereum PoA (Last 2 Mins)", "refId": "A" } ], diff --git a/deployments/bridges/poa-rialto/dashboard/grafana/relay-rialto-to-poa-headers-dashboard.json b/deployments/bridges/poa-rialto/dashboard/grafana/relay-rialto-to-poa-headers-dashboard.json index cac19b3fde54..149c637fcb15 100644 --- a/deployments/bridges/poa-rialto/dashboard/grafana/relay-rialto-to-poa-headers-dashboard.json +++ b/deployments/bridges/poa-rialto/dashboard/grafana/relay-rialto-to-poa-headers-dashboard.json @@ -239,7 +239,7 @@ { "expr": "max_over_time(Substrate_to_Ethereum_Sync_best_block_numbers{node=\"source\"}[2m])-min_over_time(Substrate_to_Ethereum_Sync_best_block_numbers{node=\"source\"}[2m])", "interval": "", - "legendFormat": "Number of Rialto Headers Synced on Ethereum PoA", + "legendFormat": "Number of new Headers on Rialto (Last 2 Mins)", "refId": "A" } ], diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-headers-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-headers-dashboard.json deleted file mode 100644 index 2dc4f8a41829..000000000000 --- a/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-headers-dashboard.json +++ /dev/null @@ -1,694 +0,0 @@ -{ - "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": [ - { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 5 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "5m", - "handler": 1, - "message": "", - "name": "Synced Header Difference is Over 5 (Millau to Rialto)", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "description": "Shows how many headers behind the target chain is from the source chain.", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 0 - }, - "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": "max(Millau_to_Rialto_Sync_best_block_numbers{node=\"source\"}) - max(Millau_to_Rialto_Sync_best_block_numbers{node=\"target\"})", - "format": "table", - "instant": false, - "interval": "", - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 5 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Difference Between Source and Target 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": [ - 5 - ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "2m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "3m", - "frequency": "5m", - "handler": 1, - "name": "No New Headers (Millau to Rialto)", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "description": "How many headers has the relay synced from the source node in the last 2 mins?", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 0 - }, - "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": "max_over_time(Millau_to_Rialto_Sync_best_block_numbers{node=\"source\"}[2m])-min_over_time(Millau_to_Rialto_Sync_best_block_numbers{node=\"source\"}[2m])", - "interval": "", - "legendFormat": "Number of Millau Headers Synced on Rialto", - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "lt", - "value": 5 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Headers Synced on Rialto (Last 2 Mins)", - "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": { - "defaults": { - "custom": { - "align": null - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 8 - }, - "id": 2, - "interval": "5s", - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "Millau_to_Rialto_Sync_best_block_numbers", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "Best Known Header on {{node}} Node", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Best Blocks according to Relay", - "type": "stat" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "description": "", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 6, - "x": 12, - "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", - "percentage": false, - "pluginVersion": "7.1.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "Millau_to_Rialto_Sync_system_average_load", - "interval": "", - "legendFormat": "Average system load in last {{over}}", - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": null - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Average System Load", - "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": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 6, - "x": 18, - "y": 8 - }, - "id": 12, - "options": { - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "avg_over_time(Millau_to_Rialto_Sync_process_cpu_usage_percentage[1m])", - "instant": true, - "interval": "", - "legendFormat": "1 CPU = 100", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Relay Process CPU Usage ", - "type": "gauge" - }, - { - "datasource": "Prometheus", - "description": "", - "fieldConfig": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 14 - }, - "id": 4, - "options": { - "displayMode": "gradient", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "Millau_to_Rialto_Sync_blocks_in_state", - "instant": true, - "interval": "", - "legendFormat": "{{state}}", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Queued Headers in Relay", - "type": "bargauge" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "description": "", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "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": "Millau_to_Rialto_Sync_process_memory_usage_bytes / 1024 / 1024", - "interval": "", - "legendFormat": "Process memory, MB", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Memory Usage for Relay Process", - "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": [ - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Millau to Rialto Header Sync Dashboard", - "uid": "relay-millau-to-rialto-headers", - "version": 1 -} 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 69c07f8715f8..69396162bbaa 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 @@ -1,1113 +1,1405 @@ { "annotations": { "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } + { + "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": 3, "links": [], "panels": [ { - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_best_block_numbers{type=~\"target|target_at_source\"}, \"type\", \"At Rialto\", \"type\", \"target\"), \"type\", \"At Millau\", \"type\", \"target_at_source\")", - "instant": false, - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Best finalized Rialto 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 + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_best_block_numbers{type=~\"target|target_at_source\"}, \"type\", \"At Rialto\", \"type\", \"target\"), \"type\", \"At Millau\", \"type\", \"target_at_source\")", + "instant": false, + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Rialto 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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_best_block_numbers{type=~\"source|source_at_target\"}, \"type\", \"At Millau\", \"type\", \"source\"), \"type\", \"At Rialto\", \"type\", \"source_at_target\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - } - ], - "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 + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_best_block_numbers{type=~\"source|source_at_target\"}, \"type\", \"At Millau\", \"type\", \"source\"), \"type\", \"At Rialto\", \"type\", \"source_at_target\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ + "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": "5m", + "frequency": "1m", + "handler": 1, + "name": "Messages generated at Millau 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": [ { - "evaluator": { - "params": [ - 1 - ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "max" - }, - "type": "query" + "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\")", + "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])", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes", + "refId": "B" } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Messages generated at Millau are not detected by relay", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "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\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" + "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" }, - { - "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])", - "hide": true, - "interval": "", - "legendFormat": "Messages generated in last 5 minutes", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Delivery race", - "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 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "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\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Confirmations race", - "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 + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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_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\")", + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "1m", - "now" - ] + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "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": [] }, - "reducer": { - "params": [], - "type": "sum" + "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_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at Rialto", + "refId": "A" }, - "type": "query" - } + { + "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[1m])", + "interval": "", + "legendFormat": "Messages delivered to Rialto in last 1m", + "refId": "B" + } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "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": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", - "format": "time_series", - "instant": false, - "interval": "", - "legendFormat": "Undelivered messages at Rialto", - "refId": "A" + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[1m])", - "interval": "", - "legendFormat": "Messages delivered to Rialto in last 1m", - "refId": "B" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "lt", - "value": 1 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Delivery race lags", - "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 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 10 + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] }, - "reducer": { - "params": [], - "type": "min" + "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_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]))", + "interval": "", + "legendFormat": "Unconfirmed messages at Millau", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "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 }, - "type": "query" - } + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Too many unconfirmed messages", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "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]))", - "interval": "", - "legendFormat": "Unconfirmed messages at Millau", - "refId": "A" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 10 + "yaxis": { + "align": false, + "alignLevel": null } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Confirmations race lags", - "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 + { + "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": "5m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed", + "noDataState": "no_data", + "notifications": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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_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]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Rialto", + "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]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Rialto (zero if messages are not being delivered to Rialto)", + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 10 + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Messages (00000001) from Millau to Rialto are not being delivered", + "noDataState": "alerting", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] }, - "reducer": { - "params": [], - "type": "min" + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 21, + "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_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\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" }, - "type": "query" - } + { + "expr": "increase(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=\"target_latest_received\"}[10m])", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes", + "refId": "B" + } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Rewards are not being confirmed", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "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]))", - "interval": "", - "legendFormat": "Unconfirmed rewards at Rialto", - "refId": "A" + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000001)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "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]))", - "interval": "", - "legendFormat": "Unconfirmed rewards at Rialto (zero if messages are not being delivered to Rialto)", - "refId": "B" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 10 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Reward lags", - "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 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ + "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": "Messages (00000001) from Millau to Rialto are not being confirmed", + "noDataState": "alerting", + "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": 12, + "y": 27 + }, + "hiddenSeries": false, + "id": 22, + "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": [ { - "color": "green", - "value": null + "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\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" }, { - "color": "red", - "value": 80 + "expr": "increase(Millau_to_Rialto_MessageLane_00000001_lane_state_nonces{type=\"source_latest_confirmed\"}[10m])", + "hide": true, + "interval": "", + "legendFormat": "", + "refId": "B" } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 8, - "x": 0, - "y": 27 - }, - "id": 16, - "options": { - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" ], - "fields": "", - "values": false + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000001)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "7.0.6", - "targets": [ - { - "expr": "avg_over_time(Millau_to_Rialto_MessageLane_00000000_process_cpu_usage_percentage[1m])", - "instant": true, - "interval": "", - "legendFormat": "1 CPU = 100", - "refId": "A" + "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 } - ], - "timeFrom": null, - "timeShift": null, - "title": "Relay process CPU usage (1 CPU = 100)", - "type": "gauge" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 8, - "y": 27 - }, - "hiddenSeries": false, - "id": 18, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "Millau_to_Rialto_MessageLane_00000000_system_average_load", - "interval": "", - "legendFormat": "Average system load in last {{over}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "System load average", - "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 + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg_over_time(Millau_to_Rialto_MessageLane_00000000_process_cpu_usage_percentage[1m])", + "instant": true, + "interval": "", + "legendFormat": "1 CPU = 100", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Relay process CPU usage (1 CPU = 100)", + "type": "gauge" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 16, - "y": 27 - }, - "hiddenSeries": false, - "id": 20, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "Millau_to_Rialto_MessageLane_00000000_process_memory_usage_bytes / 1024 / 1024", - "interval": "", - "legendFormat": "Process memory, MB", - "refId": "A" + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 38 + }, + "hiddenSeries": false, + "id": 18, + "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_system_average_load", + "interval": "", + "legendFormat": "Average system load in last {{over}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "System load average", + "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 } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Memory used by relay process", - "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 + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 38 + }, + "hiddenSeries": false, + "id": 20, + "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_process_memory_usage_bytes / 1024 / 1024", + "interval": "", + "legendFormat": "Process memory, MB", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory used by relay process", + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } } ], "refresh": "5s", - "schemaVersion": 25, + "schemaVersion": 26, "style": "dark", "tags": [], "templating": { @@ -1119,19 +1411,19 @@ }, "timepicker": { "refresh_intervals": [ - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" ] }, "timezone": "", "title": "Millau to Rialto Message Sync Dashboard", "uid": "relay-millau-to-rialto-messages", - "version": 1 + "version": 2 } 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 138d1f7f2c03..29691e0a060c 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 @@ -1,1113 +1,1396 @@ { "annotations": { "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } + { + "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": 4, "links": [], "panels": [ { - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_best_block_numbers{type=~\"target|target_at_source\"}, \"type\", \"At Millau\", \"type\", \"target\"), \"type\", \"At Rialto\", \"type\", \"target_at_source\")", - "instant": false, - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - } - ], - "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 + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_best_block_numbers{type=~\"target|target_at_source\"}, \"type\", \"At Millau\", \"type\", \"target\"), \"type\", \"At Rialto\", \"type\", \"target_at_source\")", + "instant": false, + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_best_block_numbers{type=~\"source|source_at_target\"}, \"type\", \"At Rialto\", \"type\", \"source\"), \"type\", \"At Millau\", \"type\", \"source_at_target\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Best finalized Rialto 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 + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_best_block_numbers{type=~\"source|source_at_target\"}, \"type\", \"At Rialto\", \"type\", \"source\"), \"type\", \"At Millau\", \"type\", \"source_at_target\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Rialto 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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ + "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": "5m", + "frequency": "1m", + "handler": 1, + "name": "Messages generated at Rialto 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": [ { - "evaluator": { - "params": [ - 1 - ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "max" - }, - "type": "query" + "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Millau\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "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])", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes", + "refId": "B" } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Messages generated at Rialto are not detected by relay", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Millau\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "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])", - "hide": true, - "interval": "", - "legendFormat": "Messages generated in last 5 minutes", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Delivery race", - "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 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Millau to Rialto\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", - "interval": "", - "legendFormat": "{{type}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Confirmations race", - "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 + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Millau to Rialto\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Rialto\", \"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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 1 + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "1m", - "now" - ] + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Messages from Rialto to Millau are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] }, - "reducer": { - "params": [], - "type": "sum" + "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(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at Millau", + "refId": "A" }, - "type": "query" - } + { + "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[1m])", + "interval": "", + "legendFormat": "Messages delivered to Millau in last 1m", + "refId": "B" + } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Messages from Rialto to Millau are not being delivered", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", - "format": "time_series", - "instant": false, - "interval": "", - "legendFormat": "Undelivered messages at Millau", - "refId": "A" + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[1m])", - "interval": "", - "legendFormat": "Messages delivered to Millau in last 1m", - "refId": "B" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "lt", - "value": 1 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Delivery race lags", - "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 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 10 + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] }, - "reducer": { - "params": [], - "type": "min" + "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(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]))", + "interval": "", + "legendFormat": "Unconfirmed messages at Rialto", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "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 }, - "type": "query" - } + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Too many unconfirmed messages", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "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]))", - "interval": "", - "legendFormat": "Unconfirmed messages at Rialto", - "refId": "A" + "yaxis": { + "align": false, + "alignLevel": null } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 10 - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Confirmations race lags", - "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 + { + "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": "5m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed", + "noDataState": "no_data", + "notifications": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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(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]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau", + "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]))", + "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, + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 10 + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Messages (00000001) from Rialto to Millau are not being delivered", + "noDataState": "alerting", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] }, - "reducer": { - "params": [], - "type": "min" + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 21, + "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(Rialto_to_Millau_MessageLane_00000001_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Millau\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" }, - "type": "query" - } + { + "expr": "increase(Rialto_to_Millau_MessageLane_00000001_lane_state_nonces{type=\"target_latest_received\"}[10m])", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes", + "refId": "B" + } ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Rewards are not being confirmed", - "noDataState": "no_data", - "notifications": [] - }, - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "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", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "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]))", - "interval": "", - "legendFormat": "Unconfirmed rewards at Millau", - "refId": "A" + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000001)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - { - "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]))", - "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", - "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 + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } }, { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ + "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": "Messages (00000001) from Rialto to Millau are not being confirmed", + "noDataState": "alerting", + "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": 12, + "y": 27 + }, + "hiddenSeries": false, + "id": 22, + "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": [ { - "color": "green", - "value": null + "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000001_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Millau to Rialto\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" }, { - "color": "red", - "value": 80 + "expr": "increase(Rialto_to_Millau_MessageLane_00000001_lane_state_nonces{type=\"source_latest_confirmed\"}[10m])", + "hide": true, + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 8, - "x": 0, - "y": 27 - }, - "id": 16, - "options": { - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" ], - "fields": "", - "values": false + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000001)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "7.0.6", - "targets": [ - { - "expr": "avg_over_time(Rialto_to_Millau_MessageLane_00000000_process_cpu_usage_percentage[1m])", - "instant": true, - "interval": "", - "legendFormat": "1 CPU = 100", - "refId": "A" + "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 } - ], - "timeFrom": null, - "timeShift": null, - "title": "Relay process CPU usage (1 CPU = 100)", - "type": "gauge" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 8, - "y": 27 - }, - "hiddenSeries": false, - "id": 18, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "Rialto_to_Millau_MessageLane_00000000_system_average_load", - "interval": "", - "legendFormat": "Average system load in last {{over}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "System load average", - "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 + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg_over_time(Rialto_to_Millau_MessageLane_00000000_process_cpu_usage_percentage[1m])", + "instant": true, + "interval": "", + "legendFormat": "1 CPU = 100", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Relay process CPU usage (1 CPU = 100)", + "type": "gauge" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 16, - "y": 27 - }, - "hiddenSeries": false, - "id": 20, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "Rialto_to_Millau_MessageLane_00000000_process_memory_usage_bytes / 1024 / 1024", - "interval": "", - "legendFormat": "Process memory, MB", - "refId": "A" + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 38 + }, + "hiddenSeries": false, + "id": 18, + "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": "Rialto_to_Millau_MessageLane_00000000_system_average_load", + "interval": "", + "legendFormat": "Average system load in last {{over}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "System load average", + "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 } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Memory used by relay process", - "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 + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 38 + }, + "hiddenSeries": false, + "id": 20, + "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": "Rialto_to_Millau_MessageLane_00000000_process_memory_usage_bytes / 1024 / 1024", + "interval": "", + "legendFormat": "Process memory, MB", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory used by relay process", + "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 } - ], - "yaxis": { - "align": false, - "alignLevel": null - } } ], "refresh": "5s", - "schemaVersion": 25, + "schemaVersion": 26, "style": "dark", "tags": [], "templating": { @@ -1119,19 +1402,19 @@ }, "timepicker": { "refresh_intervals": [ - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" ] }, "timezone": "", "title": "Rialto to Millau Message Sync Dashboard", "uid": "relay-rialto-to-millau-messages", - "version": 1 + "version": 2 } diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-headers-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json similarity index 50% rename from deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-headers-dashboard.json rename to deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json index 1f9176ddba1b..2e518ce2d008 100644 --- a/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-headers-dashboard.json +++ b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json @@ -15,55 +15,17 @@ "editable": true, "gnetId": null, "graphTooltip": 0, + "id": 9, "links": [], "panels": [ { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 5 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "5m", - "handler": 1, - "message": "", - "name": "Synced Header Difference is Over 5 (Rialto to Millau)", - "noDataState": "no_data", - "notifications": [] - }, "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "description": "Shows how many headers behind the target chain is from the source chain.", "fieldConfig": { - "defaults": { - "custom": {} - }, + "defaults": {}, "overrides": [] }, "fill": 1, @@ -75,7 +37,7 @@ "y": 0 }, "hiddenSeries": false, - "id": 14, + "id": 4, "legend": { "avg": false, "current": false, @@ -88,8 +50,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "7.5.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -99,27 +64,26 @@ "steppedLine": false, "targets": [ { - "expr": "max(Rialto_to_Millau_Sync_best_block_numbers{node=\"source\"}) - max(Rialto_to_Millau_Sync_best_block_numbers{node=\"target\"})", - "format": "table", - "instant": false, + "exemplar": true, + "expr": "Rialto_to_Millau_MessageLane_00000000_rialto_storage_proof_overhead", "interval": "", - "legendFormat": "", + "legendFormat": "Actual overhead", "refId": "A" - } - ], - "thresholds": [ + }, { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 5 + "exemplar": true, + "expr": "1024", + "hide": false, + "interval": "", + "legendFormat": "At runtime (hardcoded)", + "refId": "B" } ], + "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Difference Between Source and Target Headers", + "title": "Rialto: storage proof overhead", "tooltip": { "shared": true, "sort": 0, @@ -135,6 +99,7 @@ }, "yaxes": [ { + "$$hashKey": "object:111", "format": "short", "label": null, "logBase": 1, @@ -143,6 +108,7 @@ "show": true }, { + "$$hashKey": "object:112", "format": "short", "label": null, "logBase": 1, @@ -157,51 +123,13 @@ } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 5 - ], - "type": "lt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "2m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "min" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "3m", - "frequency": "5m", - "handler": 1, - "name": "No New Headers (Rialto to Millau)", - "noDataState": "no_data", - "notifications": [] - }, "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "description": "How many headers has the relay synced from the source node in the last 2 mins?", "fieldConfig": { - "defaults": { - "custom": {} - }, + "defaults": {}, "overrides": [] }, "fill": 1, @@ -213,7 +141,7 @@ "y": 0 }, "hiddenSeries": false, - "id": 16, + "id": 2, "legend": { "avg": false, "current": false, @@ -226,8 +154,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "7.5.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -237,25 +168,26 @@ "steppedLine": false, "targets": [ { - "expr": "max_over_time(Rialto_to_Millau_Sync_best_block_numbers{node=\"source\"}[2m])-min_over_time(Rialto_to_Millau_Sync_best_block_numbers{node=\"source\"}[2m])", + "exemplar": true, + "expr": "Westend_to_Millau_Sync_kusama_price / Westend_to_Millau_Sync_polkadot_price", "interval": "", - "legendFormat": "Number of Rialto Headers Synced on Millau", + "legendFormat": "At exchanges (actually Polkadot -> Kusama)", "refId": "A" - } - ], - "thresholds": [ + }, { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "lt", - "value": 5 + "exemplar": true, + "expr": "Rialto_to_Millau_MessageLane_00000000_rialto_millau_to_rialto_conversion_rate", + "hide": false, + "interval": "", + "legendFormat": "At runtime", + "refId": "B" } ], + "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Headers Synced on Millau (Last 2 Mins)", + "title": "Rialto: Millau -> Rialto conversion rate", "tooltip": { "shared": true, "sort": 0, @@ -271,6 +203,7 @@ }, "yaxes": [ { + "$$hashKey": "object:49", "format": "short", "label": null, "logBase": 1, @@ -279,6 +212,7 @@ "show": true }, { + "$$hashKey": "object:50", "format": "short", "label": null, "logBase": 1, @@ -292,92 +226,26 @@ "alignLevel": null } }, - { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": { - "align": null - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 8 - }, - "id": 2, - "interval": "5s", - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "textMode": "auto" - }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "Rialto_to_Millau_Sync_best_block_numbers", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "Best Known Header on {{node}} Node", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Best Blocks according to Relay", - "type": "stat" - }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "description": "", "fieldConfig": { - "defaults": { - "custom": {} - }, + "defaults": {}, "overrides": [] }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, - "w": 6, - "x": 12, + "w": 12, + "x": 0, "y": 8 }, "hiddenSeries": false, - "id": 6, + "id": 5, "legend": { "avg": false, "current": false, @@ -390,8 +258,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "7.5.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -401,25 +272,26 @@ "steppedLine": false, "targets": [ { - "expr": "Rialto_to_Millau_Sync_system_average_load", + "exemplar": true, + "expr": "Millau_to_Rialto_MessageLane_00000000_millau_storage_proof_overhead", "interval": "", - "legendFormat": "Average system load in last {{over}}", + "legendFormat": "Actual overhead", "refId": "A" - } - ], - "thresholds": [ + }, { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": null + "exemplar": true, + "expr": "1024", + "hide": false, + "interval": "", + "legendFormat": "At runtime (hardcoded)", + "refId": "B" } ], + "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Average System Load", + "title": "Millau: storage proof overhead", "tooltip": { "shared": true, "sort": 0, @@ -435,6 +307,7 @@ }, "yaxes": [ { + "$$hashKey": "object:111", "format": "short", "label": null, "logBase": 1, @@ -443,6 +316,7 @@ "show": true }, { + "$$hashKey": "object:112", "format": "short", "label": null, "logBase": 1, @@ -456,130 +330,14 @@ "alignLevel": null } }, - { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 6, - "x": 18, - "y": 8 - }, - "id": 12, - "options": { - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "avg_over_time(Rialto_to_Millau_Sync_process_cpu_usage_percentage[1m])", - "instant": true, - "interval": "", - "legendFormat": "1 CPU = 100", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Relay Process CPU Usage ", - "type": "gauge" - }, - { - "datasource": "Prometheus", - "description": "", - "fieldConfig": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 14 - }, - "id": 4, - "options": { - "displayMode": "gradient", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "Rialto_to_Millau_Sync_blocks_in_state", - "instant": true, - "interval": "", - "legendFormat": "{{state}}", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Queued Headers in Relay", - "type": "bargauge" - }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "description": "", "fieldConfig": { - "defaults": { - "custom": {} - }, + "defaults": {}, "overrides": [] }, "fill": 1, @@ -588,10 +346,10 @@ "h": 8, "w": 12, "x": 12, - "y": 16 + "y": 8 }, "hiddenSeries": false, - "id": 10, + "id": 6, "legend": { "avg": false, "current": false, @@ -604,8 +362,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "7.5.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -615,17 +376,26 @@ "steppedLine": false, "targets": [ { - "expr": "Rialto_to_Millau_Sync_process_memory_usage_bytes / 1024 / 1024", + "exemplar": true, + "expr": "Westend_to_Millau_Sync_polkadot_price / Westend_to_Millau_Sync_kusama_price", "interval": "", - "legendFormat": "Process memory, MB", + "legendFormat": "At exchanges (actually Kusama -> Polkadot)", "refId": "A" + }, + { + "exemplar": true, + "expr": "Millau_to_Rialto_MessageLane_00000000_millau_rialto_to_millau_conversion_rate", + "hide": false, + "interval": "", + "legendFormat": "At runtime", + "refId": "B" } ], "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Memory Usage for Relay Process", + "title": "Millau: Rialto -> Millau conversion rate", "tooltip": { "shared": true, "sort": 0, @@ -641,6 +411,7 @@ }, "yaxes": [ { + "$$hashKey": "object:49", "format": "short", "label": null, "logBase": 1, @@ -649,6 +420,7 @@ "show": true }, { + "$$hashKey": "object:50", "format": "short", "label": null, "logBase": 1, @@ -663,32 +435,20 @@ } } ], - "refresh": "5s", - "schemaVersion": 26, + "refresh": "10s", + "schemaVersion": 27, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { - "from": "now-5m", + "from": "now-1h", "to": "now" }, - "timepicker": { - "refresh_intervals": [ - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, + "timepicker": {}, "timezone": "", - "title": "Rialto to Millau Header Sync Dashboard", - "uid": "relay-rialto-to-millau-headers", - "version": 1 + "title": "Rialto+Millau maintenance dashboard", + "uid": "7AuyrjlMz", + "version": 2 } diff --git a/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml b/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml index eb9051515660..16b798b5a25b 100644 --- a/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml +++ b/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml @@ -1,5 +1,4 @@ - targets: - - relay-headers-millau-to-rialto:9616 - - relay-headers-rialto-to-millau:9616 - - relay-messages-millau-to-rialto:9616 - - relay-messages-rialto-to-millau:9616 + - relay-millau-rialto:9616 + - relay-messages-millau-to-rialto-lane-00000001:9616 + - relay-messages-rialto-to-millau-lane-00000001:9616 diff --git a/deployments/bridges/rialto-millau/docker-compose.yml b/deployments/bridges/rialto-millau/docker-compose.yml index 6a9e7e78d6e2..5f00e449c3b0 100644 --- a/deployments/bridges/rialto-millau/docker-compose.yml +++ b/deployments/bridges/rialto-millau/docker-compose.yml @@ -1,4 +1,4 @@ -# Exposed ports: 10016, 10116, 10216, 10316, 10416, 10516 +# Exposed ports: 10016, 10116, 10216, 10316, 10416 version: '3.5' services: @@ -18,9 +18,9 @@ services: LETSENCRYPT_HOST: wss.millau.brucke.link LETSENCRYPT_EMAIL: admin@parity.io - relay-headers-millau-to-rialto: &sub-bridge-relay + relay-millau-rialto: &sub-bridge-relay image: paritytech/substrate-relay - entrypoint: /entrypoints/relay-headers-millau-to-rialto-entrypoint.sh + entrypoint: /entrypoints/relay-millau-rialto-entrypoint.sh volumes: - ./bridges/rialto-millau/entrypoints:/entrypoints environment: @@ -39,45 +39,45 @@ services: - rialto-node-dave - rialto-node-eve - relay-headers-rialto-to-millau: - <<: *sub-bridge-relay - entrypoint: /entrypoints/relay-headers-rialto-to-millau-entrypoint.sh - ports: - - "10116:9616" - - relay-messages-millau-to-rialto: + relay-messages-millau-to-rialto-lane-00000001: <<: *sub-bridge-relay + environment: + MSG_EXCHANGE_GEN_LANE: "00000001" entrypoint: /entrypoints/relay-messages-millau-to-rialto-entrypoint.sh ports: - - "10216:9616" + - "10116:9616" depends_on: - - relay-headers-millau-to-rialto - - relay-headers-rialto-to-millau + - relay-millau-rialto relay-messages-millau-to-rialto-generator: <<: *sub-bridge-relay + environment: + MSG_EXCHANGE_GEN_SECONDARY_LANE: "00000001" entrypoint: /entrypoints/relay-messages-to-rialto-generator-entrypoint.sh ports: - - "10316:9616" + - "10216:9616" depends_on: - - relay-messages-millau-to-rialto + - relay-millau-rialto - relay-messages-rialto-to-millau: + relay-messages-rialto-to-millau-lane-00000001: <<: *sub-bridge-relay + environment: + MSG_EXCHANGE_GEN_LANE: "00000001" entrypoint: /entrypoints/relay-messages-rialto-to-millau-entrypoint.sh ports: - - "10416:9616" + - "10316:9616" depends_on: - - relay-headers-millau-to-rialto - - relay-headers-rialto-to-millau + - relay-millau-rialto relay-messages-rialto-to-millau-generator: <<: *sub-bridge-relay + environment: + MSG_EXCHANGE_GEN_SECONDARY_LANE: "00000001" entrypoint: /entrypoints/relay-messages-to-millau-generator-entrypoint.sh ports: - - "10516:9616" + - "10416:9616" depends_on: - - relay-messages-rialto-to-millau + - relay-millau-rialto # Note: These are being overridden from the top level `monitoring` compose file. grafana-dashboard: diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-headers-rialto-to-millau-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-headers-rialto-to-millau-entrypoint.sh deleted file mode 100755 index 921d92be5d81..000000000000 --- a/deployments/bridges/rialto-millau/entrypoints/relay-headers-rialto-to-millau-entrypoint.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -xeu - -sleep 3 -curl -v http://millau-node-alice:9933/health -curl -v http://rialto-node-alice:9933/health - -/home/user/substrate-relay init-bridge RialtoToMillau \ - --target-host millau-node-alice \ - --target-port 9944 \ - --source-host rialto-node-alice \ - --source-port 9944 \ - --target-signer //Alice - -# Give chain a little bit of time to process initialization transaction -sleep 6 -/home/user/substrate-relay relay-headers RialtoToMillau \ - --target-host millau-node-alice \ - --target-port 9944 \ - --source-host rialto-node-alice \ - --source-port 9944 \ - --target-signer //Charlie \ - --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 e34d11004cf9..96676bad85b0 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 @@ -10,10 +10,11 @@ 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} +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_CMD="/home/user/substrate-relay send-message RialtoToMillau" SHARED_HOST="--source-host rialto-node-bob --source-port 9944" DAVE_SIGNER="--source-signer //Dave --target-signer //Dave" @@ -40,6 +41,14 @@ do --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 \ + --origin Target \ + remark + fi + rand_sleep echo "Sending Transfer from Rialto to Millau using Target Origin" $SEND_MESSAGE \ 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 ae9e87d5e9ab..c24ec8ea7f40 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 @@ -10,10 +10,11 @@ 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} +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_CMD=" /home/user/substrate-relay send-message MillauToRialto" SHARED_HOST="--source-host millau-node-bob --source-port 9944" DAVE_SIGNER="--target-signer //Dave --source-signer //Dave" @@ -40,6 +41,14 @@ do --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 \ + --origin Target \ + remark + fi + rand_sleep echo "Sending Transfer from Millau to Rialto using Target Origin" $SEND_MESSAGE \ diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-headers-millau-to-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh similarity index 53% rename from deployments/bridges/rialto-millau/entrypoints/relay-headers-millau-to-rialto-entrypoint.sh rename to deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh index 2ff6b6ff8193..d8d3290428f0 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-headers-millau-to-rialto-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh @@ -12,12 +12,22 @@ curl -v http://rialto-node-alice:9933/health --target-port 9944 \ --target-signer //Alice -# Give chain a little bit of time to process initialization transaction -sleep 6 -/home/user/substrate-relay relay-headers MillauToRialto \ - --source-host millau-node-alice \ +/home/user/substrate-relay init-bridge RialtoToMillau \ + --source-host rialto-node-alice \ --source-port 9944 \ - --target-host rialto-node-alice \ + --target-host millau-node-alice \ --target-port 9944 \ - --target-signer //Charlie \ + --target-signer //Alice + +# Give chain a little bit of time to process initialization transaction +sleep 6 + +/home/user/substrate-relay relay-headers-and-messages millau-rialto \ + --millau-host millau-node-alice \ + --millau-port 9944 \ + --millau-signer //Charlie \ + --rialto-host rialto-node-alice \ + --rialto-port 9944 \ + --rialto-signer //Charlie \ + --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 ec4e9ed2e6db..e73ddea40f1a 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 @@ -239,7 +239,7 @@ { "expr": "max_over_time(Westend_to_Millau_Sync_best_block_numbers{node=\"source\"}[2m])-min_over_time(Westend_to_Millau_Sync_best_block_numbers{node=\"source\"}[2m])", "interval": "", - "legendFormat": "Number of Westend Headers Synced on Millau", + "legendFormat": "Number of new Headers on Westend (Last 2 Mins)", "refId": "A" } ], 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 d9607a7bd86c..740a9a973960 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,7 +3,7 @@ set -xeu sleep 3 curl -v http://millau-node-alice:9933/health -curl -v http://westend-rpc.polkadot.io:443/health +curl -v https://westend-rpc.polkadot.io:443/health /home/user/substrate-relay init-bridge WestendToMillau \ --source-host westend-rpc.polkadot.io \ diff --git a/deployments/types-millau.json b/deployments/types-millau.json index f768be3c9c9a..2414620733f4 100644 --- a/deployments/types-millau.json +++ b/deployments/types-millau.json @@ -135,6 +135,27 @@ "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" + }, "Fee": "MillauBalance", "Balance": "MillauBalance", "Hash": "MillauBlockHash", diff --git a/deployments/types-rialto.json b/deployments/types-rialto.json index b21814ba2c5c..bd746e003ea1 100644 --- a/deployments/types-rialto.json +++ b/deployments/types-rialto.json @@ -135,6 +135,27 @@ "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" + }, "Fee": "RialtoBalance", "Balance": "RialtoBalance", "BlockHash": "RialtoBlockHash", diff --git a/deployments/types/common.json b/deployments/types/common.json index 923bc0f176f0..cf881288694c 100644 --- a/deployments/types/common.json +++ b/deployments/types/common.json @@ -134,5 +134,26 @@ "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" } } diff --git a/docs/send-message.md b/docs/send-message.md index dad8dc6b2deb..91d3bfd976b5 100644 --- a/docs/send-message.md +++ b/docs/send-message.md @@ -46,22 +46,22 @@ FLAGS: SUBCOMMANDS: help Prints this message or the help of the given subcommand(s) - millau-to-rialto Submit message to given Millau -> Rialto lane - rialto-to-millau Submit message to given Rialto -> Millau lane + MillauToRialto Submit message to given Millau -> Rialto lane + RialtoToMillau Submit message to given Rialto -> Millau lane ``` Messages are send from a source chain to a target chain using a so called `message lane`. Message lanes handle both, message transport and message dispatch. There is one command for submitting a message to each of the two -available bridges, namely `millau-to-rialto` and `rialto-to-millau`. +available bridges, namely `MillauToRialto` and `RialtoToMillau`. Submitting a message requires a number of arguments to be provided. Those arguments are essentially the same -for both submit message commands, hence only the output for `millau-to-rialto` is shown below. +for both submit message commands, hence only the output for `MillauToRialto` is shown below. ``` Submit message to given Millau -> Rialto lane USAGE: - substrate-relay send-message millau-to-rialto [OPTIONS] --lane --source-host --source-port --source-signer --origin --target-signer + substrate-relay send-message MillauToRialto [OPTIONS] --lane --source-host --source-port --source-signer --origin --target-signer FLAGS: -h, --help Prints help information @@ -104,7 +104,7 @@ Usage of the arguments is best explained with an example. Below you can see, how would look like: ``` -substrate-relay send-message millau-to-rialto \ +substrate-relay send-message MillauToRialto \ --source-host=127.0.0.1 \ --source-port=10946 \ --source-signer=//Dave \ diff --git a/modules/dispatch/src/lib.rs b/modules/dispatch/src/lib.rs index 76706d4d1e16..416d080b0c17 100644 --- a/modules/dispatch/src/lib.rs +++ b/modules/dispatch/src/lib.rs @@ -45,6 +45,7 @@ use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; /// Spec version type. pub type SpecVersion = u32; +// TODO [#895] move to primitives /// 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 @@ -89,6 +90,7 @@ pub enum CallOrigin { diff --git a/modules/grandpa/src/benchmarking.rs b/modules/grandpa/src/benchmarking.rs index a3abe508d8a8..cb170fdc8b19 100644 --- a/modules/grandpa/src/benchmarking.rs +++ b/modules/grandpa/src/benchmarking.rs @@ -64,9 +64,7 @@ const MAX_VOTE_ANCESTRIES: u32 = 1000; // The maximum number of pre-commits to include in a justification. In practice this scales with the // number of validators. -// -// TODO [#846]: Right now this will break benchmarking if it is greater than `u8::MAX` -const MAX_VALIDATOR_SET_SIZE: u32 = 255; +const MAX_VALIDATOR_SET_SIZE: u32 = 1024; benchmarks_instance_pallet! { // This is the "gold standard" benchmark for this extrinsic, and it's what should be used to @@ -80,7 +78,7 @@ benchmarks_instance_pallet! { let caller: T::AccountId = whitelisted_caller(); - let authority_list = accounts(p as u8) + let authority_list = accounts(p as u16) .iter() .map(|id| (AuthorityId::from(*id), 1)) .collect::>(); @@ -99,7 +97,7 @@ benchmarks_instance_pallet! { header: header.clone(), round: TEST_GRANDPA_ROUND, set_id: TEST_GRANDPA_SET_ID, - authorities: accounts(p as u8).iter().map(|k| (*k, 1)).collect::>(), + authorities: accounts(p as u16).iter().map(|k| (*k, 1)).collect::>(), votes: v, forks: 1, }; @@ -160,7 +158,7 @@ benchmarks_instance_pallet! { let caller: T::AccountId = whitelisted_caller(); - let authority_list = accounts(p as u8) + let authority_list = accounts(p as u16) .iter() .map(|id| (AuthorityId::from(*id), 1)) .collect::>(); @@ -179,7 +177,7 @@ benchmarks_instance_pallet! { header: header.clone(), round: TEST_GRANDPA_ROUND, set_id: TEST_GRANDPA_SET_ID, - authorities: accounts(p as u8).iter().map(|k| (*k, 1)).collect::>(), + authorities: accounts(p as u16).iter().map(|k| (*k, 1)).collect::>(), votes: p, forks: p, }; diff --git a/modules/grandpa/src/lib.rs b/modules/grandpa/src/lib.rs index 58f58d6aa6dd..9fb7372b0204 100644 --- a/modules/grandpa/src/lib.rs +++ b/modules/grandpa/src/lib.rs @@ -39,16 +39,13 @@ use crate::weights::WeightInfo; use bp_header_chain::justification::GrandpaJustification; +use bp_header_chain::InitializationData; use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf}; -use codec::{Decode, Encode}; use finality_grandpa::voter_set::VoterSet; use frame_support::ensure; use frame_system::{ensure_signed, RawOrigin}; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; use sp_finality_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID}; use sp_runtime::traits::{BadOrigin, Header as HeaderT, Zero}; -use sp_runtime::RuntimeDebug; #[cfg(test)] mod mock; @@ -91,6 +88,14 @@ pub mod pallet { #[pallet::constant] type MaxRequests: Get; + /// Maximal number of finalized headers to keep in the storage. + /// + /// 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. + #[pallet::constant] + type HeadersToKeep: Get; + /// Weights gathered through benchmarking. type WeightInfo: WeightInfo; } @@ -153,10 +158,20 @@ pub mod pallet { verify_justification::(&justification, hash, *number, authority_set)?; let _enacted = try_enact_authority_change::(&finality_target, set_id)?; + let index = >::get(); + let pruning = >::try_get(index); >::put(hash); >::insert(hash, finality_target); + >::insert(index, hash); >::mutate(|count| *count += 1); + // 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); + >::remove(hash); + } + log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash); Ok(().into()) @@ -248,6 +263,15 @@ pub mod pallet { #[pallet::storage] pub(super) type BestFinalized, I: 'static = ()> = StorageValue<_, BridgedBlockHash, ValueQuery>; + /// A ring buffer of imported hashes. Ordered by the insertion time. + #[pallet::storage] + pub(super) type ImportedHashes, I: 'static = ()> = + StorageMap<_, Identity, u32, BridgedBlockHash>; + + /// Current ring buffer position. + #[pallet::storage] + pub(super) type ImportedHashesPointer, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; + /// Headers which have been imported into the pallet. #[pallet::storage] pub(super) type ImportedHeaders, I: 'static = ()> = @@ -484,22 +508,6 @@ impl, I: 'static> Pallet { } } -/// Data required for initializing the bridge pallet. -/// -/// The bridge needs to know where to start its sync from, and this provides that initial context. -#[derive(Default, Encode, Decode, RuntimeDebug, PartialEq, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct InitializationData { - /// The header from which we should start syncing. - pub header: H, - /// The initial authorities of the pallet. - pub authority_list: sp_finality_grandpa::AuthorityList, - /// The ID of the initial authority set. - pub set_id: sp_finality_grandpa::SetId, - /// Should the pallet block transaction immediately after initialization. - pub is_halted: bool, -} - pub(crate) fn find_scheduled_change(header: &H) -> Option> { use sp_runtime::generic::OpaqueDigestItemId; @@ -999,4 +1007,30 @@ mod tests { assert_ok!(submit_finality_proof(7)); }) } + + #[test] + fn should_prune_headers_over_headers_to_keep_parameter() { + run_test(|| { + initialize_substrate_bridge(); + assert_ok!(submit_finality_proof(1)); + let first_header = Pallet::::best_finalized(); + next_block(); + + assert_ok!(submit_finality_proof(2)); + next_block(); + assert_ok!(submit_finality_proof(3)); + next_block(); + assert_ok!(submit_finality_proof(4)); + next_block(); + assert_ok!(submit_finality_proof(5)); + next_block(); + + assert_ok!(submit_finality_proof(6)); + + assert!( + !Pallet::::is_known_header(first_header.hash()), + "First header should be pruned." + ); + }) + } } diff --git a/modules/grandpa/src/mock.rs b/modules/grandpa/src/mock.rs index 7d5901a679c6..20f5ea7bdf7a 100644 --- a/modules/grandpa/src/mock.rs +++ b/modules/grandpa/src/mock.rs @@ -81,6 +81,7 @@ impl frame_system::Config for TestRuntime { parameter_types! { pub const MaxRequests: u32 = 2; + pub const HeadersToKeep: u32 = 5; pub const SessionLength: u64 = 5; pub const NumValidators: u32 = 5; } @@ -88,6 +89,7 @@ parameter_types! { impl grandpa::Config for TestRuntime { type BridgedChain = TestBridgedChain; type MaxRequests = MaxRequests; + type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } diff --git a/modules/messages/rpc/Cargo.toml b/modules/messages/rpc/Cargo.toml deleted file mode 100644 index bb0d1e0c5447..000000000000 --- a/modules/messages/rpc/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "pallet-bridge-messages-rpc" -description = "Module that provides RPC methods specific to pallet-bridge-messages pallet." -version = "0.1.0" -authors = ["Parity Technologies "] -edition = "2018" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" - -[dependencies] -derive_more = "0.99.2" -futures = { version = "0.3.5", features = ["compat"] } -jsonrpc-core = "15.1.0" -jsonrpc-core-client = "15.1.0" -jsonrpc-derive = "15.1.0" -log = "0.4.11" - -# Bridge dependencies - -bp-runtime = { path = "../../../primitives/runtime" } -bp-messages = { path = "../../../primitives/messages" } - -# Substrate Dependencies - -sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-blockchain = { 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" } -sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/modules/messages/rpc/src/error.rs b/modules/messages/rpc/src/error.rs deleted file mode 100644 index 983b53b65ba3..000000000000 --- a/modules/messages/rpc/src/error.rs +++ /dev/null @@ -1,59 +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 . - -//! Possible errors and results of messages pallet RPC calls. - -/// Future Result type. -pub type FutureResult = jsonrpc_core::BoxFuture; - -/// State RPC errors. -#[derive(Debug, derive_more::Display, derive_more::From)] -pub enum Error { - /// When unknown instance id is passed. - #[display(fmt = "Message lane instance is unknown")] - UnknownInstance, - /// Client error. - #[display(fmt = "Client error: {}", _0)] - Client(Box), -} - -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::UnknownInstance => None, - Error::Client(ref err) => Some(&**err), - } - } -} - -impl From for jsonrpc_core::Error { - fn from(e: Error) -> Self { - const UNKNOW_INSTANCE_CODE: i64 = 1; - - match e { - Error::UnknownInstance => jsonrpc_core::Error { - code: jsonrpc_core::ErrorCode::ServerError(UNKNOW_INSTANCE_CODE), - message: "Unknown instance passed".into(), - data: None, - }, - Error::Client(e) => jsonrpc_core::Error { - code: jsonrpc_core::ErrorCode::InternalError, - message: format!("Unknown error occured: {}", e), - data: Some(format!("{:?}", e).into()), - }, - } - } -} diff --git a/modules/messages/rpc/src/lib.rs b/modules/messages/rpc/src/lib.rs deleted file mode 100644 index a53dcfeb0276..000000000000 --- a/modules/messages/rpc/src/lib.rs +++ /dev/null @@ -1,202 +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 . - -//! Pallet that provides RPC methods specific to messages pallet. - -use crate::error::{Error, FutureResult}; - -use bp_messages::{LaneId, MessageNonce}; -use bp_runtime::InstanceId; -use futures::{FutureExt, TryFutureExt}; -use jsonrpc_core::futures::Future as _; -use jsonrpc_derive::rpc; -use sc_client_api::Backend as BackendT; -use sp_blockchain::{Error as BlockchainError, HeaderBackend}; -use sp_core::{storage::StorageKey, Bytes}; -use sp_runtime::{codec::Encode, generic::BlockId, traits::Block as BlockT}; -use sp_state_machine::prove_read; -use sp_trie::StorageProof; -use std::sync::Arc; - -mod error; - -/// Trie-based storage proof that the message(s) with given key(s) have been sent by the bridged chain. -/// SCALE-encoded trie nodes array `Vec>`. -pub type MessagesProof = Bytes; - -/// Trie-based storage proof that the message(s) with given key(s) have been received by the bridged chain. -/// SCALE-encoded trie nodes array `Vec>`. -pub type MessagesDeliveryProof = Bytes; - -/// Runtime adapter. -pub trait Runtime: Send + Sync + 'static { - /// Return runtime storage key for given message. May return None if instance is unknown. - fn message_key(&self, instance: &InstanceId, lane: &LaneId, nonce: MessageNonce) -> Option; - /// Return runtime storage key for outbound lane state. May return None if instance is unknown. - fn outbound_lane_data_key(&self, instance: &InstanceId, lane: &LaneId) -> Option; - /// Return runtime storage key for inbound lane state. May return None if instance is unknown. - fn inbound_lane_data_key(&self, instance: &InstanceId, lane: &LaneId) -> Option; -} - -/// Provides RPC methods for interacting with messages pallet. -#[rpc] -pub trait MessagesApi { - /// Returns storage proof of messages in given inclusive range. The state of outbound - /// lane is included in the proof if `include_outbound_lane_state` is true. - #[rpc(name = "messages_proveMessages")] - fn prove_messages( - &self, - instance: InstanceId, - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - include_outbound_lane_state: bool, - block: Option, - ) -> FutureResult; - - /// Returns proof-of-message(s) delivery. - #[rpc(name = "messages_proveMessagesDelivery")] - fn prove_messages_delivery( - &self, - instance: InstanceId, - lane: LaneId, - block: Option, - ) -> FutureResult; -} - -/// Implements the MessagesApi trait for interacting with message lanes. -pub struct MessagesRpcHandler { - backend: Arc, - runtime: Arc, - _phantom: std::marker::PhantomData, -} - -impl MessagesRpcHandler { - /// Creates new mesage lane RPC handler. - pub fn new(backend: Arc, runtime: Arc) -> Self { - Self { - backend, - runtime, - _phantom: Default::default(), - } - } -} - -impl MessagesApi for MessagesRpcHandler -where - Block: BlockT, - Backend: BackendT + 'static, - R: Runtime, -{ - fn prove_messages( - &self, - instance: InstanceId, - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - include_outbound_lane_state: bool, - block: Option, - ) -> FutureResult { - let runtime = self.runtime.clone(); - let outbound_lane_data_key = if include_outbound_lane_state { - Some(runtime.outbound_lane_data_key(&instance, &lane)) - } else { - None - }; - let messages_count = if end >= begin { end - begin + 1 } else { 0 }; - Box::new( - prove_keys_read( - self.backend.clone(), - block, - (begin..=end) - .map(move |nonce| runtime.message_key(&instance, &lane, nonce)) - .chain(outbound_lane_data_key.into_iter()), - ) - .boxed() - .compat() - .map(move |proof| { - let serialized_proof = serialize_storage_proof(proof); - log::trace!( - "Generated proof of {} messages. Size: {}", - messages_count, - serialized_proof.len() - ); - serialized_proof - }) - .map_err(Into::into), - ) - } - - fn prove_messages_delivery( - &self, - instance: InstanceId, - lane: LaneId, - block: Option, - ) -> FutureResult { - Box::new( - prove_keys_read( - self.backend.clone(), - block, - vec![self.runtime.inbound_lane_data_key(&instance, &lane)], - ) - .boxed() - .compat() - .map(|proof| { - let serialized_proof = serialize_storage_proof(proof); - log::trace!("Generated message delivery proof. Size: {}", serialized_proof.len()); - serialized_proof - }) - .map_err(Into::into), - ) - } -} - -async fn prove_keys_read( - backend: Arc, - block: Option, - keys: impl IntoIterator>, -) -> Result -where - Block: BlockT, - Backend: BackendT + 'static, -{ - let block = unwrap_or_best(&*backend, block); - let state = backend.state_at(BlockId::Hash(block)).map_err(blockchain_err)?; - let keys = keys - .into_iter() - .map(|key| key.ok_or(Error::UnknownInstance).map(|key| key.0)) - .collect::, _>>()?; - let storage_proof = prove_read(state, keys) - .map_err(BlockchainError::Execution) - .map_err(blockchain_err)?; - Ok(storage_proof) -} - -fn serialize_storage_proof(proof: StorageProof) -> Bytes { - let raw_nodes: Vec> = proof.iter_nodes().map(Into::into).collect(); - raw_nodes.encode().into() -} - -fn unwrap_or_best(backend: &impl BackendT, block: Option) -> Block::Hash { - match block { - Some(block) => block, - None => backend.blockchain().info().best_hash, - } -} - -fn blockchain_err(err: BlockchainError) -> Error { - Error::Client(Box::new(err)) -} diff --git a/primitives/chain-rococo/src/lib.rs b/primitives/chain-rococo/src/lib.rs index 7ee6dabef7be..cc3eb47b1b76 100644 --- a/primitives/chain-rococo/src/lib.rs +++ b/primitives/chain-rococo/src/lib.rs @@ -42,14 +42,33 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { transaction_version: 6, }; +/// 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: https://github.com/paritytech/polkadot/blob/master/runtime/rococo/src/lib.rs #[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)] -#[allow(non_camel_case_types)] pub enum Call { - MockPallet, + /// Westend bridge pallet. + #[codec(index = 40)] + BridgeGrandpaWestend(BridgeGrandpaWestendCall), +} + +#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)] +#[allow(non_camel_case_types)] +pub enum BridgeGrandpaWestendCall { + #[codec(index = 0)] submit_finality_proof( ::Header, bp_header_chain::justification::GrandpaJustification<::Header>, ), + #[codec(index = 1)] + initialize(bp_header_chain::InitializationData<::Header>), } impl sp_runtime::traits::Dispatchable for Call { diff --git a/primitives/chain-westend/src/lib.rs b/primitives/chain-westend/src/lib.rs index 5019fbe87530..dbbfabd5dcf2 100644 --- a/primitives/chain-westend/src/lib.rs +++ b/primitives/chain-westend/src/lib.rs @@ -43,15 +43,33 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { transaction_version: 5, }; +/// Westend Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to Westend 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 Westend +/// `construct_runtime`, so that we maintain SCALE-compatibility. +/// +/// See: https://github.com/paritytech/polkadot/blob/master/runtime/westend/src/lib.rs #[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)] -#[allow(non_camel_case_types)] pub enum Call { - MockPallet, + /// Rococo bridge pallet. + #[codec(index = 40)] + BridgeGrandpaRococo(BridgeGrandpaRococoCall), +} + +#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, PartialEq, Eq, Clone)] +#[allow(non_camel_case_types)] +pub enum BridgeGrandpaRococoCall { + #[codec(index = 0)] submit_finality_proof( ::Header, bp_header_chain::justification::GrandpaJustification<::Header>, ), - initialize, + #[codec(index = 1)] + initialize(bp_header_chain::InitializationData<::Header>), } impl sp_runtime::traits::Dispatchable for Call { diff --git a/primitives/header-chain/src/lib.rs b/primitives/header-chain/src/lib.rs index d33a6d36eb1b..adac6eb26880 100644 --- a/primitives/header-chain/src/lib.rs +++ b/primitives/header-chain/src/lib.rs @@ -55,6 +55,22 @@ impl AuthoritySet { } } +/// Data required for initializing the bridge pallet. +/// +/// The bridge needs to know where to start its sync from, and this provides that initial context. +#[derive(Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct InitializationData { + /// The header from which we should start syncing. + pub header: H, + /// The initial authorities of the pallet. + 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, +} + /// base trait for verifying transaction inclusion proofs. pub trait InclusionProofVerifier { /// Transaction type. diff --git a/primitives/test-utils/Cargo.toml b/primitives/test-utils/Cargo.toml index 64a85a2c6709..5adb2c2b55f5 100644 --- a/primitives/test-utils/Cargo.toml +++ b/primitives/test-utils/Cargo.toml @@ -9,10 +9,11 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" bp-header-chain = { path = "../header-chain", default-features = false } ed25519-dalek = { version = "1.0", default-features = false, features = ["u64_backend"] } finality-grandpa = { version = "0.14.0", default-features = false } +parity-scale-codec = { version = "2.0.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 } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } -sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [features] default = ["std"] @@ -20,8 +21,9 @@ std = [ "bp-header-chain/std", "ed25519-dalek/std", "finality-grandpa/std", + "parity-scale-codec/std", + "sp-application-crypto/std", "sp-finality-grandpa/std", "sp-runtime/std", "sp-std/std", - "sp-application-crypto/std", ] diff --git a/primitives/test-utils/src/keyring.rs b/primitives/test-utils/src/keyring.rs index fbc1496e1635..6c5b1cae9114 100644 --- a/primitives/test-utils/src/keyring.rs +++ b/primitives/test-utils/src/keyring.rs @@ -18,6 +18,7 @@ use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature}; use finality_grandpa::voter_set::VoterSet; +use parity_scale_codec::Encode; use sp_application_crypto::Public; use sp_finality_grandpa::{AuthorityId, AuthorityList, AuthorityWeight}; use sp_runtime::RuntimeDebug; @@ -33,7 +34,7 @@ pub const FERDIE: Account = Account(5); /// A test account which can be used to sign messages. #[derive(RuntimeDebug, Clone, Copy)] -pub struct Account(pub u8); +pub struct Account(pub u16); impl Account { pub fn public(&self) -> PublicKey { @@ -41,7 +42,10 @@ impl Account { } pub fn secret(&self) -> SecretKey { - SecretKey::from_bytes(&[self.0; 32]).expect("A static array of the correct length is a known good.") + let data = self.0.encode(); + let mut bytes = [0_u8; 32]; + bytes[0..data.len()].copy_from_slice(&*data); + SecretKey::from_bytes(&bytes).expect("A static array of the correct length is a known good.") } pub fn pair(&self) -> Keypair { @@ -87,6 +91,6 @@ pub fn test_keyring() -> Vec<(Account, AuthorityWeight)> { } /// Get a list of "unique" accounts. -pub fn accounts(len: u8) -> Vec { +pub fn accounts(len: u16) -> Vec { (0..len).into_iter().map(Account).collect() } diff --git a/primitives/test-utils/src/lib.rs b/primitives/test-utils/src/lib.rs index 39652fc83aeb..0fcc263763c3 100644 --- a/primitives/test-utils/src/lib.rs +++ b/primitives/test-utils/src/lib.rs @@ -212,16 +212,19 @@ fn signed_precommit( /// /// The correct parent hash will be used if given a non-zero header. pub fn test_header(number: H::Number) -> H { - let mut header = H::new( - number, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ); + let default = |num| { + H::new( + num, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ) + }; + let mut header = default(number); if number != Zero::zero() { - let parent_hash = test_header::(number - One::one()).hash(); + let parent_hash = default(number - One::one()).hash(); header.set_parent_hash(parent_hash); } diff --git a/relays/bin-ethereum/src/rialto_client.rs b/relays/bin-ethereum/src/rialto_client.rs index c294edbf4e87..d9c0f265cbb9 100644 --- a/relays/bin-ethereum/src/rialto_client.rs +++ b/relays/bin-ethereum/src/rialto_client.rs @@ -156,7 +156,7 @@ impl SubmitEthereumHeaders for SubstrateClient { ) -> SubmittedHeaders { let ids = headers.iter().map(|header| header.id()).collect(); let submission_result = async { - self.submit_signed_extrinsic(params.public().as_array_ref().clone().into(), |transaction_nonce| { + self.submit_signed_extrinsic((*params.public().as_array_ref()).into(), |transaction_nonce| { Bytes( Rialto::sign_transaction( *self.genesis_hash(), @@ -257,7 +257,7 @@ impl SubmitEthereumExchangeTransactionProof for SubstrateClient { instance: Arc, proof: rialto_runtime::exchange::EthereumTransactionInclusionProof, ) -> RpcResult<()> { - self.submit_signed_extrinsic(params.public().as_array_ref().clone().into(), |transaction_nonce| { + self.submit_signed_extrinsic((*params.public().as_array_ref()).into(), |transaction_nonce| { Bytes( Rialto::sign_transaction( *self.genesis_hash(), diff --git a/relays/bin-substrate/Cargo.toml b/relays/bin-substrate/Cargo.toml index a76174e58fbe..d203201e60a4 100644 --- a/relays/bin-substrate/Cargo.toml +++ b/relays/bin-substrate/Cargo.toml @@ -13,6 +13,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.12" hex = "0.4" log = "0.4.14" +num-format = "0.4" num-traits = "0.2" paste = "1.0" structopt = "0.3" @@ -35,7 +36,6 @@ headers-relay = { path = "../headers" } 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" } relay-kusama-client = { path = "../client-kusama" } relay-millau-client = { path = "../client-millau" } @@ -58,3 +58,4 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master [dev-dependencies] sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } +hex-literal = "0.3" diff --git a/relays/bin-substrate/src/chains/millau.rs b/relays/bin-substrate/src/chains/millau.rs new file mode 100644 index 000000000000..ac5e611fdbcb --- /dev/null +++ b/relays/bin-substrate/src/chains/millau.rs @@ -0,0 +1,101 @@ +// 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 chain specification for CLI. + +use crate::cli::{ + bridge, + encode_call::{self, Call, CliEncodeCall}, + encode_message, send_message, CliChain, +}; +use codec::Decode; +use frame_support::weights::{GetDispatchInfo, Weight}; +use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; +use relay_millau_client::Millau; +use sp_version::RuntimeVersion; + +impl CliEncodeCall for Millau { + fn max_extrinsic_size() -> u32 { + bp_millau::max_extrinsic_size() + } + + fn encode_call(call: &Call) -> anyhow::Result { + Ok(match call { + Call::Raw { data } => Decode::decode(&mut &*data.0)?, + Call::Remark { remark_payload, .. } => millau_runtime::Call::System(millau_runtime::SystemCall::remark( + remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), + )), + Call::Transfer { recipient, amount } => millau_runtime::Call::Balances( + millau_runtime::BalancesCall::transfer(recipient.raw_id(), amount.cast()), + ), + 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.0, + payload, + fee.cast(), + )) + } + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }, + }) + } +} + +impl CliChain for Millau { + const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = MessagePayload>; + + fn ss58_format() -> u16 { + millau_runtime::SS58Prefix::get() as u16 + } + + fn max_extrinsic_weight() -> Weight { + bp_millau::max_extrinsic_weight() + } + + // TODO [#854|#843] support multiple bridges? + fn encode_message(message: encode_message::MessagePayload) -> Result { + match message { + encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) + .map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)), + encode_message::MessagePayload::Call { mut call, mut sender } => { + 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).map_err(|e| e.to_string())?; + let weight = call.get_dispatch_info().weight; + + Ok(send_message::message_payload(spec_version, weight, origin, &call)) + } + } + } +} diff --git a/relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs b/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs similarity index 97% rename from relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs rename to relays/bin-substrate/src/chains/millau_headers_to_rialto.rs index 3091df31ff1e..58f0620b0764 100644 --- a/relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs +++ b/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs @@ -34,7 +34,7 @@ impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { type TargetChain = Rialto; fn transactions_author(&self) -> bp_rialto::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_submit_finality_proof_transaction( diff --git a/relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs b/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs similarity index 74% rename from relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs rename to relays/bin-substrate/src/chains/millau_messages_to_rialto.rs index 0e80aacc176d..d96fa7b79720 100644 --- a/relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs +++ b/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs @@ -16,12 +16,13 @@ //! Millau-to-Rialto messages sync entrypoint. -use super::{MillauClient, RialtoClient}; -use crate::messages_lane::{select_delivery_transaction_limits, SubstrateMessageLane, SubstrateMessageLaneToSubstrate}; +use crate::messages_lane::{ + select_delivery_transaction_limits, MessagesRelayParams, SubstrateMessageLane, SubstrateMessageLaneToSubstrate, +}; use crate::messages_source::SubstrateMessagesSource; use crate::messages_target::SubstrateMessagesTarget; -use bp_messages::{LaneId, MessageNonce}; +use bp_messages::MessageNonce; use bp_runtime::{MILLAU_BRIDGE_INSTANCE, RIALTO_BRIDGE_INSTANCE}; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; use codec::Encode; @@ -33,12 +34,12 @@ use relay_substrate_client::{ metrics::{FloatStorageValueMetric, StorageProofOverheadMetric}, Chain, TransactionSignScheme, }; -use relay_utils::metrics::MetricsParams; use sp_core::{Bytes, Pair}; use std::{ops::RangeInclusive, time::Duration}; /// Millau-to-Rialto message lane. -type MillauMessagesToRialto = SubstrateMessageLaneToSubstrate; +pub type MillauMessagesToRialto = + SubstrateMessageLaneToSubstrate; impl SubstrateMessageLane for MillauMessagesToRialto { const OUTBOUND_LANE_MESSAGES_DISPATCH_WEIGHT_METHOD: &'static str = @@ -59,7 +60,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { type TargetChain = Rialto; fn source_transactions_author(&self) -> bp_rialto::AccountId { - self.source_sign.public().as_array_ref().clone().into() + (*self.source_sign.public().as_array_ref()).into() } fn make_messages_receiving_proof_transaction( @@ -86,7 +87,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { } fn target_transactions_author(&self) -> bp_rialto::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_messages_delivery_transaction( @@ -126,28 +127,35 @@ impl SubstrateMessageLane for MillauMessagesToRialto { } /// Millau node as messages source. -type MillauSourceClient = SubstrateMessagesSource; +type MillauSourceClient = SubstrateMessagesSource< + Millau, + MillauMessagesToRialto, + millau_runtime::Runtime, + millau_runtime::WithRialtoMessagesInstance, +>; /// Rialto node as messages target. -type RialtoTargetClient = SubstrateMessagesTarget; +type RialtoTargetClient = SubstrateMessagesTarget< + Rialto, + MillauMessagesToRialto, + rialto_runtime::Runtime, + rialto_runtime::WithMillauMessagesInstance, +>; /// Run Millau-to-Rialto messages sync. pub async fn run( - millau_client: MillauClient, - millau_sign: MillauSigningParams, - rialto_client: RialtoClient, - rialto_sign: RialtoSigningParams, - lane_id: LaneId, - metrics_params: MetricsParams, + params: MessagesRelayParams, ) -> Result<(), String> { let stall_timeout = Duration::from_secs(5 * 60); - let relayer_id_at_millau = millau_sign.public().as_array_ref().clone().into(); + let relayer_id_at_millau = (*params.source_sign.public().as_array_ref()).into(); + let lane_id = params.lane_id; + let source_client = params.source_client; let lane = MillauMessagesToRialto { - source_client: millau_client.clone(), - source_sign: millau_sign, - target_client: rialto_client.clone(), - target_sign: rialto_sign, + source_client: source_client.clone(), + source_sign: params.source_sign, + target_client: params.target_client.clone(), + target_sign: params.target_sign, relayer_id_at_source: relayer_id_at_millau, }; @@ -188,26 +196,48 @@ pub async fn run( max_messages_size_in_single_batch, }, }, - MillauSourceClient::new(millau_client.clone(), lane.clone(), lane_id, RIALTO_BRIDGE_INSTANCE), - RialtoTargetClient::new(rialto_client, lane, lane_id, MILLAU_BRIDGE_INSTANCE), + MillauSourceClient::new( + source_client.clone(), + lane.clone(), + lane_id, + RIALTO_BRIDGE_INSTANCE, + params.target_to_source_headers_relay, + ), + RialtoTargetClient::new( + params.target_client, + lane, + lane_id, + MILLAU_BRIDGE_INSTANCE, + params.source_to_target_headers_relay, + ), relay_utils::relay_metrics( - messages_relay::message_lane_loop::metrics_prefix::(&lane_id), - metrics_params.address, + Some(messages_relay::message_lane_loop::metrics_prefix::< + MillauMessagesToRialto, + >(&lane_id)), + params.metrics_params, ) - .standalone_metric(StorageProofOverheadMetric::new( - millau_client.clone(), - (bp_runtime::RIALTO_BRIDGE_INSTANCE, lane_id), - millau_runtime::rialto_messages::inbound_lane_data_key(&lane_id), - "millau_storage_proof_overhead".into(), - "Millau storage proof overhead".into(), - ))? - .standalone_metric(FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( - millau_client, - sp_core::storage::StorageKey(millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec()), - Some(millau_runtime::rialto_messages::INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE), - "millau_rialto_to_millau_conversion_rate".into(), - "Rialto to Millau tokens conversion rate (used by Rialto)".into(), - ))? + .standalone_metric(|registry, prefix| { + StorageProofOverheadMetric::new( + registry, + prefix, + source_client.clone(), + "millau_storage_proof_overhead".into(), + "Millau storage proof overhead".into(), + ) + })? + .standalone_metric(|registry, prefix| { + FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( + registry, + prefix, + source_client, + sp_core::storage::StorageKey( + millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec(), + ), + Some(millau_runtime::rialto_messages::INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE), + "millau_rialto_to_millau_conversion_rate".into(), + "Rialto to Millau tokens conversion rate (used by Rialto)".into(), + ) + })? .into_params(), futures::future::pending(), ) diff --git a/relays/bin-substrate/src/chains/mod.rs b/relays/bin-substrate/src/chains/mod.rs new file mode 100644 index 000000000000..1f6b4134ce84 --- /dev/null +++ b/relays/bin-substrate/src/chains/mod.rs @@ -0,0 +1,331 @@ +// 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 . + +//! Chain-specific relayer configuration. + +pub mod millau_headers_to_rialto; +pub mod millau_messages_to_rialto; +pub mod rialto_headers_to_millau; +pub mod rialto_messages_to_millau; +pub mod rococo_headers_to_westend; +pub mod westend_headers_to_millau; +pub mod westend_headers_to_rococo; + +mod millau; +mod rialto; +mod rococo; +mod westend; + +use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams}; + +pub(crate) fn add_polkadot_kusama_price_metrics( + params: MetricsParams, +) -> anyhow::Result { + Ok( + relay_utils::relay_metrics(Some(finality_relay::metrics_prefix::()), params) + // Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama + // relays, but we want to test metrics/dashboards in advance + .standalone_metric(|registry, prefix| { + FloatJsonValueMetric::new( + registry, + prefix, + "https://api.coingecko.com/api/v3/simple/price?ids=Polkadot&vs_currencies=usd".into(), + "$.polkadot.usd".into(), + "polkadot_price".into(), + "Polkadot price in USD".into(), + ) + }) + .map_err(|e| anyhow::format_err!("{}", e))? + .standalone_metric(|registry, prefix| { + FloatJsonValueMetric::new( + registry, + prefix, + "https://api.coingecko.com/api/v3/simple/price?ids=Kusama&vs_currencies=usd".into(), + "$.kusama.usd".into(), + "kusama_price".into(), + "Kusama price in USD".into(), + ) + }) + .map_err(|e| anyhow::format_err!("{}", e))? + .into_params(), + ) +} + +#[cfg(test)] +mod tests { + use crate::cli::{encode_call, send_message}; + use bp_messages::source_chain::TargetHeaderChain; + use codec::Encode; + use frame_support::dispatch::GetDispatchInfo; + use relay_millau_client::Millau; + use relay_rialto_client::Rialto; + use relay_substrate_client::TransactionSignScheme; + 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(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::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(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::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() { + use rialto_runtime::millau_messages::Millau; + + let maximal_remark_size = encode_call::compute_maximal_message_arguments_size( + bp_rialto::max_extrinsic_size(), + bp_millau::max_extrinsic_size(), + ); + + let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into(); + let payload = send_message::message_payload( + Default::default(), + call.get_dispatch_info().weight, + pallet_bridge_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert_eq!(Millau::verify_message(&payload), Ok(())); + + let call: millau_runtime::Call = + millau_runtime::SystemCall::remark(vec![42; (maximal_remark_size + 1) as _]).into(); + let payload = send_message::message_payload( + Default::default(), + call.get_dispatch_info().weight, + pallet_bridge_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert!(Millau::verify_message(&payload).is_err()); + } + + #[test] + fn maximal_size_remark_to_rialto_is_generated_correctly() { + assert!( + bridge_runtime_common::messages::target::maximal_incoming_message_size( + bp_rialto::max_extrinsic_size() + ) > bp_millau::max_extrinsic_size(), + "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::max_extrinsic_weight()); + let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into(); + + let payload = send_message::message_payload( + Default::default(), + maximal_dispatch_weight, + pallet_bridge_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert_eq!(Millau::verify_message(&payload), Ok(())); + + let payload = send_message::message_payload( + Default::default(), + maximal_dispatch_weight + 1, + pallet_bridge_dispatch::CallOrigin::SourceRoot, + &call, + ); + 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::max_extrinsic_weight()); + let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into(); + + let payload = send_message::message_payload( + Default::default(), + maximal_dispatch_weight, + pallet_bridge_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert_eq!(Rialto::verify_message(&payload), Ok(())); + + let payload = send_message::message_payload( + Default::default(), + maximal_dispatch_weight + 1, + pallet_bridge_dispatch::CallOrigin::SourceRoot, + &call, + ); + 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(vec![])); + let rialto_tx = Rialto::sign_transaction( + Default::default(), + &sp_keyring::AccountKeyring::Alice.pair(), + 0, + rialto_call.clone(), + ); + let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); + assert!( + bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, + "Hardcoded number of extra bytes in Rialto transaction {} is lower than actual value: {}", + bp_rialto::TX_EXTRA_BYTES, + extra_bytes_in_transaction, + ); + } + + #[test] + fn millau_tx_extra_bytes_constant_is_correct() { + let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![])); + let millau_tx = Millau::sign_transaction( + Default::default(), + &sp_keyring::AccountKeyring::Alice.pair(), + 0, + millau_call.clone(), + ); + let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); + assert!( + bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, + "Hardcoded number of extra bytes in Millau transaction {} is lower than actual value: {}", + bp_millau::TX_EXTRA_BYTES, + extra_bytes_in_transaction, + ); + } +} + +#[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 = bp_rococo::BridgeGrandpaWestendCall::submit_finality_proof(header.clone(), justification.clone()); + let expected = millau_runtime::BridgeGrandpaRialtoCall::::submit_finality_proof( + header, + justification, + ); + + // when + let actual_encoded = actual.encode(); + let expected_encoded = expected.encode(); + + // then + assert_eq!( + actual_encoded, expected_encoded, + "Encoding difference. Raw: {:?} vs {:?}", + 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 = bp_westend::BridgeGrandpaRococoCall::submit_finality_proof(header.clone(), justification.clone()); + let expected = millau_runtime::BridgeGrandpaRialtoCall::::submit_finality_proof( + header, + justification, + ); + + // when + let actual_encoded = actual.encode(); + let expected_encoded = expected.encode(); + + // then + assert_eq!( + actual_encoded, expected_encoded, + "Encoding difference. Raw: {:?} vs {:?}", + actual, expected + ); + } +} diff --git a/relays/bin-substrate/src/chains/rialto.rs b/relays/bin-substrate/src/chains/rialto.rs new file mode 100644 index 000000000000..25c1ab04c9fd --- /dev/null +++ b/relays/bin-substrate/src/chains/rialto.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 . + +//! Rialto chain specification for CLI. + +use crate::cli::{ + bridge, + encode_call::{self, Call, CliEncodeCall}, + encode_message, send_message, CliChain, +}; +use codec::Decode; +use frame_support::weights::{GetDispatchInfo, Weight}; +use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; +use relay_rialto_client::Rialto; +use sp_version::RuntimeVersion; + +impl CliEncodeCall for Rialto { + fn max_extrinsic_size() -> u32 { + bp_rialto::max_extrinsic_size() + } + + fn encode_call(call: &Call) -> anyhow::Result { + Ok(match call { + Call::Raw { data } => Decode::decode(&mut &*data.0)?, + Call::Remark { remark_payload, .. } => rialto_runtime::Call::System(rialto_runtime::SystemCall::remark( + remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), + )), + Call::Transfer { recipient, amount } => { + rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount.0)) + } + 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.0, payload, fee.0, + )) + } + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }, + }) + } +} + +impl CliChain for Rialto { + const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = MessagePayload>; + + fn ss58_format() -> u16 { + rialto_runtime::SS58Prefix::get() as u16 + } + + fn max_extrinsic_weight() -> Weight { + bp_rialto::max_extrinsic_weight() + } + + fn encode_message(message: encode_message::MessagePayload) -> Result { + match message { + encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) + .map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)), + encode_message::MessagePayload::Call { mut call, mut sender } => { + 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).map_err(|e| e.to_string())?; + let weight = call.get_dispatch_info().weight; + + Ok(send_message::message_payload(spec_version, weight, origin, &call)) + } + } + } +} diff --git a/relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs b/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs similarity index 97% rename from relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs rename to relays/bin-substrate/src/chains/rialto_headers_to_millau.rs index 1c36991fd272..39295c89433e 100644 --- a/relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs +++ b/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs @@ -34,7 +34,7 @@ impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { type TargetChain = Millau; fn transactions_author(&self) -> bp_millau::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_submit_finality_proof_transaction( diff --git a/relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs b/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs similarity index 74% rename from relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs rename to relays/bin-substrate/src/chains/rialto_messages_to_millau.rs index ed231cd208e9..ec39a4caa3fc 100644 --- a/relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs +++ b/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs @@ -16,12 +16,13 @@ //! Rialto-to-Millau messages sync entrypoint. -use super::{MillauClient, RialtoClient}; -use crate::messages_lane::{select_delivery_transaction_limits, SubstrateMessageLane, SubstrateMessageLaneToSubstrate}; +use crate::messages_lane::{ + select_delivery_transaction_limits, MessagesRelayParams, SubstrateMessageLane, SubstrateMessageLaneToSubstrate, +}; use crate::messages_source::SubstrateMessagesSource; use crate::messages_target::SubstrateMessagesTarget; -use bp_messages::{LaneId, MessageNonce}; +use bp_messages::MessageNonce; use bp_runtime::{MILLAU_BRIDGE_INSTANCE, RIALTO_BRIDGE_INSTANCE}; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; use codec::Encode; @@ -33,12 +34,12 @@ use relay_substrate_client::{ metrics::{FloatStorageValueMetric, StorageProofOverheadMetric}, Chain, TransactionSignScheme, }; -use relay_utils::metrics::MetricsParams; use sp_core::{Bytes, Pair}; use std::{ops::RangeInclusive, time::Duration}; /// Rialto-to-Millau message lane. -type RialtoMessagesToMillau = SubstrateMessageLaneToSubstrate; +pub type RialtoMessagesToMillau = + SubstrateMessageLaneToSubstrate; impl SubstrateMessageLane for RialtoMessagesToMillau { const OUTBOUND_LANE_MESSAGES_DISPATCH_WEIGHT_METHOD: &'static str = @@ -59,7 +60,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { type TargetChain = Millau; fn source_transactions_author(&self) -> bp_rialto::AccountId { - self.source_sign.public().as_array_ref().clone().into() + (*self.source_sign.public().as_array_ref()).into() } fn make_messages_receiving_proof_transaction( @@ -86,7 +87,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { } fn target_transactions_author(&self) -> bp_rialto::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_messages_delivery_transaction( @@ -126,28 +127,35 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { } /// Rialto node as messages source. -type RialtoSourceClient = SubstrateMessagesSource; +type RialtoSourceClient = SubstrateMessagesSource< + Rialto, + RialtoMessagesToMillau, + rialto_runtime::Runtime, + rialto_runtime::WithMillauMessagesInstance, +>; /// Millau node as messages target. -type MillauTargetClient = SubstrateMessagesTarget; +type MillauTargetClient = SubstrateMessagesTarget< + Millau, + RialtoMessagesToMillau, + millau_runtime::Runtime, + millau_runtime::WithRialtoMessagesInstance, +>; /// Run Rialto-to-Millau messages sync. pub async fn run( - rialto_client: RialtoClient, - rialto_sign: RialtoSigningParams, - millau_client: MillauClient, - millau_sign: MillauSigningParams, - lane_id: LaneId, - metrics_params: MetricsParams, + params: MessagesRelayParams, ) -> Result<(), String> { let stall_timeout = Duration::from_secs(5 * 60); - let relayer_id_at_rialto = rialto_sign.public().as_array_ref().clone().into(); + let relayer_id_at_rialto = (*params.source_sign.public().as_array_ref()).into(); + let lane_id = params.lane_id; + let source_client = params.source_client; let lane = RialtoMessagesToMillau { - source_client: rialto_client.clone(), - source_sign: rialto_sign, - target_client: millau_client.clone(), - target_sign: millau_sign, + source_client: source_client.clone(), + source_sign: params.source_sign, + target_client: params.target_client.clone(), + target_sign: params.target_sign, relayer_id_at_source: relayer_id_at_rialto, }; @@ -187,26 +195,48 @@ pub async fn run( max_messages_size_in_single_batch, }, }, - RialtoSourceClient::new(rialto_client.clone(), lane.clone(), lane_id, MILLAU_BRIDGE_INSTANCE), - MillauTargetClient::new(millau_client, lane, lane_id, RIALTO_BRIDGE_INSTANCE), + RialtoSourceClient::new( + source_client.clone(), + lane.clone(), + lane_id, + MILLAU_BRIDGE_INSTANCE, + params.target_to_source_headers_relay, + ), + MillauTargetClient::new( + params.target_client, + lane, + lane_id, + RIALTO_BRIDGE_INSTANCE, + params.source_to_target_headers_relay, + ), relay_utils::relay_metrics( - messages_relay::message_lane_loop::metrics_prefix::(&lane_id), - metrics_params.address, + Some(messages_relay::message_lane_loop::metrics_prefix::< + RialtoMessagesToMillau, + >(&lane_id)), + params.metrics_params, ) - .standalone_metric(StorageProofOverheadMetric::new( - rialto_client.clone(), - (bp_runtime::MILLAU_BRIDGE_INSTANCE, lane_id), - rialto_runtime::millau_messages::inbound_lane_data_key(&lane_id), - "rialto_storage_proof_overhead".into(), - "Rialto storage proof overhead".into(), - ))? - .standalone_metric(FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( - rialto_client, - sp_core::storage::StorageKey(rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec()), - Some(rialto_runtime::millau_messages::INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE), - "rialto_millau_to_rialto_conversion_rate".into(), - "Millau to Rialto tokens conversion rate (used by Millau)".into(), - ))? + .standalone_metric(|registry, prefix| { + StorageProofOverheadMetric::new( + registry, + prefix, + source_client.clone(), + "rialto_storage_proof_overhead".into(), + "Rialto storage proof overhead".into(), + ) + })? + .standalone_metric(|registry, prefix| { + FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( + registry, + prefix, + source_client, + sp_core::storage::StorageKey( + rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec(), + ), + Some(rialto_runtime::millau_messages::INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE), + "rialto_millau_to_rialto_conversion_rate".into(), + "Millau to Rialto tokens conversion rate (used by Millau)".into(), + ) + })? .into_params(), futures::future::pending(), ) diff --git a/relays/bin-substrate/src/chains/rococo.rs b/relays/bin-substrate/src/chains/rococo.rs new file mode 100644 index 000000000000..0bcf388c3462 --- /dev/null +++ b/relays/bin-substrate/src/chains/rococo.rs @@ -0,0 +1,39 @@ +// 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::{encode_message, CliChain}; +use frame_support::weights::Weight; +use relay_rococo_client::Rococo; +use sp_version::RuntimeVersion; + +impl CliChain for Rococo { + const RUNTIME_VERSION: RuntimeVersion = bp_rococo::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = (); + + fn ss58_format() -> u16 { + 42 + } + + fn max_extrinsic_weight() -> Weight { + 0 + } + + fn encode_message(_message: encode_message::MessagePayload) -> Result { + Err("Sending messages from Rococo is not yet supported.".into()) + } +} diff --git a/relays/bin-substrate/src/rialto_millau/rococo_headers_to_westend.rs b/relays/bin-substrate/src/chains/rococo_headers_to_westend.rs similarity index 62% rename from relays/bin-substrate/src/rialto_millau/rococo_headers_to_westend.rs rename to relays/bin-substrate/src/chains/rococo_headers_to_westend.rs index e4a1aa52bcd9..dca91adb3df6 100644 --- a/relays/bin-substrate/src/rialto_millau/rococo_headers_to_westend.rs +++ b/relays/bin-substrate/src/chains/rococo_headers_to_westend.rs @@ -22,7 +22,7 @@ use bp_header_chain::justification::GrandpaJustification; use codec::Encode; use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader}; use relay_substrate_client::{Chain, TransactionSignScheme}; -use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams}; +use relay_utils::metrics::MetricsParams; use relay_westend_client::{SigningParams as WestendSigningParams, Westend}; use sp_core::{Bytes, Pair}; @@ -35,30 +35,11 @@ impl SubstrateFinalitySyncPipeline for RococoFinalityToWestend { type TargetChain = Westend; fn customize_metrics(params: MetricsParams) -> anyhow::Result { - Ok( - relay_utils::relay_metrics(finality_relay::metrics_prefix::(), params.address) - // Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama - // relays, but we want to test metrics/dashboards in advance - .standalone_metric(FloatJsonValueMetric::new( - "https://api.coingecko.com/api/v3/simple/price?ids=Polkadot&vs_currencies=usd".into(), - "$.polkadot.usd".into(), - "polkadot_price".into(), - "Polkadot price in USD".into(), - )) - .map_err(|e| anyhow::format_err!("{}", e))? - .standalone_metric(FloatJsonValueMetric::new( - "https://api.coingecko.com/api/v3/simple/price?ids=Kusama&vs_currencies=usd".into(), - "$.kusama.usd".into(), - "kusama_price".into(), - "Kusama price in USD".into(), - )) - .map_err(|e| anyhow::format_err!("{}", e))? - .into_params(), - ) + crate::chains::add_polkadot_kusama_price_metrics::(params) } fn transactions_author(&self) -> bp_westend::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_submit_finality_proof_transaction( @@ -67,13 +48,10 @@ impl SubstrateFinalitySyncPipeline for RococoFinalityToWestend { header: RococoSyncHeader, proof: GrandpaJustification, ) -> Bytes { - // let call = westend_runtime::BridgeGrandpaRococoCall::< - // westend_runtime::Runtime, - // westend_runtime::RococoGrandpaInstance, - // >::submit_finality_proof(header.into_inner(), proof) - // .into(); - - let call = bp_westend::Call::submit_finality_proof(header.into_inner(), proof); + let call = bp_westend::Call::BridgeGrandpaRococo(bp_westend::BridgeGrandpaRococoCall::submit_finality_proof( + header.into_inner(), + proof, + )); let genesis_hash = *self.target_client.genesis_hash(); let transaction = Westend::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); diff --git a/relays/bin-substrate/src/chains/westend.rs b/relays/bin-substrate/src/chains/westend.rs new file mode 100644 index 000000000000..27621472d6d9 --- /dev/null +++ b/relays/bin-substrate/src/chains/westend.rs @@ -0,0 +1,41 @@ +// 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 chain specification for CLI. + +use crate::cli::{encode_message, CliChain}; +use frame_support::weights::Weight; +use relay_westend_client::Westend; +use sp_version::RuntimeVersion; + +impl CliChain for Westend { + const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = (); + + fn ss58_format() -> u16 { + 42 + } + + fn max_extrinsic_weight() -> Weight { + 0 + } + + fn encode_message(_message: encode_message::MessagePayload) -> Result { + Err("Sending messages from Westend is not yet supported.".into()) + } +} diff --git a/relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs b/relays/bin-substrate/src/chains/westend_headers_to_millau.rs similarity index 70% rename from relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs rename to relays/bin-substrate/src/chains/westend_headers_to_millau.rs index ac69a7437ed3..1523dc1be584 100644 --- a/relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs +++ b/relays/bin-substrate/src/chains/westend_headers_to_millau.rs @@ -22,7 +22,7 @@ use bp_header_chain::justification::GrandpaJustification; use codec::Encode; use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; use relay_substrate_client::{Chain, TransactionSignScheme}; -use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams}; +use relay_utils::metrics::MetricsParams; use relay_westend_client::{SyncHeader as WestendSyncHeader, Westend}; use sp_core::{Bytes, Pair}; @@ -35,30 +35,11 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { type TargetChain = Millau; fn customize_metrics(params: MetricsParams) -> anyhow::Result { - Ok( - relay_utils::relay_metrics(finality_relay::metrics_prefix::(), params.address) - // Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama - // relays, but we want to test metrics/dashboards in advance - .standalone_metric(FloatJsonValueMetric::new( - "https://api.coingecko.com/api/v3/simple/price?ids=Polkadot&vs_currencies=usd".into(), - "$.polkadot.usd".into(), - "polkadot_price".into(), - "Polkadot price in USD".into(), - )) - .map_err(|e| anyhow::format_err!("{}", e))? - .standalone_metric(FloatJsonValueMetric::new( - "https://api.coingecko.com/api/v3/simple/price?ids=Kusama&vs_currencies=usd".into(), - "$.kusama.usd".into(), - "kusama_price".into(), - "Kusama price in USD".into(), - )) - .map_err(|e| anyhow::format_err!("{}", e))? - .into_params(), - ) + crate::chains::add_polkadot_kusama_price_metrics::(params) } fn transactions_author(&self) -> bp_millau::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_submit_finality_proof_transaction( diff --git a/relays/bin-substrate/src/rialto_millau/westend_headers_to_rococo.rs b/relays/bin-substrate/src/chains/westend_headers_to_rococo.rs similarity index 62% rename from relays/bin-substrate/src/rialto_millau/westend_headers_to_rococo.rs rename to relays/bin-substrate/src/chains/westend_headers_to_rococo.rs index a1ff0d059532..577a858d9229 100644 --- a/relays/bin-substrate/src/rialto_millau/westend_headers_to_rococo.rs +++ b/relays/bin-substrate/src/chains/westend_headers_to_rococo.rs @@ -22,7 +22,7 @@ use bp_header_chain::justification::GrandpaJustification; use codec::Encode; use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams}; use relay_substrate_client::{Chain, TransactionSignScheme}; -use relay_utils::metrics::{FloatJsonValueMetric, MetricsParams}; +use relay_utils::metrics::MetricsParams; use relay_westend_client::{SyncHeader as WestendSyncHeader, Westend}; use sp_core::{Bytes, Pair}; @@ -35,30 +35,11 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToRococo { type TargetChain = Rococo; fn customize_metrics(params: MetricsParams) -> anyhow::Result { - Ok( - relay_utils::relay_metrics(finality_relay::metrics_prefix::(), params.address) - // Polkadot/Kusama prices are added as metrics here, because atm we don't have Polkadot <-> Kusama - // relays, but we want to test metrics/dashboards in advance - .standalone_metric(FloatJsonValueMetric::new( - "https://api.coingecko.com/api/v3/simple/price?ids=Polkadot&vs_currencies=usd".into(), - "$.polkadot.usd".into(), - "polkadot_price".into(), - "Polkadot price in USD".into(), - )) - .map_err(|e| anyhow::format_err!("{}", e))? - .standalone_metric(FloatJsonValueMetric::new( - "https://api.coingecko.com/api/v3/simple/price?ids=Kusama&vs_currencies=usd".into(), - "$.kusama.usd".into(), - "kusama_price".into(), - "Kusama price in USD".into(), - )) - .map_err(|e| anyhow::format_err!("{}", e))? - .into_params(), - ) + crate::chains::add_polkadot_kusama_price_metrics::(params) } fn transactions_author(&self) -> bp_rococo::AccountId { - self.target_sign.public().as_array_ref().clone().into() + (*self.target_sign.public().as_array_ref()).into() } fn make_submit_finality_proof_transaction( @@ -67,14 +48,10 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToRococo { header: WestendSyncHeader, proof: GrandpaJustification, ) -> Bytes { - // let call = - // rococo_runtime::BridgeGrandpaWestendCall::< - // rococo_runtime::Runtime, - // rococo_runtime::WestendGrandpaInstance, - // >::submit_finality_proof(header.into_inner(), proof) - // .into(); - - let call = bp_rococo::Call::submit_finality_proof(header.into_inner(), proof); + let call = bp_rococo::Call::BridgeGrandpaWestend(bp_rococo::BridgeGrandpaWestendCall::submit_finality_proof( + header.into_inner(), + proof, + )); let genesis_hash = *self.target_client.genesis_hash(); let transaction = Rococo::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); diff --git a/relays/bin-substrate/src/cli/bridge.rs b/relays/bin-substrate/src/cli/bridge.rs index 83a19f88c278..faf4417d1e99 100644 --- a/relays/bin-substrate/src/cli/bridge.rs +++ b/relays/bin-substrate/src/cli/bridge.rs @@ -17,7 +17,7 @@ use structopt::clap::arg_enum; arg_enum! { - #[derive(Debug)] + #[derive(Debug, PartialEq, Eq)] /// Supported full bridges (headers + messages). pub enum FullBridge { MillauToRialto, @@ -48,25 +48,46 @@ macro_rules! select_full_bridge { 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_millau::derive_account_from_rialto_id as derive_account; + // Relay-messages #[allow(unused_imports)] - use crate::rialto_millau::millau_messages_to_rialto::run as relay_messages; + use crate::chains::millau_messages_to_rialto::run as relay_messages; + + // 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::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_rialto::derive_account_from_millau_id as derive_account; + // Relay-messages + #[allow(unused_imports)] + use crate::chains::rialto_messages_to_millau::run as relay_messages; + + // 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 crate::rialto_millau::rialto_messages_to_millau::run as relay_messages; + use rialto_runtime::millau_account_ownership_digest as account_ownership_digest; $generic } diff --git a/relays/bin-substrate/src/cli/encode_call.rs b/relays/bin-substrate/src/cli/encode_call.rs index b5cdaaa1d390..6e1130cffc1a 100644 --- a/relays/bin-substrate/src/cli/encode_call.rs +++ b/relays/bin-substrate/src/cli/encode_call.rs @@ -35,7 +35,7 @@ pub struct EncodeCall { /// /// 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)] +#[derive(StructOpt, Debug, PartialEq, Eq)] pub enum Call { /// Raw bytes for the message Raw { diff --git a/relays/bin-substrate/src/cli/encode_message.rs b/relays/bin-substrate/src/cli/encode_message.rs new file mode 100644 index 000000000000..a29aa8597d63 --- /dev/null +++ b/relays/bin-substrate/src/cli/encode_message.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 . + +use crate::cli::{bridge::FullBridge, AccountId, CliChain, HexBytes}; +use crate::select_full_bridge; +use structopt::StructOpt; + +/// Generic message payload. +#[derive(StructOpt, Debug, PartialEq, Eq)] +pub enum MessagePayload { + /// Raw, SCALE-encoded `MessagePayload`. + Raw { + /// Hex-encoded SCALE data. + 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, + }, +} + +/// A `MessagePayload` to encode. +#[derive(StructOpt)] +pub struct EncodeMessage { + /// A bridge instance to initalize. + #[structopt(possible_values = &FullBridge::variants(), case_insensitive = true)] + bridge: FullBridge, + #[structopt(flatten)] + payload: MessagePayload, +} + +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)) + }) + } + + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + let payload = self.encode()?; + println!("{:?}", payload); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::crypto::Ss58Codec; + + #[test] + fn should_encode_raw_message() { + // given + let msg = "01000000e88514000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d3c040130000000000000000000000000"; + let encode_message = EncodeMessage::from_iter(vec!["encode-message", "MillauToRialto", "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", + "RialtoToMillau", + "call", + "--sender", + &sender, + "remark", + "--remark-size", + "12", + ]); + + // when + let hex = encode_message.encode().unwrap(); + + // then + assert_eq!(format!("{:?}", hex), "0x01000000e88514000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d3c040130000000000000000000000000"); + } +} diff --git a/relays/bin-substrate/src/cli/estimate_fee.rs b/relays/bin-substrate/src/cli/estimate_fee.rs new file mode 100644 index 000000000000..4e39ad351ede --- /dev/null +++ b/relays/bin-substrate/src/cli/estimate_fee.rs @@ -0,0 +1,128 @@ +// 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; +use crate::cli::{Balance, CliChain, HexBytes, HexLaneId, SourceConnectionParams}; +use crate::select_full_bridge; +use codec::{Decode, Encode}; +use relay_substrate_client::{Chain, ChainWithBalances}; +use structopt::StructOpt; + +/// Estimate Delivery & Dispatch Fee command. +#[derive(StructOpt, Debug, PartialEq, Eq)] +pub struct EstimateFee { + /// A bridge instance to encode call for. + #[structopt(possible_values = &FullBridge::variants(), case_insensitive = true)] + bridge: FullBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + /// Hex-encoded id of lane that will be delivering the message. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + /// Payload to send over the bridge. + #[structopt(flatten)] + payload: crate::cli::encode_message::MessagePayload, +} + +impl EstimateFee { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + let Self { + source, + bridge, + lane, + payload, + } = self; + + 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))?; + + let fee: ::NativeBalance = + estimate_message_delivery_and_dispatch_fee(&source_client, ESTIMATE_MESSAGE_FEE_METHOD, lane, payload) + .await?; + + log::info!(target: "bridge", "Fee: {:?}", Balance(fee as _)); + println!("{}", fee); + Ok(()) + }) + } +} + +pub(crate) async fn estimate_message_delivery_and_dispatch_fee( + client: &relay_substrate_client::Client, + estimate_fee_method: &str, + lane: bp_messages::LaneId, + payload: P, +) -> anyhow::Result { + let encoded_response = client + .state_call(estimate_fee_method.into(), (lane, payload).encode().into(), None) + .await?; + let decoded_response: Option = + Decode::decode(&mut &encoded_response.0[..]).map_err(relay_substrate_client::Error::ResponseParseFailed)?; + let fee = decoded_response + .ok_or_else(|| anyhow::format_err!("Unable to decode fee from: {:?}", HexBytes(encoded_response.to_vec())))?; + Ok(fee) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cli::encode_call; + 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", + "RialtoToMillau", + "--source-port", + "1234", + "call", + "--sender", + &alice, + "remark", + "--remark-payload", + "1234", + ]); + + // then + assert_eq!( + res, + EstimateFee { + bridge: FullBridge::RialtoToMillau, + lane: HexLaneId([0, 0, 0, 0]), + source: SourceConnectionParams { + source_host: "127.0.0.1".into(), + source_port: 1234, + source_secure: false, + }, + 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, + } + } + } + ); + } +} diff --git a/relays/bin-substrate/src/cli/init_bridge.rs b/relays/bin-substrate/src/cli/init_bridge.rs index e7956f2ef279..cdd8ec369161 100644 --- a/relays/bin-substrate/src/cli/init_bridge.rs +++ b/relays/bin-substrate/src/cli/init_bridge.rs @@ -15,9 +15,9 @@ // along with Parity Bridges Common. If not, see . use crate::cli::{SourceConnectionParams, TargetConnectionParams, TargetSigningParams}; +use bp_header_chain::InitializationData; use bp_runtime::Chain as ChainBase; use codec::Encode; -use pallet_bridge_grandpa::InitializationData; use relay_substrate_client::{Chain, TransactionSignScheme}; use sp_core::{Bytes, Pair}; use structopt::{clap::arg_enum, StructOpt}; @@ -107,10 +107,9 @@ macro_rules! select_bridge { type Target = relay_rococo_client::Rococo; fn encode_init_bridge( - _init_data: InitializationData<::Header>, + init_data: InitializationData<::Header>, ) -> ::Call { - // TODO: Maybe more closely match "real" Call - bp_rococo::Call::initialize + bp_rococo::Call::BridgeGrandpaWestend(bp_rococo::BridgeGrandpaWestendCall::initialize(init_data)) } $generic @@ -120,10 +119,9 @@ macro_rules! select_bridge { type Target = relay_westend_client::Westend; fn encode_init_bridge( - _init_data: InitializationData<::Header>, + init_data: InitializationData<::Header>, ) -> ::Call { - // TODO: Maybe more closely match "real" Call - bp_westend::Call::initialize + bp_westend::Call::BridgeGrandpaRococo(bp_westend::BridgeGrandpaRococoCall::initialize(init_data)) } $generic @@ -136,9 +134,9 @@ impl InitBridge { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.into_client::().await?; - let target_client = self.target.into_client::().await?; - let target_sign = self.target_sign.into_keypair::()?; + let source_client = self.source.to_client::().await?; + let target_client = self.target.to_client::().await?; + let target_sign = self.target_sign.to_keypair::()?; crate::headers_initialize::initialize( source_client, diff --git a/relays/bin-substrate/src/cli/mod.rs b/relays/bin-substrate/src/cli/mod.rs index 5f6f4160c9ff..505ef11ee2a5 100644 --- a/relays/bin-substrate/src/cli/mod.rs +++ b/relays/bin-substrate/src/cli/mod.rs @@ -18,7 +18,6 @@ use std::convert::TryInto; -use crate::rialto_millau::cli as rialto_millau; use bp_messages::LaneId; use codec::{Decode, Encode}; use frame_support::weights::Weight; @@ -27,10 +26,14 @@ use structopt::{clap::arg_enum, StructOpt}; 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 init_bridge; mod relay_headers; +mod relay_headers_and_messages; mod relay_messages; /// Parse relay CLI args. @@ -52,6 +55,13 @@ pub enum Command { /// Ties up to `Messages` pallets on both chains and starts relaying messages. /// Requires the header relay to be already running. RelayMessages(relay_messages::RelayMessages), + /// Start headers and messages relay between two Substrate chains. + /// + /// This high-level relay internally starts four low-level relays: two `RelayHeaders` + /// 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), /// Initialize on-chain bridge pallet with current header data. /// /// Sends initialization transaction to bootstrap the bridge with current finalized block data. @@ -61,7 +71,7 @@ pub enum Command { /// 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(SendMessage), + 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 @@ -71,9 +81,9 @@ pub enum Command { /// /// The `MessagePayload` can be then fed to `Messages::send_message` function and sent over /// the bridge. - EncodeMessagePayload(EncodeMessagePayload), + EncodeMessage(encode_message::EncodeMessage), /// Estimate Delivery and Dispatch Fee required for message submission to messages pallet. - EstimateFee(EstimateFee), + EstimateFee(estimate_fee::EstimateFee), /// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain. DeriveAccount(derive_account::DeriveAccount), } @@ -84,10 +94,11 @@ impl Command { match self { Self::RelayHeaders(arg) => arg.run().await?, Self::RelayMessages(arg) => arg.run().await?, + Self::RelayHeadersAndMessages(arg) => arg.run().await?, Self::InitBridge(arg) => arg.run().await?, Self::SendMessage(arg) => arg.run().await?, Self::EncodeCall(arg) => arg.run().await?, - Self::EncodeMessagePayload(arg) => arg.run().await?, + Self::EncodeMessage(arg) => arg.run().await?, Self::EstimateFee(arg) => arg.run().await?, Self::DeriveAccount(arg) => arg.run().await?, } @@ -95,57 +106,6 @@ impl Command { } } -/// Send bridge message. -#[derive(StructOpt)] -pub enum SendMessage { - #[structopt(flatten)] - RialtoMillau(rialto_millau::SendMessage), -} - -impl SendMessage { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - match self { - Self::RialtoMillau(arg) => arg.run().await?, - } - Ok(()) - } -} - -/// A `MessagePayload` to encode. -#[derive(StructOpt)] -pub enum EncodeMessagePayload { - #[structopt(flatten)] - RialtoMillau(rialto_millau::EncodeMessagePayload), -} - -impl EncodeMessagePayload { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - match self { - Self::RialtoMillau(arg) => arg.run().await?, - } - Ok(()) - } -} - -/// Estimate Delivery & Dispatch Fee command. -#[derive(StructOpt)] -pub enum EstimateFee { - #[structopt(flatten)] - RialtoMillau(rialto_millau::EstimateFee), -} - -impl EstimateFee { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - match self { - Self::RialtoMillau(arg) => arg.run().await?, - } - Ok(()) - } -} - arg_enum! { #[derive(Debug)] /// The origin to use when dispatching the message on the target chain. @@ -159,9 +119,16 @@ arg_enum! { } /// Generic balance type. -#[derive(Debug)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Balance(pub u128); +impl std::fmt::Display for Balance { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + use num_format::{Locale, ToFormattedString}; + write!(fmt, "{}", self.0.to_formatted_string(&Locale::en)) + } +} + impl std::str::FromStr for Balance { type Err = ::Err; @@ -260,14 +227,14 @@ pub trait CliChain: relay_substrate_client::Chain { fn ss58_format() -> u16; /// Construct message payload to be sent over the bridge. - fn encode_message(message: crate::rialto_millau::cli::MessagePayload) -> Result; + fn encode_message(message: crate::cli::encode_message::MessagePayload) -> Result; /// Maximal extrinsic weight (from the runtime). fn max_extrinsic_weight() -> Weight; } /// Lane id. -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct HexLaneId(pub LaneId); impl From for LaneId { @@ -287,7 +254,7 @@ impl std::str::FromStr for HexLaneId { } /// Nicer formatting for raw bytes vectors. -#[derive(Default, Encode, Decode)] +#[derive(Default, Encode, Decode, PartialEq, Eq)] pub struct HexBytes(pub Vec); impl std::str::FromStr for HexBytes { @@ -346,7 +313,7 @@ impl From for relay_utils::metrics::MetricsParams { } /// Either explicit or maximal allowed value. -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum ExplicitOrMaximal { /// User has explicitly specified argument value. Explicit(V), @@ -378,7 +345,7 @@ macro_rules! declare_chain_options { ($chain:ident, $chain_prefix:ident) => { paste::item! { #[doc = $chain " connection params."] - #[derive(StructOpt)] + #[derive(StructOpt, Debug, PartialEq, Eq)] pub struct [<$chain ConnectionParams>] { #[doc = "Connect to " $chain " node at given host."] #[structopt(long, default_value = "127.0.0.1")] @@ -392,7 +359,7 @@ macro_rules! declare_chain_options { } #[doc = $chain " signing params."] - #[derive(StructOpt)] + #[derive(StructOpt, Debug, PartialEq, Eq)] pub struct [<$chain SigningParams>] { #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."] #[structopt(long)] @@ -404,7 +371,7 @@ macro_rules! declare_chain_options { impl [<$chain SigningParams>] { /// Parse signing params into chain-specific KeyPair. - pub fn into_keypair(self) -> anyhow::Result { + pub fn to_keypair(&self) -> anyhow::Result { use sp_core::crypto::Pair; Chain::KeyPair::from_string( @@ -416,11 +383,11 @@ macro_rules! declare_chain_options { impl [<$chain ConnectionParams>] { /// Convert connection params into Substrate client. - pub async fn into_client( - self, + pub async fn to_client( + &self, ) -> anyhow::Result> { Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { - host: self.[<$chain_prefix _host>], + host: self.[<$chain_prefix _host>].clone(), port: self.[<$chain_prefix _port>], secure: self.[<$chain_prefix _secure>], }) diff --git a/relays/bin-substrate/src/cli/relay_headers.rs b/relays/bin-substrate/src/cli/relay_headers.rs index cf936a34a4ed..346790f2ae74 100644 --- a/relays/bin-substrate/src/cli/relay_headers.rs +++ b/relays/bin-substrate/src/cli/relay_headers.rs @@ -53,35 +53,35 @@ macro_rules! select_bridge { RelayHeadersBridge::MillauToRialto => { type Source = relay_millau_client::Millau; type Target = relay_rialto_client::Rialto; - type Finality = crate::rialto_millau::millau_headers_to_rialto::MillauFinalityToRialto; + 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::rialto_millau::rialto_headers_to_millau::RialtoFinalityToMillau; + 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::rialto_millau::westend_headers_to_millau::WestendFinalityToMillau; + type Finality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau; $generic } RelayHeadersBridge::WestendToRococo => { type Source = relay_westend_client::Westend; type Target = relay_rococo_client::Rococo; - type Finality = crate::rialto_millau::westend_headers_to_rococo::WestendFinalityToRococo; + type Finality = crate::chains::westend_headers_to_rococo::WestendFinalityToRococo; $generic } RelayHeadersBridge::RococoToWestend => { type Source = relay_rococo_client::Rococo; type Target = relay_westend_client::Westend; - type Finality = crate::rialto_millau::rococo_headers_to_westend::RococoFinalityToWestend; + type Finality = crate::chains::rococo_headers_to_westend::RococoFinalityToWestend; $generic } @@ -93,9 +93,9 @@ impl RelayHeaders { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.into_client::().await?; - let target_client = self.target.into_client::().await?; - let target_sign = self.target_sign.into_keypair::()?; + 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 metrics_params = Finality::customize_metrics(self.prometheus_params.into())?; crate::finality_pipeline::run( diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages.rs new file mode 100644 index 000000000000..98ff1268fae9 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages.rs @@ -0,0 +1,183 @@ +// 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 crate::cli::{CliChain, HexLaneId, PrometheusParams}; +use crate::declare_chain_options; +use crate::messages_lane::MessagesRelayParams; +use crate::on_demand_headers::OnDemandHeadersRelay; + +use futures::{FutureExt, TryFutureExt}; +use relay_utils::metrics::MetricsParams; +use structopt::StructOpt; + +/// Start headers+messages relayer process. +#[derive(StructOpt)] +pub enum RelayHeadersAndMessages { + MillauRialto(MillauRialtoHeadersAndMessages), +} + +/// Parameters that have the same names across all bridges. +#[derive(StructOpt)] +pub struct HeadersAndMessagesSharedParams { + /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + #[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)] + right: [<$chain2 ConnectionParams>], + #[structopt(flatten)] + right_sign: [<$chain2 SigningParams>], + } + + #[allow(unreachable_patterns)] + 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 LeftToRightMessages = crate::chains::millau_messages_to_rialto::MillauMessagesToRialto; + type RightToLeftMessages = crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau; + + use crate::chains::millau_messages_to_rialto::run as left_to_right_messages; + use crate::chains::rialto_messages_to_millau::run as right_to_left_messages; + + $generic + } + } + }; +} + +// All supported chains. +declare_chain_options!(Millau, millau); +declare_chain_options!(Rialto, rialto); +// All supported bridges. +declare_bridge_options!(Millau, Rialto); + +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_sign = params.left_sign.to_keypair::()?; + let right_client = params.right.to_client::().await?; + let right_sign = params.right_sign.to_keypair::()?; + + let lane = params.shared.lane.into(); + + let metrics_params: MetricsParams = params.shared.prometheus_params.into(); + let metrics_params = relay_utils::relay_metrics(None, metrics_params).into_params(); + + let left_to_right_on_demand_headers = OnDemandHeadersRelay::new( + left_client.clone(), + right_client.clone(), + LeftToRightFinality::new(right_client.clone(), right_sign.clone()), + ); + let right_to_left_on_demand_headers = OnDemandHeadersRelay::new( + right_client.clone(), + left_client.clone(), + RightToLeftFinality::new(left_client.clone(), left_sign.clone()), + ); + + let left_to_right_messages = left_to_right_messages(MessagesRelayParams { + source_client: left_client.clone(), + source_sign: left_sign.clone(), + target_client: right_client.clone(), + target_sign: right_sign.clone(), + 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() + .metrics_prefix(messages_relay::message_lane_loop::metrics_prefix::(&lane)), + }) + .map_err(|e| anyhow::format_err!("{}", e)) + .boxed(); + let right_to_left_messages = right_to_left_messages(MessagesRelayParams { + source_client: right_client, + source_sign: right_sign, + target_client: left_client.clone(), + target_sign: left_sign.clone(), + source_to_target_headers_relay: Some(right_to_left_on_demand_headers), + target_to_source_headers_relay: Some(left_to_right_on_demand_headers), + lane_id: lane, + metrics_params: metrics_params + .clone() + .disable() + .metrics_prefix(messages_relay::message_lane_loop::metrics_prefix::(&lane)), + }) + .map_err(|e| anyhow::format_err!("{}", e)) + .boxed(); + + relay_utils::relay_metrics(None, metrics_params) + .expose() + .await + .map_err(|e| anyhow::format_err!("{}", e))?; + + futures::future::select(left_to_right_messages, right_to_left_messages) + .await + .factor_first() + .0 + }) + } +} diff --git a/relays/bin-substrate/src/cli/relay_messages.rs b/relays/bin-substrate/src/cli/relay_messages.rs index feedea66ef6a..94630886ca38 100644 --- a/relays/bin-substrate/src/cli/relay_messages.rs +++ b/relays/bin-substrate/src/cli/relay_messages.rs @@ -19,7 +19,9 @@ use crate::cli::{ HexLaneId, PrometheusParams, SourceConnectionParams, SourceSigningParams, TargetConnectionParams, TargetSigningParams, }; +use crate::messages_lane::MessagesRelayParams; use crate::select_full_bridge; + use structopt::StructOpt; /// Start messages relayer process. @@ -47,19 +49,21 @@ impl RelayMessages { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_full_bridge!(self.bridge, { - let source_client = self.source.into_client::().await?; - let source_sign = self.source_sign.into_keypair::()?; - let target_client = self.target.into_client::().await?; - let target_sign = self.target_sign.into_keypair::()?; + 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::()?; - relay_messages( + relay_messages(MessagesRelayParams { source_client, source_sign, target_client, target_sign, - self.lane.into(), - self.prometheus_params.into(), - ) + source_to_target_headers_relay: None, + target_to_source_headers_relay: None, + lane_id: self.lane.into(), + metrics_params: self.prometheus_params.into(), + }) .await .map_err(|e| anyhow::format_err!("{}", e)) }) diff --git a/relays/bin-substrate/src/cli/send_message.rs b/relays/bin-substrate/src/cli/send_message.rs new file mode 100644 index 000000000000..64448f0f1db3 --- /dev/null +++ b/relays/bin-substrate/src/cli/send_message.rs @@ -0,0 +1,317 @@ +// 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; +use crate::cli::encode_call::{self, CliEncodeCall}; +use crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee; +use crate::cli::{ + Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams, + TargetSigningParams, +}; +use codec::Encode; +use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; +use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; +use relay_substrate_client::{Chain, TransactionSignScheme}; +use sp_core::{Bytes, Pair}; +use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner}; +use std::fmt::Debug; +use structopt::StructOpt; + +/// Send bridge message. +#[derive(StructOpt)] +pub struct SendMessage { + /// A bridge instance to encode call for. + #[structopt(possible_values = &FullBridge::variants(), case_insensitive = true)] + bridge: FullBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + source_sign: SourceSigningParams, + // TODO [#885] Move TargetSign to origins + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// Hex-encoded lane id. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + /// 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, +} + +impl SendMessage { + pub fn encode_payload( + &mut self, + ) -> anyhow::Result>> { + crate::select_full_bridge!(self.bridge, { + let SendMessage { + source_sign, + target_sign, + ref mut message, + dispatch_weight, + origin, + bridge, + .. + } = self; + + let source_sign = source_sign.to_keypair::()?; + let target_sign = target_sign.to_keypair::()?; + + encode_call::preprocess_call::(message, bridge.bridge_instance_index()); + let target_call = Target::encode_call(&message)?; + + let payload = { + let target_call_weight = prepare_call_dispatch_weight( + dispatch_weight, + ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().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::RUNTIME_VERSION.spec_version, + target_call_weight, + match origin { + Origins::Source => CallOrigin::SourceAccount(source_account_id), + Origins::Target => { + let digest = account_ownership_digest( + &target_call, + source_account_id.clone(), + Target::RUNTIME_VERSION.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, + ) + }; + Ok(payload) + }) + } + + /// Run the command. + pub async fn run(mut self) -> anyhow::Result<()> { + crate::select_full_bridge!(self.bridge, { + let payload = self.encode_payload()?; + + let source_client = self.source.to_client::().await?; + let source_sign = self.source_sign.to_keypair::()?; + + let lane = self.lane.clone().into(); + let fee = match self.fee { + Some(fee) => fee, + None => Balance( + estimate_message_delivery_and_dispatch_fee::< + ::NativeBalance, + _, + _, + >(&source_client, ESTIMATE_MESSAGE_FEE_METHOD, lane, payload.clone()) + .await? as _, + ), + }; + let dispatch_weight = payload.weight; + 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, + })?; + + source_client + .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { + let signed_source_call = Source::sign_transaction( + *source_client.genesis_hash(), + &source_sign, + transaction_nonce, + send_message_call, + ) + .encode(); + + log::info!( + target: "bridge", + "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", + Target::NAME, + signed_source_call.len(), + dispatch_weight, + fee, + ); + log::info!( + target: "bridge", + "Signed {} Call: {:?}", + Source::NAME, + HexBytes::encode(&signed_source_call) + ); + + Bytes(signed_source_call) + }) + .await?; + }); + + Ok(()) + } +} + +fn prepare_call_dispatch_weight( + user_specified_dispatch_weight: &Option>, + weight_from_pre_dispatch_call: ExplicitOrMaximal, + maximal_allowed_weight: Weight, +) -> Weight { + match user_specified_dispatch_weight + .clone() + .unwrap_or(weight_from_pre_dispatch_call) + { + ExplicitOrMaximal::Explicit(weight) => weight, + ExplicitOrMaximal::Maximal => maximal_allowed_weight, + } +} + +pub(crate) fn message_payload( + spec_version: u32, + weight: Weight, + origin: CallOrigin, + call: &impl Encode, +) -> MessagePayload> +where + SAccountId: Encode + Debug, + TPublic: Encode + Debug, + TSignature: Encode + Debug, +{ + // Display nicely formatted call. + let payload = MessagePayload { + spec_version, + weight, + origin, + call: HexBytes::encode(call), + }; + + log::info!(target: "bridge", "Created Message Payload: {:#?}", payload); + log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload)); + + // re-pack to return `Vec` + let MessagePayload { + spec_version, + weight, + origin, + call, + } = payload; + MessagePayload { + spec_version, + weight, + origin, + call: call.0, + } +} + +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) +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn send_remark_rialto_to_millau() { + // given + let mut send_message = SendMessage::from_iter(vec![ + "send-message", + "RialtoToMillau", + "--source-port", + "1234", + "--source-signer", + "//Alice", + "--target-signer", + "//Bob", + "remark", + "--remark-payload", + "1234", + ]); + + // when + let payload = send_message.encode_payload().unwrap(); + + // then + assert_eq!( + payload, + MessagePayload { + spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version, + weight: 1345000, + origin: CallOrigin::SourceAccount(sp_keyring::AccountKeyring::Alice.to_account_id()), + call: hex!("0401081234").to_vec(), + } + ); + } + + #[test] + fn send_remark_millau_to_rialto() { + // given + let mut send_message = SendMessage::from_iter(vec![ + "send-message", + "MillauToRialto", + "--source-port", + "1234", + "--source-signer", + "//Alice", + "--origin", + "Target", + "--target-signer", + "//Bob", + "remark", + "--remark-payload", + "1234", + ]); + + // when + let payload = send_message.encode_payload().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: 1345000, + origin: CallOrigin::TargetAccount( + sp_keyring::AccountKeyring::Alice.to_account_id(), + sp_keyring::AccountKeyring::Bob.into(), + signature, + ), + call: hex!("0701081234").to_vec(), + } + ); + } +} diff --git a/relays/bin-substrate/src/headers_initialize.rs b/relays/bin-substrate/src/headers_initialize.rs index 83db39bf7bb6..c2eab1bd3534 100644 --- a/relays/bin-substrate/src/headers_initialize.rs +++ b/relays/bin-substrate/src/headers_initialize.rs @@ -21,6 +21,7 @@ //! and authorities set from source to target chain. The headers sync starts //! with this header. +use bp_header_chain::InitializationData; use bp_header_chain::{ find_grandpa_authorities_scheduled_change, justification::{verify_justification, GrandpaJustification}, @@ -28,7 +29,6 @@ use bp_header_chain::{ use codec::Decode; use finality_grandpa::voter_set::VoterSet; use num_traits::{One, Zero}; -use pallet_bridge_grandpa::InitializationData; use relay_substrate_client::{Chain, Client}; use sp_core::Bytes; use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet; diff --git a/relays/bin-substrate/src/main.rs b/relays/bin-substrate/src/main.rs index 11ff67e83b40..6bf7561fcdb3 100644 --- a/relays/bin-substrate/src/main.rs +++ b/relays/bin-substrate/src/main.rs @@ -20,6 +20,7 @@ use relay_utils::initialize::initialize_logger; +mod chains; mod cli; mod finality_pipeline; mod finality_target; @@ -27,8 +28,7 @@ mod headers_initialize; mod messages_lane; mod messages_source; mod messages_target; - -mod rialto_millau; +mod on_demand_headers; fn main() { initialize_logger(false); diff --git a/relays/bin-substrate/src/messages_lane.rs b/relays/bin-substrate/src/messages_lane.rs index ada5ce12bfc3..753bf6320d51 100644 --- a/relays/bin-substrate/src/messages_lane.rs +++ b/relays/bin-substrate/src/messages_lane.rs @@ -16,15 +16,36 @@ use crate::messages_source::SubstrateMessagesProof; use crate::messages_target::SubstrateMessagesReceivingProof; +use crate::on_demand_headers::OnDemandHeadersRelay; -use bp_messages::MessageNonce; +use bp_messages::{LaneId, MessageNonce}; use frame_support::weights::Weight; use messages_relay::message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}; use relay_substrate_client::{BlockNumberOf, Chain, Client, HashOf}; -use relay_utils::BlockNumberBase; +use relay_utils::{metrics::MetricsParams, BlockNumberBase}; use sp_core::Bytes; use std::ops::RangeInclusive; +/// Substrate <-> Substrate messages relay parameters. +pub struct MessagesRelayParams { + /// Messages source client. + pub source_client: Client, + /// Sign parameters for messages source chain. + pub source_sign: SS, + /// Messages target client. + pub target_client: Client, + /// Sign parameters for messages target chain. + pub target_sign: TS, + /// Optional on-demand source to target headers relay. + pub source_to_target_headers_relay: Option>, + /// Optional on-demand target to source headers relay. + pub target_to_source_headers_relay: Option>, + /// Identifier of lane that needs to be served. + pub lane_id: LaneId, + /// Metrics parameters. + pub metrics_params: MetricsParams, +} + /// Message sync pipeline for Substrate <-> Substrate relays. pub trait SubstrateMessageLane: MessageLane { /// Name of the runtime method that returns dispatch weight of outbound messages at the source chain. diff --git a/relays/bin-substrate/src/messages_source.rs b/relays/bin-substrate/src/messages_source.rs index 99f88fbbbb30..cf98f3276be6 100644 --- a/relays/bin-substrate/src/messages_source.rs +++ b/relays/bin-substrate/src/messages_source.rs @@ -19,24 +19,26 @@ //! chain. use crate::messages_lane::SubstrateMessageLane; +use crate::on_demand_headers::OnDemandHeadersRelay; use async_trait::async_trait; use bp_messages::{LaneId, MessageNonce}; use bp_runtime::InstanceId; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; use codec::{Decode, Encode}; -use frame_support::weights::Weight; +use frame_support::{traits::Instance, weights::Weight}; use messages_relay::{ message_lane::{SourceHeaderIdOf, TargetHeaderIdOf}, message_lane_loop::{ ClientState, MessageProofParameters, MessageWeights, MessageWeightsMap, SourceClient, SourceClientState, }, }; +use pallet_bridge_messages::Config as MessagesConfig; use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf}; use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId}; use sp_core::Bytes; use sp_runtime::{traits::Header as HeaderT, DeserializeOwned}; -use std::ops::RangeInclusive; +use std::{marker::PhantomData, ops::RangeInclusive}; /// Intermediate message proof returned by the source Substrate node. Includes everything /// required to submit to the target node: cumulative dispatch weight of bundled messages and @@ -44,38 +46,56 @@ use std::ops::RangeInclusive; pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof>); /// Substrate client as Substrate messages source. -pub struct SubstrateMessagesSource { +pub struct SubstrateMessagesSource { client: Client, lane: P, lane_id: LaneId, instance: InstanceId, + target_to_source_headers_relay: Option>, + _phantom: PhantomData<(R, I)>, } -impl SubstrateMessagesSource { +impl SubstrateMessagesSource { /// Create new Substrate headers source. - pub fn new(client: Client, lane: P, lane_id: LaneId, instance: InstanceId) -> Self { + pub fn new( + client: Client, + lane: P, + lane_id: LaneId, + instance: InstanceId, + target_to_source_headers_relay: Option>, + ) -> Self { SubstrateMessagesSource { client, lane, lane_id, instance, + target_to_source_headers_relay, + _phantom: Default::default(), } } } -impl Clone for SubstrateMessagesSource { +impl Clone for SubstrateMessagesSource { fn clone(&self) -> Self { Self { client: self.client.clone(), lane: self.lane.clone(), lane_id: self.lane_id, instance: self.instance, + target_to_source_headers_relay: self.target_to_source_headers_relay.clone(), + _phantom: Default::default(), } } } #[async_trait] -impl RelayClient for SubstrateMessagesSource { +impl RelayClient for SubstrateMessagesSource +where + C: Chain, + P: SubstrateMessageLane, + R: Send + Sync, + I: Send + Sync + Instance, +{ type Error = SubstrateError; async fn reconnect(&mut self) -> Result<(), SubstrateError> { @@ -84,7 +104,7 @@ impl RelayClient for SubstrateMessagesSource< } #[async_trait] -impl SourceClient

for SubstrateMessagesSource +impl SourceClient

for SubstrateMessagesSource where C: Chain, C::Header: DeserializeOwned, @@ -96,8 +116,11 @@ where SourceHeaderHash = ::Hash, SourceChain = C, >, + P::TargetChain: Chain, P::TargetHeaderNumber: Decode, P::TargetHeaderHash: Decode, + R: Send + Sync + MessagesConfig, + I: Send + Sync + Instance, { async fn state(&self) -> Result, SubstrateError> { // we can't continue to deliver confirmations if source node is out of sync, because @@ -171,15 +194,22 @@ where nonces: RangeInclusive, proof_parameters: MessageProofParameters, ) -> Result<(SourceHeaderIdOf

, RangeInclusive, P::MessagesProof), SubstrateError> { + let mut storage_keys = Vec::with_capacity(nonces.end().saturating_sub(*nonces.start()) as usize + 1); + let mut message_nonce = *nonces.start(); + while message_nonce <= *nonces.end() { + let message_key = pallet_bridge_messages::storage_keys::message_key::(&self.lane_id, message_nonce); + storage_keys.push(message_key); + message_nonce += 1; + } + if proof_parameters.outbound_state_proof_required { + storage_keys.push(pallet_bridge_messages::storage_keys::outbound_lane_data_key::( + &self.lane_id, + )); + } + let proof = self .client - .prove_messages( - self.instance, - self.lane_id, - nonces.clone(), - proof_parameters.outbound_state_proof_required, - id.1, - ) + .prove_storage(storage_keys, id.1) .await? .iter_nodes() .collect(); @@ -207,7 +237,11 @@ where Ok(()) } - async fn activate_target_to_source_headers_relay(&self, _activate: bool) {} + 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); + } + } } pub async fn read_client_state( diff --git a/relays/bin-substrate/src/messages_target.rs b/relays/bin-substrate/src/messages_target.rs index 3d8ab4fd0045..176083273069 100644 --- a/relays/bin-substrate/src/messages_target.rs +++ b/relays/bin-substrate/src/messages_target.rs @@ -20,21 +20,24 @@ use crate::messages_lane::SubstrateMessageLane; use crate::messages_source::read_client_state; +use crate::on_demand_headers::OnDemandHeadersRelay; use async_trait::async_trait; use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState}; use bp_runtime::InstanceId; use bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof; use codec::{Decode, Encode}; +use frame_support::traits::Instance; use messages_relay::{ message_lane::{SourceHeaderIdOf, TargetHeaderIdOf}, message_lane_loop::{TargetClient, TargetClientState}, }; +use pallet_bridge_messages::Config as MessagesConfig; use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf}; use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase}; use sp_core::Bytes; use sp_runtime::{traits::Header as HeaderT, DeserializeOwned}; -use std::ops::RangeInclusive; +use std::{marker::PhantomData, ops::RangeInclusive}; /// Message receiving proof returned by the target Substrate node. pub type SubstrateMessagesReceivingProof = ( @@ -43,38 +46,56 @@ pub type SubstrateMessagesReceivingProof = ( ); /// Substrate client as Substrate messages target. -pub struct SubstrateMessagesTarget { +pub struct SubstrateMessagesTarget { client: Client, lane: P, lane_id: LaneId, instance: InstanceId, + source_to_target_headers_relay: Option>, + _phantom: PhantomData<(R, I)>, } -impl SubstrateMessagesTarget { +impl SubstrateMessagesTarget { /// Create new Substrate headers target. - pub fn new(client: Client, lane: P, lane_id: LaneId, instance: InstanceId) -> Self { + pub fn new( + client: Client, + lane: P, + lane_id: LaneId, + instance: InstanceId, + source_to_target_headers_relay: Option>, + ) -> Self { SubstrateMessagesTarget { client, lane, lane_id, instance, + source_to_target_headers_relay, + _phantom: Default::default(), } } } -impl Clone for SubstrateMessagesTarget { +impl Clone for SubstrateMessagesTarget { fn clone(&self) -> Self { Self { client: self.client.clone(), lane: self.lane.clone(), lane_id: self.lane_id, instance: self.instance, + source_to_target_headers_relay: self.source_to_target_headers_relay.clone(), + _phantom: Default::default(), } } } #[async_trait] -impl RelayClient for SubstrateMessagesTarget { +impl RelayClient for SubstrateMessagesTarget +where + C: Chain, + P: SubstrateMessageLane, + R: Send + Sync, + I: Send + Sync + Instance, +{ type Error = SubstrateError; async fn reconnect(&mut self) -> Result<(), SubstrateError> { @@ -83,7 +104,7 @@ impl RelayClient for SubstrateMessagesTarget< } #[async_trait] -impl TargetClient

for SubstrateMessagesTarget +impl TargetClient

for SubstrateMessagesTarget where C: Chain, C::Header: DeserializeOwned, @@ -95,8 +116,11 @@ where TargetHeaderNumber = ::Number, TargetHeaderHash = ::Hash, >, + P::SourceChain: Chain, P::SourceHeaderNumber: Decode, P::SourceHeaderHash: Decode, + R: Send + Sync + MessagesConfig, + I: Send + Sync + Instance, { async fn state(&self) -> Result, SubstrateError> { // we can't continue to deliver messages if target node is out of sync, because @@ -166,10 +190,13 @@ where id: TargetHeaderIdOf

, ) -> Result<(TargetHeaderIdOf

, P::MessagesReceivingProof), SubstrateError> { let (id, relayers_state) = self.unrewarded_relayers_state(id).await?; + let inbound_data_key = pallet_bridge_messages::storage_keys::inbound_lane_data_key::(&self.lane_id); let proof = self .client - .prove_messages_delivery(self.instance, self.lane_id, id.1) - .await?; + .prove_storage(vec![inbound_data_key], id.1) + .await? + .iter_nodes() + .collect(); let proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: id.1, storage_proof: proof, @@ -197,5 +224,9 @@ where Ok(nonces) } - async fn activate_source_to_target_headers_relay(&self, _activate: bool) {} + 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); + } + } } diff --git a/relays/bin-substrate/src/on_demand_headers.rs b/relays/bin-substrate/src/on_demand_headers.rs new file mode 100644 index 000000000000..4c86b6a17018 --- /dev/null +++ b/relays/bin-substrate/src/on_demand_headers.rs @@ -0,0 +1,255 @@ +// 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 headers relay. + +use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}; +use crate::finality_target::SubstrateFinalityTarget; + +use bp_header_chain::justification::GrandpaJustification; +use finality_relay::TargetClient as FinalityTargetClient; +use futures::{ + channel::{mpsc, oneshot}, + select, FutureExt, StreamExt, +}; +use num_traits::Zero; +use relay_substrate_client::{BlockNumberOf, Chain, Client, HashOf, HeaderIdOf, SyncHeader}; +use relay_utils::{metrics::MetricsParams, BlockNumberBase, HeaderId}; +use std::fmt::Debug; + +/// On-demand Substrate <-> Substrate headers relay. +/// +/// This relay may be started by messages whenever some other relay (e.g. messages relay) needs more +/// headers to be relayed to continue its regular work. When enough headers are relayed, on-demand +/// relay may be deactivated. +#[derive(Clone)] +pub struct OnDemandHeadersRelay { + /// Background task name. + background_task_name: String, + /// Required headers to background sender. + required_header_tx: mpsc::Sender>, +} + +impl OnDemandHeadersRelay { + /// Create new on-demand headers relay. + pub fn new( + source_client: Client, + target_client: Client, + pipeline: SubstrateFinalityToSubstrate, + ) -> Self + where + SourceChain: Chain + Debug, + SourceChain::BlockNumber: BlockNumberBase, + TargetChain: Chain + Debug, + TargetChain::BlockNumber: BlockNumberBase, + TargetSign: Clone + Send + Sync + 'static, + SubstrateFinalityToSubstrate: SubstrateFinalitySyncPipeline< + Hash = HashOf, + Number = BlockNumberOf, + Header = SyncHeader, + FinalityProof = GrandpaJustification, + TargetChain = TargetChain, + >, + SubstrateFinalityTarget>: + FinalityTargetClient>, + { + let (required_header_tx, required_header_rx) = mpsc::channel(1); + async_std::task::spawn(async move { + background_task(source_client, target_client, pipeline, required_header_rx).await; + }); + + let background_task_name = format!( + "{}-background", + on_demand_headers_relay_name::() + ); + OnDemandHeadersRelay { + background_task_name, + required_header_tx, + } + } + + /// Someone is asking us to relay given finalized header. + pub fn require_finalized_header(&self, header_id: HeaderIdOf) { + if let Err(error) = self.required_header_tx.clone().try_send(header_id) { + log::error!( + target: "bridge", + "Failed to send require header id {:?} to {:?}: {:?}", + header_id, + self.background_task_name, + error, + ); + } + } +} + +/// Background task that is responsible for starting and stopping headers relay when required. +async fn background_task( + source_client: Client, + target_client: Client, + pipeline: SubstrateFinalityToSubstrate, + mut required_header_rx: mpsc::Receiver>, +) where + SourceChain: Chain + Debug, + SourceChain::BlockNumber: BlockNumberBase, + TargetChain: Chain + Debug, + TargetChain::BlockNumber: BlockNumberBase, + TargetSign: Clone + Send + Sync + 'static, + SubstrateFinalityToSubstrate: SubstrateFinalitySyncPipeline< + Hash = HashOf, + Number = BlockNumberOf, + Header = SyncHeader, + FinalityProof = GrandpaJustification, + TargetChain = TargetChain, + >, + SubstrateFinalityTarget>: + FinalityTargetClient>, +{ + let relay_task_name = on_demand_headers_relay_name::(); + let finality_target = SubstrateFinalityTarget::new(target_client.clone(), pipeline.clone()); + + let mut active_headers_relay = None; + let mut required_header_number = Zero::zero(); + let mut relay_exited_rx = futures::future::pending().left_future(); + + loop { + // wait for next target block or for new required header + select! { + _ = async_std::task::sleep(TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, + required_header_id = required_header_rx.next() => { + match required_header_id { + Some(required_header_id) => { + if required_header_id.0 > required_header_number { + required_header_number = required_header_id.0; + } + }, + None => { + // that's the only way to exit background task - to drop `required_header_tx` + break + }, + } + }, + _ = relay_exited_rx => { + // there could be a situation when we're receiving exit signals after we + // have already stopped relay or when we have already started new relay. + // but it isn't critical, because even if we'll accidentally stop new relay + // we'll restart it almost immediately + stop_on_demand_headers_relay(active_headers_relay.take()).await; + }, + } + + // read best finalized source block from target + let available_header_number = match finality_target.best_finalized_source_block_number().await { + Ok(available_header_number) => available_header_number, + Err(error) => { + log::error!( + target: "bridge", + "Failed to read best finalized {} header from {} in {} relay: {:?}", + SourceChain::NAME, + TargetChain::NAME, + relay_task_name, + error, + ); + + // we don't know what's happening with target client, so better to stop on-demand relay than + // submit unneeded transactions + // => assume that required header is known to the target node + required_header_number + } + }; + + // start or stop headers relay if required + let activate = required_header_number > available_header_number; + match (activate, active_headers_relay.is_some()) { + (true, false) => { + let (relay_exited_tx, new_relay_exited_rx) = oneshot::channel(); + active_headers_relay = start_on_demand_headers_relay( + relay_task_name.clone(), + relay_exited_tx, + source_client.clone(), + target_client.clone(), + pipeline.clone(), + ); + if active_headers_relay.is_some() { + relay_exited_rx = new_relay_exited_rx.right_future(); + } + } + (false, true) => { + stop_on_demand_headers_relay(active_headers_relay.take()).await; + } + _ => (), + } + } +} + +/// On-demand headers relay task name. +fn on_demand_headers_relay_name() -> String { + format!("on-demand-{}-to-{}", SourceChain::NAME, TargetChain::NAME) +} + +/// Start on-demand headers relay task. +fn start_on_demand_headers_relay( + task_name: String, + relay_exited_tx: oneshot::Sender<()>, + source_client: Client, + target_client: Client, + pipeline: SubstrateFinalityToSubstrate, +) -> Option> +where + SourceChain::BlockNumber: BlockNumberBase, + SubstrateFinalityToSubstrate: SubstrateFinalitySyncPipeline< + Hash = HashOf, + Number = BlockNumberOf, + Header = SyncHeader, + FinalityProof = GrandpaJustification, + TargetChain = TargetChain, + >, + TargetSign: 'static, +{ + let headers_relay_future = + crate::finality_pipeline::run(pipeline, source_client, target_client, MetricsParams::disabled()); + let closure_task_name = task_name.clone(); + async_std::task::Builder::new() + .name(task_name.clone()) + .spawn(async move { + log::info!(target: "bridge", "Starting {} headers relay", closure_task_name); + let result = headers_relay_future.await; + log::trace!(target: "bridge", "{} headers relay has exited. Result: {:?}", closure_task_name, result); + let _ = relay_exited_tx.send(()); + }) + .map_err(|error| { + log::error!( + target: "bridge", + "Failed to start {} relay: {:?}", + task_name, + error, + ); + }) + .ok() +} + +/// Stop on-demand headers relay task. +async fn stop_on_demand_headers_relay(task: Option>) { + if let Some(task) = task { + let task_name = task + .task() + .name() + .expect("on-demand tasks are always started with name; qed") + .to_string(); + log::trace!(target: "bridge", "Cancelling {} headers relay", task_name); + task.cancel().await; + log::info!(target: "bridge", "Cancelled {} headers relay", task_name); + } +} diff --git a/relays/bin-substrate/src/rialto_millau/cli.rs b/relays/bin-substrate/src/rialto_millau/cli.rs deleted file mode 100644 index 9e5788b1cb69..000000000000 --- a/relays/bin-substrate/src/rialto_millau/cli.rs +++ /dev/null @@ -1,175 +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 . - -//! Deal with CLI args of Rialto <> Millau relay. - -use frame_support::weights::Weight; -use structopt::StructOpt; - -use crate::cli::{ - AccountId, Balance, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams, - TargetSigningParams, -}; - -/// Send bridge message. -/// -/// TODO [#855] Move to separate module. -#[derive(StructOpt)] -pub enum SendMessage { - /// Submit message to given Millau -> Rialto lane. - MillauToRialto { - #[structopt(flatten)] - source: SourceConnectionParams, - #[structopt(flatten)] - source_sign: SourceSigningParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, - /// Hex-encoded lane id. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// 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, - }, - /// Submit message to given Rialto -> Millau lane. - RialtoToMillau { - #[structopt(flatten)] - source: SourceConnectionParams, - #[structopt(flatten)] - source_sign: SourceSigningParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, - /// Hex-encoded lane id. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// 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, - }, -} - -impl SendMessage { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - super::run_send_message(self).await.map_err(format_err)?; - Ok(()) - } -} - -/// A `MessagePayload` to encode. -/// -/// TODO [#855] Move to separate module. -#[derive(StructOpt)] -pub enum EncodeMessagePayload { - /// Message Payload of Rialto to Millau call. - RialtoToMillau { - #[structopt(flatten)] - payload: MessagePayload, - }, - /// Message Payload of Millau to Rialto call. - MillauToRialto { - #[structopt(flatten)] - payload: MessagePayload, - }, -} - -impl EncodeMessagePayload { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - super::run_encode_message_payload(self).await.map_err(format_err)?; - Ok(()) - } -} - -/// Estimate Delivery & Dispatch Fee command. -/// -/// TODO [#855] Move to separate module. -#[derive(StructOpt)] -pub enum EstimateFee { - /// Estimate fee of Rialto to Millau message. - RialtoToMillau { - #[structopt(flatten)] - source: SourceConnectionParams, - /// Hex-encoded id of lane that will be delivering the message. - #[structopt(long)] - lane: HexLaneId, - /// Payload to send over the bridge. - #[structopt(flatten)] - payload: MessagePayload, - }, - /// Estimate fee of Rialto to Millau message. - MillauToRialto { - #[structopt(flatten)] - source: SourceConnectionParams, - /// Hex-encoded id of lane that will be delivering the message. - #[structopt(long)] - lane: HexLaneId, - /// Payload to send over the bridge. - #[structopt(flatten)] - payload: MessagePayload, - }, -} - -impl EstimateFee { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - super::run_estimate_fee(self).await.map_err(format_err)?; - Ok(()) - } -} - -fn format_err(err: String) -> anyhow::Error { - anyhow::anyhow!(err) -} - -/// Generic message payload. -#[derive(StructOpt, Debug)] -pub enum MessagePayload { - /// Raw, SCALE-encoded `MessagePayload`. - Raw { - /// Hex-encoded SCALE data. - data: HexBytes, - }, - /// Construct message to send over the bridge. - Call { - /// Message details. - #[structopt(flatten)] - call: crate::cli::encode_call::Call, - /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) - #[structopt(long)] - sender: AccountId, - }, -} diff --git a/relays/bin-substrate/src/rialto_millau/mod.rs b/relays/bin-substrate/src/rialto_millau/mod.rs deleted file mode 100644 index 285a13f0d0d1..000000000000 --- a/relays/bin-substrate/src/rialto_millau/mod.rs +++ /dev/null @@ -1,769 +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 . - -//! Rialto <> Millau Bridge commands. - -pub mod cli; -pub mod millau_headers_to_rialto; -pub mod millau_messages_to_rialto; -pub mod rialto_headers_to_millau; -pub mod rialto_messages_to_millau; -pub mod rococo_headers_to_westend; -pub mod westend_headers_to_millau; -pub mod westend_headers_to_rococo; - -/// Millau node client. -pub type MillauClient = relay_substrate_client::Client; -/// Rialto node client. -pub type RialtoClient = relay_substrate_client::Client; - -use crate::cli::{ - bridge::{MILLAU_TO_RIALTO_INDEX, RIALTO_TO_MILLAU_INDEX}, - encode_call::{self, Call, CliEncodeCall}, - CliChain, ExplicitOrMaximal, HexBytes, Origins, -}; -use codec::{Decode, Encode}; -use frame_support::weights::{GetDispatchInfo, Weight}; -use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; -use relay_millau_client::Millau; -use relay_rialto_client::Rialto; -use relay_rococo_client::Rococo; -use relay_substrate_client::{Chain, TransactionSignScheme}; -use relay_westend_client::Westend; -use sp_core::{Bytes, Pair}; -use sp_runtime::{traits::IdentifyAccount, MultiSigner}; -use sp_version::RuntimeVersion; -use std::fmt::Debug; - -async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { - match command { - cli::SendMessage::MillauToRialto { - source, - source_sign, - target_sign, - lane, - mut message, - dispatch_weight, - fee, - origin, - .. - } => { - type Source = Millau; - type Target = Rialto; - - let account_ownership_digest = |target_call, source_account_id| { - millau_runtime::rialto_account_ownership_digest( - &target_call, - source_account_id, - Target::RUNTIME_VERSION.spec_version, - ) - }; - let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; - let fee = fee.map(|x| x.cast()); - let send_message_call = |lane, payload, fee| { - millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( - lane, payload, fee, - )) - }; - - let source_client = source.into_client::().await.map_err(format_err)?; - let source_sign = source_sign.into_keypair::().map_err(format_err)?; - let target_sign = target_sign.into_keypair::().map_err(format_err)?; - - encode_call::preprocess_call::(&mut message, MILLAU_TO_RIALTO_INDEX); - let target_call = Target::encode_call(&message).map_err(|e| e.to_string())?; - - let payload = { - let target_call_weight = prepare_call_dispatch_weight( - dispatch_weight, - ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().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::RUNTIME_VERSION.spec_version, - target_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(source_account_id), - Origins::Target => { - let digest = account_ownership_digest(&target_call, source_account_id.clone()); - 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, - ) - }; - let dispatch_weight = payload.weight; - - let lane = lane.into(); - let fee = get_fee(fee, || { - estimate_message_delivery_and_dispatch_fee( - &source_client, - estimate_message_fee_method, - lane, - payload.clone(), - ) - }) - .await?; - - source_client - .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { - let send_message_call = send_message_call(lane, payload, fee); - - let signed_source_call = Source::sign_transaction( - *source_client.genesis_hash(), - &source_sign, - transaction_nonce, - send_message_call, - ) - .encode(); - - log::info!( - target: "bridge", - "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", - Target::NAME, - signed_source_call.len(), - dispatch_weight, - fee, - ); - log::info!( - target: "bridge", - "Signed {} Call: {:?}", - Source::NAME, - HexBytes::encode(&signed_source_call) - ); - - Bytes(signed_source_call) - }) - .await?; - } - cli::SendMessage::RialtoToMillau { - source, - source_sign, - target_sign, - lane, - mut message, - dispatch_weight, - fee, - origin, - .. - } => { - type Source = Rialto; - type Target = Millau; - - let account_ownership_digest = |target_call, source_account_id| { - rialto_runtime::millau_account_ownership_digest( - &target_call, - source_account_id, - Target::RUNTIME_VERSION.spec_version, - ) - }; - let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; - let fee = fee.map(|x| x.0); - let send_message_call = |lane, payload, fee| { - rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( - lane, payload, fee, - )) - }; - - let source_client = source.into_client::().await.map_err(format_err)?; - let source_sign = source_sign.into_keypair::().map_err(format_err)?; - let target_sign = target_sign.into_keypair::().map_err(format_err)?; - - encode_call::preprocess_call::(&mut message, RIALTO_TO_MILLAU_INDEX); - let target_call = Target::encode_call(&message).map_err(|e| e.to_string())?; - - let payload = { - let target_call_weight = prepare_call_dispatch_weight( - dispatch_weight, - ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().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::RUNTIME_VERSION.spec_version, - target_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(source_account_id), - Origins::Target => { - let digest = account_ownership_digest(&target_call, source_account_id.clone()); - 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, - ) - }; - let dispatch_weight = payload.weight; - - let lane = lane.into(); - let fee = get_fee(fee, || { - estimate_message_delivery_and_dispatch_fee( - &source_client, - estimate_message_fee_method, - lane, - payload.clone(), - ) - }) - .await?; - - source_client - .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { - let send_message_call = send_message_call(lane, payload, fee); - - let signed_source_call = Source::sign_transaction( - *source_client.genesis_hash(), - &source_sign, - transaction_nonce, - send_message_call, - ) - .encode(); - - log::info!( - target: "bridge", - "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", - Target::NAME, - signed_source_call.len(), - dispatch_weight, - fee, - ); - log::info!( - target: "bridge", - "Signed {} Call: {:?}", - Source::NAME, - HexBytes::encode(&signed_source_call) - ); - - Bytes(signed_source_call) - }) - .await?; - } - } - Ok(()) -} - -async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> { - match call { - cli::EncodeMessagePayload::RialtoToMillau { payload } => { - type Source = Rialto; - - let payload = Source::encode_message(payload)?; - println!("{:?}", HexBytes::encode(&payload)); - } - cli::EncodeMessagePayload::MillauToRialto { payload } => { - type Source = Millau; - - let payload = Source::encode_message(payload)?; - println!("{:?}", HexBytes::encode(&payload)); - } - } - Ok(()) -} - -async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { - match cmd { - cli::EstimateFee::RialtoToMillau { source, lane, payload } => { - type Source = Rialto; - type SourceBalance = bp_rialto::Balance; - - let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; - - let source_client = source.into_client::().await.map_err(format_err)?; - let lane = lane.into(); - let payload = Source::encode_message(payload)?; - - let fee: Option = - estimate_message_delivery_and_dispatch_fee(&source_client, estimate_message_fee_method, lane, payload) - .await?; - - println!("Fee: {:?}", fee); - } - cli::EstimateFee::MillauToRialto { source, lane, payload } => { - type Source = Millau; - type SourceBalance = bp_millau::Balance; - - let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; - - let source_client = source.into_client::().await.map_err(format_err)?; - let lane = lane.into(); - let payload = Source::encode_message(payload)?; - - let fee: Option = - estimate_message_delivery_and_dispatch_fee(&source_client, estimate_message_fee_method, lane, payload) - .await?; - - println!("Fee: {:?}", fee); - } - } - - Ok(()) -} - -async fn estimate_message_delivery_and_dispatch_fee( - client: &relay_substrate_client::Client, - estimate_fee_method: &str, - lane: bp_messages::LaneId, - payload: P, -) -> Result, relay_substrate_client::Error> { - let encoded_response = client - .state_call(estimate_fee_method.into(), (lane, payload).encode().into(), None) - .await?; - let decoded_response: Option = - Decode::decode(&mut &encoded_response.0[..]).map_err(relay_substrate_client::Error::ResponseParseFailed)?; - Ok(decoded_response) -} - -fn message_payload( - spec_version: u32, - weight: Weight, - origin: CallOrigin, - call: &impl Encode, -) -> MessagePayload> -where - SAccountId: Encode + Debug, - TPublic: Encode + Debug, - TSignature: Encode + Debug, -{ - // Display nicely formatted call. - let payload = MessagePayload { - spec_version, - weight, - origin, - call: HexBytes::encode(call), - }; - - log::info!(target: "bridge", "Created Message Payload: {:#?}", payload); - log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload)); - - // re-pack to return `Vec` - let MessagePayload { - spec_version, - weight, - origin, - call, - } = payload; - MessagePayload { - spec_version, - weight, - origin, - call: call.0, - } -} - -fn prepare_call_dispatch_weight( - user_specified_dispatch_weight: Option>, - weight_from_pre_dispatch_call: ExplicitOrMaximal, - maximal_allowed_weight: Weight, -) -> Weight { - match user_specified_dispatch_weight.unwrap_or(weight_from_pre_dispatch_call) { - ExplicitOrMaximal::Explicit(weight) => weight, - ExplicitOrMaximal::Maximal => maximal_allowed_weight, - } -} - -async fn get_fee(fee: Option, f: F) -> Result -where - Fee: Decode, - F: FnOnce() -> R, - R: std::future::Future, E>>, - E: Debug, -{ - match fee { - Some(fee) => Ok(fee), - None => match f().await { - Ok(Some(fee)) => Ok(fee), - Ok(None) => Err("Failed to estimate message fee. Message is too heavy?".into()), - Err(error) => Err(format!("Failed to estimate message fee: {:?}", error)), - }, - } -} - -fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { - bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight) -} - -impl CliEncodeCall for Millau { - fn max_extrinsic_size() -> u32 { - bp_millau::max_extrinsic_size() - } - - fn encode_call(call: &Call) -> anyhow::Result { - Ok(match call { - Call::Raw { data } => Decode::decode(&mut &*data.0)?, - Call::Remark { remark_payload, .. } => millau_runtime::Call::System(millau_runtime::SystemCall::remark( - remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - )), - Call::Transfer { recipient, amount } => millau_runtime::Call::Balances( - millau_runtime::BalancesCall::transfer(recipient.raw_id(), amount.cast()), - ), - Call::BridgeSendMessage { - lane, - payload, - fee, - bridge_instance_index, - } => match *bridge_instance_index { - MILLAU_TO_RIALTO_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( - lane.0, - payload, - fee.cast(), - )) - } - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, - }) - } -} - -impl CliChain for Millau { - const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload>; - - fn ss58_format() -> u16 { - millau_runtime::SS58Prefix::get() as u16 - } - - fn max_extrinsic_weight() -> Weight { - bp_millau::max_extrinsic_weight() - } - - // TODO [#854|#843] support multiple bridges? - fn encode_message(message: cli::MessagePayload) -> Result { - match message { - cli::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)), - cli::MessagePayload::Call { mut call, mut sender } => { - type Source = Millau; - type Target = 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, MILLAU_TO_RIALTO_INDEX); - let call = Target::encode_call(&call).map_err(|e| e.to_string())?; - let weight = call.get_dispatch_info().weight; - - Ok(message_payload(spec_version, weight, origin, &call)) - } - } - } -} - -impl CliEncodeCall for Rialto { - fn max_extrinsic_size() -> u32 { - bp_rialto::max_extrinsic_size() - } - - fn encode_call(call: &Call) -> anyhow::Result { - Ok(match call { - Call::Raw { data } => Decode::decode(&mut &*data.0)?, - Call::Remark { remark_payload, .. } => rialto_runtime::Call::System(rialto_runtime::SystemCall::remark( - remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), - )), - Call::Transfer { recipient, amount } => { - rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount.0)) - } - Call::BridgeSendMessage { - lane, - payload, - fee, - bridge_instance_index, - } => match *bridge_instance_index { - RIALTO_TO_MILLAU_INDEX => { - let payload = Decode::decode(&mut &*payload.0)?; - rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( - lane.0, payload, fee.0, - )) - } - _ => anyhow::bail!( - "Unsupported target bridge pallet with instance index: {}", - bridge_instance_index - ), - }, - }) - } -} - -impl CliChain for Rialto { - const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = MessagePayload>; - - fn ss58_format() -> u16 { - rialto_runtime::SS58Prefix::get() as u16 - } - - fn max_extrinsic_weight() -> Weight { - bp_rialto::max_extrinsic_weight() - } - - fn encode_message(message: cli::MessagePayload) -> Result { - match message { - cli::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)), - cli::MessagePayload::Call { mut call, mut sender } => { - type Source = Rialto; - type Target = 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, RIALTO_TO_MILLAU_INDEX); - let call = Target::encode_call(&call).map_err(|e| e.to_string())?; - let weight = call.get_dispatch_info().weight; - - Ok(message_payload(spec_version, weight, origin, &call)) - } - } - } -} - -impl CliChain for Westend { - const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = (); - - fn ss58_format() -> u16 { - 42 - } - - fn max_extrinsic_weight() -> Weight { - 0 - } - - fn encode_message(_message: cli::MessagePayload) -> Result { - Err("Sending messages from Westend is not yet supported.".into()) - } -} - -impl CliChain for Rococo { - const RUNTIME_VERSION: RuntimeVersion = bp_rococo::VERSION; - - type KeyPair = sp_core::sr25519::Pair; - type MessagePayload = (); - - fn ss58_format() -> u16 { - 42 - } - - fn max_extrinsic_weight() -> Weight { - 0 - } - - fn encode_message(_message: cli::MessagePayload) -> Result { - Err("Sending messages from Rococo is not yet supported.".into()) - } -} - -fn format_err(e: anyhow::Error) -> String { - e.to_string() -} - -#[cfg(test)] -mod tests { - use super::*; - use bp_messages::source_chain::TargetHeaderChain; - 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(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::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(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::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() { - use rialto_runtime::millau_messages::Millau; - - let maximal_remark_size = encode_call::compute_maximal_message_arguments_size( - bp_rialto::max_extrinsic_size(), - bp_millau::max_extrinsic_size(), - ); - - let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into(); - let payload = message_payload( - Default::default(), - call.get_dispatch_info().weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert_eq!(Millau::verify_message(&payload), Ok(())); - - let call: millau_runtime::Call = - millau_runtime::SystemCall::remark(vec![42; (maximal_remark_size + 1) as _]).into(); - let payload = message_payload( - Default::default(), - call.get_dispatch_info().weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert!(Millau::verify_message(&payload).is_err()); - } - - #[test] - fn maximal_size_remark_to_rialto_is_generated_correctly() { - assert!( - bridge_runtime_common::messages::target::maximal_incoming_message_size( - bp_rialto::max_extrinsic_size() - ) > bp_millau::max_extrinsic_size(), - "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 = compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight()); - let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into(); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert_eq!(Millau::verify_message(&payload), Ok(())); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight + 1, - pallet_bridge_dispatch::CallOrigin::SourceRoot, - &call, - ); - 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 = compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight()); - let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into(); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight, - pallet_bridge_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert_eq!(Rialto::verify_message(&payload), Ok(())); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight + 1, - pallet_bridge_dispatch::CallOrigin::SourceRoot, - &call, - ); - 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(vec![])); - let rialto_tx = Rialto::sign_transaction( - Default::default(), - &sp_keyring::AccountKeyring::Alice.pair(), - 0, - rialto_call.clone(), - ); - let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); - assert!( - bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, - "Hardcoded number of extra bytes in Rialto transaction {} is lower than actual value: {}", - bp_rialto::TX_EXTRA_BYTES, - extra_bytes_in_transaction, - ); - } - - #[test] - fn millau_tx_extra_bytes_constant_is_correct() { - let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![])); - let millau_tx = Millau::sign_transaction( - Default::default(), - &sp_keyring::AccountKeyring::Alice.pair(), - 0, - millau_call.clone(), - ); - let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); - assert!( - bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, - "Hardcoded number of extra bytes in Millau transaction {} is lower than actual value: {}", - bp_millau::TX_EXTRA_BYTES, - extra_bytes_in_transaction, - ); - } -} diff --git a/relays/client-ethereum/Cargo.toml b/relays/client-ethereum/Cargo.toml index 79f6ab0cf6fe..56e346417301 100644 --- a/relays/client-ethereum/Cargo.toml +++ b/relays/client-ethereum/Cargo.toml @@ -10,9 +10,9 @@ bp-eth-poa = { path = "../../primitives/ethereum-poa" } codec = { package = "parity-scale-codec", version = "2.0.0" } headers-relay = { path = "../headers" } hex-literal = "0.3" -jsonrpsee-proc-macros = "0.2.0-alpha.2" -jsonrpsee-types = "0.2.0-alpha.2" -jsonrpsee-ws-client = "0.2.0-alpha.2" +jsonrpsee-proc-macros = "=0.2.0-alpha.3" +jsonrpsee-types = "=0.2.0-alpha.3" +jsonrpsee-ws-client = "=0.2.0-alpha.3" libsecp256k1 = { version = "0.3.4", default-features = false, features = ["hmac"] } log = "0.4.11" relay-utils = { path = "../utils" } diff --git a/relays/client-substrate/Cargo.toml b/relays/client-substrate/Cargo.toml index 48feac3834e4..012913d4a4a2 100644 --- a/relays/client-substrate/Cargo.toml +++ b/relays/client-substrate/Cargo.toml @@ -9,9 +9,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" async-std = "1.6.5" async-trait = "0.1.40" codec = { package = "parity-scale-codec", version = "2.0.0" } -jsonrpsee-proc-macros = "0.2.0-alpha.2" -jsonrpsee-types = "0.2.0-alpha.2" -jsonrpsee-ws-client = "0.2.0-alpha.2" +jsonrpsee-proc-macros = "=0.2.0-alpha.3" +jsonrpsee-types = "=0.2.0-alpha.3" +jsonrpsee-ws-client = "=0.2.0-alpha.3" log = "0.4.11" num-traits = "0.2" rand = "0.7" @@ -34,6 +34,7 @@ sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-std = { 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" } diff --git a/relays/client-substrate/src/client.rs b/relays/client-substrate/src/client.rs index a149ba69701f..ce91f4e33fc7 100644 --- a/relays/client-substrate/src/client.rs +++ b/relays/client-substrate/src/client.rs @@ -17,12 +17,10 @@ //! Substrate node client. use crate::chain::{Chain, ChainWithBalances}; -use crate::rpc::{Substrate, SubstrateMessages}; +use crate::rpc::Substrate; use crate::{ConnectionParams, Error, Result}; use async_std::sync::{Arc, Mutex}; -use bp_messages::{LaneId, MessageNonce}; -use bp_runtime::InstanceId; use codec::Decode; use frame_system::AccountInfo; use jsonrpsee_types::{jsonrpc::DeserializeOwned, traits::SubscriptionClient}; @@ -32,7 +30,6 @@ use pallet_balances::AccountData; use sp_core::{storage::StorageKey, Bytes}; use sp_trie::StorageProof; use sp_version::RuntimeVersion; -use std::ops::RangeInclusive; const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities"; const MAX_SUBSCRIPTION_CAPACITY: usize = 4096; @@ -50,7 +47,7 @@ pub struct Client { /// Client connection params. params: ConnectionParams, /// Substrate RPC client. - client: RpcClient, + client: Arc, /// Genesis block hash. genesis_hash: C::Hash, /// If several tasks are submitting their transactions simultaneously using `submit_signed_extrinsic` @@ -84,7 +81,7 @@ impl Client { let client = Self::build_client(params.clone()).await?; let number: C::BlockNumber = Zero::zero(); - let genesis_hash = Substrate::::chain_get_block_hash(&client, number).await?; + let genesis_hash = Substrate::::chain_get_block_hash(&*client, number).await?; Ok(Self { params, @@ -101,7 +98,7 @@ impl Client { } /// Build client to use in connection. - async fn build_client(params: ConnectionParams) -> Result { + async fn build_client(params: ConnectionParams) -> Result> { let uri = format!( "{}://{}:{}", if params.secure { "wss" } else { "ws" }, @@ -111,14 +108,15 @@ impl Client { let mut config = RpcConfig::with_url(&uri); config.max_notifs_per_subscription = MAX_SUBSCRIPTION_CAPACITY; let client = RpcClient::new(config).await?; - Ok(client) + + Ok(Arc::new(client)) } } 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<()> { - let health = Substrate::::system_health(&self.client).await?; + let health = Substrate::::system_health(&*self.client).await?; let is_synced = !health.is_syncing && (!health.should_have_peers || health.peers > 0); if is_synced { Ok(()) @@ -134,7 +132,7 @@ impl Client { /// Return hash of the best finalized block. pub async fn best_finalized_header_hash(&self) -> Result { - Ok(Substrate::::chain_get_finalized_head(&self.client).await?) + Ok(Substrate::::chain_get_finalized_head(&*self.client).await?) } /// Returns the best Substrate header. @@ -142,12 +140,12 @@ impl Client { where C::Header: DeserializeOwned, { - Ok(Substrate::::chain_get_header(&self.client, None).await?) + Ok(Substrate::::chain_get_header(&*self.client, None).await?) } /// Get a Substrate block from its hash. pub async fn get_block(&self, block_hash: Option) -> Result { - Ok(Substrate::::chain_get_block(&self.client, block_hash).await?) + Ok(Substrate::::chain_get_block(&*self.client, block_hash).await?) } /// Get a Substrate header by its hash. @@ -155,12 +153,12 @@ impl Client { where C::Header: DeserializeOwned, { - Ok(Substrate::::chain_get_header(&self.client, block_hash).await?) + Ok(Substrate::::chain_get_header(&*self.client, block_hash).await?) } /// Get a Substrate block hash by its number. pub async fn block_hash_by_number(&self, number: C::BlockNumber) -> Result { - Ok(Substrate::::chain_get_block_hash(&self.client, number).await?) + Ok(Substrate::::chain_get_block_hash(&*self.client, number).await?) } /// Get a Substrate header by its number. @@ -174,12 +172,12 @@ impl Client { /// Return runtime version. pub async fn runtime_version(&self) -> Result { - Ok(Substrate::::runtime_version(&self.client).await?) + Ok(Substrate::::state_runtime_version(&*self.client).await?) } /// Read value from runtime storage. pub async fn storage_value(&self, storage_key: StorageKey) -> Result> { - Substrate::::get_storage(&self.client, storage_key) + Substrate::::state_get_storage(&*self.client, storage_key) .await? .map(|encoded_value| T::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed)) .transpose() @@ -191,7 +189,7 @@ impl Client { C: ChainWithBalances, { let storage_key = C::account_info_storage_key(&account); - let encoded_account_data = Substrate::::get_storage(&self.client, storage_key) + let encoded_account_data = Substrate::::state_get_storage(&*self.client, storage_key) .await? .ok_or(Error::AccountDoesNotExist)?; let decoded_account_data = @@ -204,14 +202,14 @@ 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 { - Ok(Substrate::::system_account_next_index(&self.client, account).await?) + Ok(Substrate::::system_account_next_index(&*self.client, account).await?) } /// Submit unsigned extrinsic for inclusion in a block. /// /// Note: The given transaction needs to be SCALE encoded beforehand. pub async fn submit_unsigned_extrinsic(&self, transaction: Bytes) -> Result { - let tx_hash = Substrate::::author_submit_extrinsic(&self.client, transaction).await?; + let tx_hash = Substrate::::author_submit_extrinsic(&*self.client, transaction).await?; log::trace!(target: "bridge", "Sent transaction to Substrate node: {:?}", tx_hash); Ok(tx_hash) } @@ -231,7 +229,7 @@ impl Client { let _guard = self.submit_signed_extrinsic_lock.lock().await; let transaction_nonce = self.next_account_index(extrinsic_signer).await?; let extrinsic = prepare_extrinsic(transaction_nonce); - let tx_hash = Substrate::::author_submit_extrinsic(&self.client, extrinsic).await?; + let tx_hash = Substrate::::author_submit_extrinsic(&*self.client, extrinsic).await?; log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); Ok(tx_hash) } @@ -241,7 +239,7 @@ impl Client { let call = SUB_API_GRANDPA_AUTHORITIES.to_string(); let data = Bytes(Vec::new()); - let encoded_response = Substrate::::state_call(&self.client, call, data, Some(block)).await?; + let encoded_response = Substrate::::state_call(&*self.client, call, data, Some(block)).await?; let authority_list = encoded_response.0; Ok(authority_list) @@ -249,50 +247,17 @@ impl Client { /// Execute runtime call at given block. pub async fn state_call(&self, method: String, data: Bytes, at_block: Option) -> Result { - Substrate::::state_call(&self.client, method, data, at_block) + Substrate::::state_call(&*self.client, method, data, at_block) .await .map_err(Into::into) } - /// Returns proof-of-message(s) in given inclusive range. - pub async fn prove_messages( - &self, - instance: InstanceId, - lane: LaneId, - range: RangeInclusive, - include_outbound_lane_state: bool, - at_block: C::Hash, - ) -> Result { - let encoded_trie_nodes = SubstrateMessages::::prove_messages( - &self.client, - instance, - lane, - *range.start(), - *range.end(), - include_outbound_lane_state, - Some(at_block), - ) - .await - .map_err(Error::RpcError)?; - let decoded_trie_nodes: Vec> = - Decode::decode(&mut &encoded_trie_nodes[..]).map_err(Error::ResponseParseFailed)?; - Ok(StorageProof::new(decoded_trie_nodes)) - } - - /// Returns proof-of-message(s) delivery. - pub async fn prove_messages_delivery( - &self, - instance: InstanceId, - lane: LaneId, - at_block: C::Hash, - ) -> Result>> { - let encoded_trie_nodes = - SubstrateMessages::::prove_messages_delivery(&self.client, instance, lane, Some(at_block)) - .await - .map_err(Error::RpcError)?; - let decoded_trie_nodes: Vec> = - Decode::decode(&mut &encoded_trie_nodes[..]).map_err(Error::ResponseParseFailed)?; - Ok(decoded_trie_nodes) + /// Returns storage proof of given storage keys. + pub async fn prove_storage(&self, keys: Vec, at_block: C::Hash) -> Result { + Substrate::::state_prove_storage(&*self.client, keys, Some(at_block)) + .await + .map(|proof| StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect())) + .map_err(Into::into) } /// Return new justifications stream. diff --git a/relays/client-substrate/src/error.rs b/relays/client-substrate/src/error.rs index db1cdb437454..7aee28df1857 100644 --- a/relays/client-substrate/src/error.rs +++ b/relays/client-substrate/src/error.rs @@ -36,6 +36,8 @@ pub enum Error { UninitializedBridgePallet, /// Account does not exist on the chain. AccountDoesNotExist, + /// Runtime storage is missing mandatory ":code:" entry. + MissingMandatoryCodeEntry, /// The client we're connected to is not synced, so we can't rely on its state. ClientNotSynced(Health), /// An error has happened when we have tried to parse storage proof. @@ -51,6 +53,7 @@ impl std::error::Error for Error { Self::ResponseParseFailed(ref e) => Some(e), Self::UninitializedBridgePallet => None, Self::AccountDoesNotExist => None, + Self::MissingMandatoryCodeEntry => None, Self::ClientNotSynced(_) => None, Self::StorageProofError(_) => None, Self::Custom(_) => None, @@ -72,6 +75,7 @@ impl MaybeConnectionError for Error { // right now if connection to the ws server is dropped (after it is already established), // we're getting this error | Error::RpcError(RpcError::Internal(_)) + | Error::RpcError(RpcError::RestartNeeded(_)) | Error::ClientNotSynced(_), ) } @@ -84,6 +88,7 @@ impl std::fmt::Display for Error { Self::ResponseParseFailed(e) => e.to_string(), Self::UninitializedBridgePallet => "The Substrate bridge pallet has not been initialized yet.".into(), Self::AccountDoesNotExist => "Account does not exist on the chain".into(), + Self::MissingMandatoryCodeEntry => "Mandatory :code: entry is missing from runtime storage".into(), Self::StorageProofError(e) => format!("Error when parsing storage proof: {:?}", e), Self::ClientNotSynced(health) => format!("Substrate client is not synced: {}", health), Self::Custom(e) => e.clone(), diff --git a/relays/client-substrate/src/metrics/float_storage_value.rs b/relays/client-substrate/src/metrics/float_storage_value.rs index e1647d4bcd51..f3ba8988eea4 100644 --- a/relays/client-substrate/src/metrics/float_storage_value.rs +++ b/relays/client-substrate/src/metrics/float_storage_value.rs @@ -19,7 +19,7 @@ use crate::client::Client; use async_trait::async_trait; use codec::Decode; -use relay_utils::metrics::{register, Gauge, Metrics, Registry, StandaloneMetrics, F64}; +use relay_utils::metrics::{metric_name, register, Gauge, PrometheusError, Registry, StandaloneMetrics, F64}; use sp_core::storage::StorageKey; use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber}; use std::time::Duration; @@ -39,29 +39,20 @@ pub struct FloatStorageValueMetric { impl FloatStorageValueMetric { /// Create new metric. pub fn new( + registry: &Registry, + prefix: Option<&str>, client: Client, storage_key: StorageKey, maybe_default_value: Option, name: String, help: String, - ) -> Self { - FloatStorageValueMetric { + ) -> Result { + Ok(FloatStorageValueMetric { client, storage_key, maybe_default_value, - metric: Gauge::new(name, help).expect( - "only fails if gauge options are customized;\ - we use default options;\ - qed", - ), - } - } -} - -impl Metrics for FloatStorageValueMetric { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.metric.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) + metric: register(Gauge::new(metric_name(prefix, &name), help)?, registry)?, + }) } } diff --git a/relays/client-substrate/src/metrics/storage_proof_overhead.rs b/relays/client-substrate/src/metrics/storage_proof_overhead.rs index 167f59605d27..526fe1e048bf 100644 --- a/relays/client-substrate/src/metrics/storage_proof_overhead.rs +++ b/relays/client-substrate/src/metrics/storage_proof_overhead.rs @@ -19,12 +19,10 @@ use crate::client::Client; use crate::error::Error; use async_trait::async_trait; -use bp_messages::LaneId; -use bp_runtime::InstanceId; -use relay_utils::metrics::{register, Gauge, Metrics, Registry, StandaloneMetrics, U64}; +use relay_utils::metrics::{metric_name, register, Gauge, PrometheusError, Registry, StandaloneMetrics, U64}; use sp_core::storage::StorageKey; use sp_runtime::traits::Header as HeaderT; -use sp_trie::StorageProof; +use sp_storage::well_known_keys::CODE; use std::time::Duration; /// Storage proof overhead update interval (in blocks). @@ -32,20 +30,11 @@ const UPDATE_INTERVAL_IN_BLOCKS: u32 = 100; /// Metric that represents extra size of storage proof as unsigned integer gauge. /// -/// Regular Substrate node does not provide any RPC endpoints that return storage proofs. -/// So here we're using our own `pallet-bridge-messages-rpc` RPC API, which returns proof -/// of the inbound message lane state. Then we simply subtract size of this state from -/// the size of storage proof to compute metric value. -/// -/// There are two things to keep in mind when using this metric: -/// -/// 1) it'll only work on inbound lanes that have already accepted at least one message; -/// 2) the overhead may be slightly different for other values, but this metric gives a good estimation. +/// There's one thing to keep in mind when using this metric: the overhead may be slightly +/// different for other values, but this metric gives a good estimation. #[derive(Debug)] pub struct StorageProofOverheadMetric { client: Client, - inbound_lane: (InstanceId, LaneId), - inbound_lane_data_key: StorageKey, metric: Gauge, } @@ -53,8 +42,6 @@ impl Clone for StorageProofOverheadMetric { fn clone(&self) -> Self { StorageProofOverheadMetric { client: self.client.clone(), - inbound_lane: self.inbound_lane, - inbound_lane_data_key: self.inbound_lane_data_key.clone(), metric: self.metric.clone(), } } @@ -63,58 +50,40 @@ impl Clone for StorageProofOverheadMetric { impl StorageProofOverheadMetric { /// Create new metric instance with given name and help. pub fn new( + registry: &Registry, + prefix: Option<&str>, client: Client, - inbound_lane: (InstanceId, LaneId), - inbound_lane_data_key: StorageKey, name: String, help: String, - ) -> Self { - StorageProofOverheadMetric { + ) -> Result { + Ok(StorageProofOverheadMetric { client, - inbound_lane, - inbound_lane_data_key, - metric: Gauge::new(name, help).expect( - "only fails if gauge options are customized;\ - we use default options;\ - qed", - ), - } + metric: register(Gauge::new(metric_name(prefix, &name), help)?, registry)?, + }) } /// Returns approximate storage proof size overhead. - /// - /// Returs `Ok(None)` if inbound lane we're watching for has no state. This shouldn't be treated as error. - async fn compute_storage_proof_overhead(&self) -> Result, Error> { + async fn compute_storage_proof_overhead(&self) -> Result { let best_header_hash = self.client.best_finalized_header_hash().await?; let best_header = self.client.header_by_hash(best_header_hash).await?; let storage_proof = self .client - .prove_messages_delivery(self.inbound_lane.0, self.inbound_lane.1, best_header_hash) + .prove_storage(vec![StorageKey(CODE.to_vec())], best_header_hash) .await?; - let storage_proof_size: usize = storage_proof.iter().map(|n| n.len()).sum(); + let storage_proof_size: usize = storage_proof.clone().iter_nodes().map(|n| n.len()).sum(); - let storage_value_reader = bp_runtime::StorageProofChecker::::new( - *best_header.state_root(), - StorageProof::new(storage_proof), - ) - .map_err(Error::StorageProofError)?; + let storage_value_reader = + bp_runtime::StorageProofChecker::::new(*best_header.state_root(), storage_proof) + .map_err(Error::StorageProofError)?; let maybe_encoded_storage_value = storage_value_reader - .read_value(&self.inbound_lane_data_key.0) + .read_value(CODE) .map_err(Error::StorageProofError)?; - let encoded_storage_value_size = match maybe_encoded_storage_value { - Some(encoded_storage_value) => encoded_storage_value.len(), - None => return Ok(None), - }; - - Ok(Some(storage_proof_size - encoded_storage_value_size)) - } -} + let encoded_storage_value_size = maybe_encoded_storage_value + .ok_or(Error::MissingMandatoryCodeEntry)? + .len(); -impl Metrics for StorageProofOverheadMetric { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.metric.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) + Ok(storage_proof_size - encoded_storage_value_size) } } @@ -129,7 +98,7 @@ impl StandaloneMetrics for StorageProofOverheadMetric { &self.metric, self.compute_storage_proof_overhead() .await - .map(|v| v.map(|overhead| overhead as u64)), + .map(|overhead| Some(overhead as u64)), ); } } diff --git a/relays/client-substrate/src/rpc.rs b/relays/client-substrate/src/rpc.rs index 1816e8cd3f26..06df1f705d09 100644 --- a/relays/client-substrate/src/rpc.rs +++ b/relays/client-substrate/src/rpc.rs @@ -18,9 +18,7 @@ use crate::chain::Chain; -use bp_messages::{LaneId, MessageNonce}; -use bp_runtime::InstanceId; -use sc_rpc_api::system::Health; +use sc_rpc_api::{state::ReadProof, system::Health}; use sp_core::{ storage::{StorageData, StorageKey}, Bytes, @@ -46,27 +44,10 @@ jsonrpsee_proc_macros::rpc_client_api! { #[rpc(method = "state_call", positional_params)] fn state_call(method: String, data: Bytes, at_block: Option) -> Bytes; #[rpc(method = "state_getStorage", positional_params)] - fn get_storage(key: StorageKey) -> Option; + fn state_get_storage(key: StorageKey) -> Option; + #[rpc(method = "state_getReadProof", positional_params)] + fn state_prove_storage(keys: Vec, hash: Option) -> ReadProof; #[rpc(method = "state_getRuntimeVersion", positional_params)] - fn runtime_version() -> RuntimeVersion; - } - - pub(crate) SubstrateMessages { - #[rpc(method = "messages_proveMessages", positional_params)] - fn prove_messages( - instance: InstanceId, - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - include_outbound_lane_state: bool, - block: Option, - ) -> Bytes; - - #[rpc(method = "messages_proveMessagesDelivery", positional_params)] - fn prove_messages_delivery( - instance: InstanceId, - lane: LaneId, - block: Option, - ) -> Bytes; + fn state_runtime_version() -> RuntimeVersion; } } diff --git a/relays/exchange/src/exchange_loop.rs b/relays/exchange/src/exchange_loop.rs index 7bb4abb7461b..b46d34e047a8 100644 --- a/relays/exchange/src/exchange_loop.rs +++ b/relays/exchange/src/exchange_loop.rs @@ -78,6 +78,11 @@ impl TransactionProofsRelayStorage for InMemoryStorag } } +/// Return prefix that will be used by default to expose Prometheus metrics of the exchange loop. +pub fn metrics_prefix() -> String { + format!("{}_to_{}_Exchange", P::SOURCE_NAME, P::TARGET_NAME) +} + /// Run proofs synchronization. pub async fn run( storage: impl TransactionProofsRelayStorage>, @@ -89,12 +94,9 @@ pub async fn run( let exit_signal = exit_signal.shared(); relay_utils::relay_loop(source_client, target_client) - .with_metrics( - format!("{}_to_{}_Exchange", P::SOURCE_NAME, P::TARGET_NAME), - metrics_params, - ) - .loop_metric(ExchangeLoopMetrics::default())? - .standalone_metric(GlobalMetrics::default())? + .with_metrics(Some(metrics_prefix::

()), metrics_params) + .loop_metric(|registry, prefix| ExchangeLoopMetrics::new(registry, prefix))? + .standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))? .expose() .await? .run(|source_client, target_client, metrics| { diff --git a/relays/exchange/src/exchange_loop_metrics.rs b/relays/exchange/src/exchange_loop_metrics.rs index 320f662c6dc5..82d3e649d431 100644 --- a/relays/exchange/src/exchange_loop_metrics.rs +++ b/relays/exchange/src/exchange_loop_metrics.rs @@ -17,7 +17,9 @@ //! Metrics for currency-exchange relay loop. use crate::exchange::{BlockNumberOf, RelayedBlockTransactions, TransactionProofPipeline}; -use relay_utils::metrics::{register, Counter, CounterVec, GaugeVec, Metrics, Opts, Registry, U64}; +use relay_utils::metrics::{ + metric_name, register, Counter, CounterVec, GaugeVec, Opts, PrometheusError, Registry, U64, +}; /// Exchange transactions relay metrics. #[derive(Clone)] @@ -30,31 +32,38 @@ pub struct ExchangeLoopMetrics { processed_transactions: CounterVec, } -impl Metrics for ExchangeLoopMetrics { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.best_block_numbers.clone(), registry).map_err(|e| e.to_string())?; - register(self.processed_blocks.clone(), registry).map_err(|e| e.to_string())?; - register(self.processed_transactions.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) - } -} - -impl Default for ExchangeLoopMetrics { - fn default() -> Self { - ExchangeLoopMetrics { - best_block_numbers: GaugeVec::new( - Opts::new("best_block_numbers", "Best finalized block numbers"), - &["type"], - ) - .expect("metric is static and thus valid; qed"), - processed_blocks: Counter::new("processed_blocks", "Total number of processed blocks") - .expect("metric is static and thus valid; qed"), - processed_transactions: CounterVec::new( - Opts::new("processed_transactions", "Total number of processed transactions"), - &["type"], - ) - .expect("metric is static and thus valid; qed"), - } +impl ExchangeLoopMetrics { + /// Create and register exchange loop metrics. + pub fn new(registry: &Registry, prefix: Option<&str>) -> Result { + Ok(ExchangeLoopMetrics { + best_block_numbers: register( + GaugeVec::new( + Opts::new( + metric_name(prefix, "best_block_numbers"), + "Best finalized block numbers", + ), + &["type"], + )?, + registry, + )?, + processed_blocks: register( + Counter::new( + metric_name(prefix, "processed_blocks"), + "Total number of processed blocks", + )?, + registry, + )?, + processed_transactions: register( + CounterVec::new( + Opts::new( + metric_name(prefix, "processed_transactions"), + "Total number of processed transactions", + ), + &["type"], + )?, + registry, + )?, + }) } } diff --git a/relays/finality/src/finality_loop.rs b/relays/finality/src/finality_loop.rs index e0ad8a7c1b6d..aff32e46de44 100644 --- a/relays/finality/src/finality_loop.rs +++ b/relays/finality/src/finality_loop.rs @@ -105,9 +105,9 @@ pub async fn run( ) -> Result<(), String> { let exit_signal = exit_signal.shared(); relay_utils::relay_loop(source_client, target_client) - .with_metrics(metrics_prefix::

(), metrics_params) - .loop_metric(SyncLoopMetrics::default())? - .standalone_metric(GlobalMetrics::default())? + .with_metrics(Some(metrics_prefix::

()), metrics_params) + .loop_metric(|registry, prefix| SyncLoopMetrics::new(registry, prefix))? + .standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))? .expose() .await? .run(|source_client, target_client, metrics| { diff --git a/relays/headers/src/sync_loop.rs b/relays/headers/src/sync_loop.rs index 2e0d12ec87c8..e4f1b7b04507 100644 --- a/relays/headers/src/sync_loop.rs +++ b/relays/headers/src/sync_loop.rs @@ -110,6 +110,11 @@ pub trait SyncMaintain: Clone + Send + Sync { impl SyncMaintain

for () {} +/// Return prefix that will be used by default to expose Prometheus metrics of the finality proofs sync loop. +pub fn metrics_prefix() -> String { + format!("{}_to_{}_Sync", P::SOURCE_NAME, P::TARGET_NAME) +} + /// Run headers synchronization. #[allow(clippy::too_many_arguments)] pub async fn run>( @@ -124,9 +129,9 @@ pub async fn run>( ) -> Result<(), String> { let exit_signal = exit_signal.shared(); relay_utils::relay_loop(source_client, target_client) - .with_metrics(format!("{}_to_{}_Sync", P::SOURCE_NAME, P::TARGET_NAME), metrics_params) - .loop_metric(SyncLoopMetrics::default())? - .standalone_metric(GlobalMetrics::default())? + .with_metrics(Some(metrics_prefix::

()), metrics_params) + .loop_metric(|registry, prefix| SyncLoopMetrics::new(registry, prefix))? + .standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))? .expose() .await? .run(|source_client, target_client, metrics| { @@ -628,5 +633,5 @@ fn print_sync_progress( now_best_header.map(|id| id.0), now_target_header, ); - (now_time, now_best_header.clone().map(|id| id.0), *now_target_header) + (now_time, (*now_best_header).map(|id| id.0), *now_target_header) } diff --git a/relays/headers/src/sync_loop_metrics.rs b/relays/headers/src/sync_loop_metrics.rs index 616a04360d6b..37dae1134042 100644 --- a/relays/headers/src/sync_loop_metrics.rs +++ b/relays/headers/src/sync_loop_metrics.rs @@ -20,7 +20,7 @@ use crate::sync::HeadersSync; use crate::sync_types::{HeaderStatus, HeadersSyncPipeline}; use num_traits::Zero; -use relay_utils::metrics::{register, GaugeVec, Metrics, Opts, Registry, U64}; +use relay_utils::metrics::{metric_name, register, GaugeVec, Opts, PrometheusError, Registry, U64}; /// Headers sync metrics. #[derive(Clone)] @@ -31,28 +31,31 @@ pub struct SyncLoopMetrics { blocks_in_state: GaugeVec, } -impl Metrics for SyncLoopMetrics { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.best_block_numbers.clone(), registry).map_err(|e| e.to_string())?; - register(self.blocks_in_state.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) - } -} - -impl Default for SyncLoopMetrics { - fn default() -> Self { - SyncLoopMetrics { - best_block_numbers: GaugeVec::new( - Opts::new("best_block_numbers", "Best block numbers on source and target nodes"), - &["node"], - ) - .expect("metric is static and thus valid; qed"), - blocks_in_state: GaugeVec::new( - Opts::new("blocks_in_state", "Number of blocks in given state"), - &["state"], - ) - .expect("metric is static and thus valid; qed"), - } +impl SyncLoopMetrics { + /// Create and register headers loop metrics. + pub fn new(registry: &Registry, prefix: Option<&str>) -> Result { + Ok(SyncLoopMetrics { + best_block_numbers: register( + GaugeVec::new( + Opts::new( + metric_name(prefix, "best_block_numbers"), + "Best block numbers on source and target nodes", + ), + &["node"], + )?, + registry, + )?, + blocks_in_state: register( + GaugeVec::new( + Opts::new( + metric_name(prefix, "blocks_in_state"), + "Number of blocks in given state", + ), + &["state"], + )?, + registry, + )?, + }) } } diff --git a/relays/messages/src/message_lane_loop.rs b/relays/messages/src/message_lane_loop.rs index daa74b50735b..41eee606d82b 100644 --- a/relays/messages/src/message_lane_loop.rs +++ b/relays/messages/src/message_lane_loop.rs @@ -140,8 +140,8 @@ pub trait SourceClient: RelayClient { proof: P::MessagesReceivingProof, ) -> Result<(), Self::Error>; - /// Activate (or deactivate) headers relay that relays target headers to source node. - async fn activate_target_to_source_headers_relay(&self, activate: bool); + /// We need given finalized target header on source to continue synchronization. + async fn require_target_header_on_source(&self, id: TargetHeaderIdOf

); } /// Target client trait. @@ -181,8 +181,8 @@ pub trait TargetClient: RelayClient { proof: P::MessagesProof, ) -> Result, Self::Error>; - /// Activate (or deactivate) headers relay that relays source headers to target node. - async fn activate_source_to_target_headers_relay(&self, activate: bool); + /// We need given finalized source header on target to continue synchronization. + async fn require_source_header_on_target(&self, id: SourceHeaderIdOf

); } /// State of the client. @@ -232,9 +232,9 @@ pub async fn run( let exit_signal = exit_signal.shared(); relay_utils::relay_loop(source_client, target_client) .reconnect_delay(params.reconnect_delay) - .with_metrics(metrics_prefix::

(¶ms.lane), metrics_params) - .loop_metric(MessageLaneLoopMetrics::default())? - .standalone_metric(GlobalMetrics::default())? + .with_metrics(Some(metrics_prefix::

(¶ms.lane)), metrics_params) + .loop_metric(|registry, prefix| MessageLaneLoopMetrics::new(registry, prefix))? + .standalone_metric(|registry, prefix| GlobalMetrics::new(registry, prefix))? .expose() .await? .run(|source_client, target_client, metrics| { @@ -475,8 +475,10 @@ pub(crate) mod tests { target_latest_received_nonce: MessageNonce, target_latest_confirmed_received_nonce: MessageNonce, submitted_messages_proofs: Vec, - is_target_to_source_headers_relay_activated: bool, - is_source_to_target_headers_relay_activated: bool, + target_to_source_header_required: Option, + target_to_source_header_requirements: Vec, + source_to_target_header_required: Option, + source_to_target_header_requirements: Vec, } #[derive(Clone)] @@ -582,9 +584,10 @@ pub(crate) mod tests { Ok(()) } - async fn activate_target_to_source_headers_relay(&self, activate: bool) { + async fn require_target_header_on_source(&self, id: TargetHeaderIdOf) { let mut data = self.data.lock(); - data.is_target_to_source_headers_relay_activated = activate; + data.target_to_source_header_required = Some(id); + data.target_to_source_header_requirements.push(id); (self.tick)(&mut *data); } } @@ -686,9 +689,10 @@ pub(crate) mod tests { Ok(nonces) } - async fn activate_source_to_target_headers_relay(&self, activate: bool) { + async fn require_source_header_on_target(&self, id: SourceHeaderIdOf) { let mut data = self.data.lock(); - data.is_source_to_target_headers_relay_activated = activate; + data.source_to_target_header_required = Some(id); + data.source_to_target_header_requirements.push(id); (self.tick)(&mut *data); } } @@ -806,16 +810,16 @@ pub(crate) mod tests { }, Arc::new(|data: &mut TestClientData| { // headers relay must only be started when we need new target headers at source node - if data.is_target_to_source_headers_relay_activated { + if data.target_to_source_header_required.is_some() { assert!(data.source_state.best_finalized_peer_at_best_self.0 < data.target_state.best_self.0); - data.is_target_to_source_headers_relay_activated = false; + data.target_to_source_header_required = None; } }), Arc::new(move |data: &mut TestClientData| { // headers relay must only be started when we need new source headers at target node - if data.is_target_to_source_headers_relay_activated { + if data.source_to_target_header_required.is_some() { assert!(data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_self.0); - data.is_target_to_source_headers_relay_activated = false; + data.source_to_target_header_required = None; } // syncing source headers -> target chain (all at once) if data.target_state.best_finalized_peer_at_best_self.0 < data.source_state.best_finalized_self.0 { @@ -837,7 +841,7 @@ pub(crate) mod tests { HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.0 + 1); data.source_state.best_finalized_self = data.source_state.best_self; } - // if source has received all messages receiving confirmations => increase source block so that confirmations may be sent + // if source has received all messages receiving confirmations => stop if data.source_latest_confirmed_received_nonce == 10 { exit_sender.unbounded_send(()).unwrap(); } @@ -853,5 +857,9 @@ pub(crate) mod tests { assert_eq!(result.submitted_messages_proofs[1].0, 5..=8); assert_eq!(result.submitted_messages_proofs[2].0, 9..=10); assert!(!result.submitted_messages_receiving_proofs.is_empty()); + + // check that we have at least once required new source->target or target->source headers + assert!(!result.target_to_source_header_requirements.is_empty()); + assert!(!result.source_to_target_header_requirements.is_empty()); } } diff --git a/relays/messages/src/message_race_delivery.rs b/relays/messages/src/message_race_delivery.rs index 3b1644b72892..225c59f23ca3 100644 --- a/relays/messages/src/message_race_delivery.rs +++ b/relays/messages/src/message_race_delivery.rs @@ -166,8 +166,8 @@ where type Error = C::Error; type TargetNoncesData = DeliveryRaceTargetNoncesData; - async fn require_more_source_headers(&self, activate: bool) { - self.client.activate_source_to_target_headers_relay(activate).await + async fn require_source_header(&self, id: SourceHeaderIdOf

) { + self.client.require_source_header_on_target(id).await } async fn nonces( @@ -291,6 +291,10 @@ impl RaceStrategy, TargetHeaderIdOf

, P::M self.strategy.is_empty() } + fn required_source_header_at_target(&self, current_best: &SourceHeaderIdOf

) -> Option> { + self.strategy.required_source_header_at_target(current_best) + } + fn best_at_source(&self) -> Option { self.strategy.best_at_source() } diff --git a/relays/messages/src/message_race_loop.rs b/relays/messages/src/message_race_loop.rs index f3bf2626ef4b..41f5ede1033a 100644 --- a/relays/messages/src/message_race_loop.rs +++ b/relays/messages/src/message_race_loop.rs @@ -123,8 +123,9 @@ pub trait TargetClient { /// Type of the additional data from the target client, used by the race. type TargetNoncesData: std::fmt::Debug; - /// Ask headers relay to relay more headers from race source to race target. - async fn require_more_source_headers(&self, activate: bool); + /// Ask headers relay to relay finalized headers up to (and including) given header + /// from race source to race target. + async fn require_source_header(&self, id: P::SourceHeaderId); /// Return nonces that are known to the target client. async fn nonces( @@ -152,6 +153,8 @@ pub trait RaceStrategy: Debug { /// Should return true if nothing has to be synced. fn is_empty(&self) -> bool; + /// Return id of source header that is required to be on target to continue synchronization. + fn required_source_header_at_target(&self, current_best: &SourceHeaderId) -> Option; /// Return best nonce at source node. /// /// `Some` is returned only if we are sure that the value is greater or equal @@ -219,7 +222,6 @@ pub async fn run, TC: TargetClient

>( TargetNoncesData = TC::TargetNoncesData, >, ) -> Result<(), FailedClient> { - let mut is_strategy_empty = true; let mut progress_context = Instant::now(); let mut race_state = RaceState::default(); let mut stall_countdown = Instant::now(); @@ -307,6 +309,15 @@ pub async fn run, TC: TargetClient

>( async_std::task::sleep, || format!("Error retrieving nonces from {}", P::source_name()), ).fail_if_connection_error(FailedClient::Source)?; + + // ask for more headers if we have nonces to deliver and required headers are missing + let required_source_header_id = race_state + .best_finalized_source_header_id_at_best_target + .as_ref() + .and_then(|best|strategy.required_source_header_at_target(best)); + if let Some(required_source_header_id) = required_source_header_id { + race_target.require_source_header(required_source_header_id).await; + } }, nonces = target_best_nonces => { target_best_nonces_required = false; @@ -408,13 +419,6 @@ pub async fn run, TC: TargetClient

>( progress_context = print_race_progress::(progress_context, &strategy); - // ask for more headers if we have nonces to deliver - let prev_is_strategy_empty = is_strategy_empty; - is_strategy_empty = strategy.is_empty(); - if is_strategy_empty != prev_is_strategy_empty { - race_target.require_more_source_headers(!is_strategy_empty).await; - } - if stall_countdown.elapsed() > stall_timeout { log::warn!( target: "bridge", diff --git a/relays/messages/src/message_race_receiving.rs b/relays/messages/src/message_race_receiving.rs index 6538061965ae..4381b63591f7 100644 --- a/relays/messages/src/message_race_receiving.rs +++ b/relays/messages/src/message_race_receiving.rs @@ -159,8 +159,8 @@ where type Error = C::Error; type TargetNoncesData = (); - async fn require_more_source_headers(&self, activate: bool) { - self.client.activate_target_to_source_headers_relay(activate).await + async fn require_source_header(&self, id: TargetHeaderIdOf

) { + self.client.require_target_header_on_source(id).await } async fn nonces( diff --git a/relays/messages/src/message_race_strategy.rs b/relays/messages/src/message_race_strategy.rs index 2d8e90d433e6..7088f8d74b55 100644 --- a/relays/messages/src/message_race_strategy.rs +++ b/relays/messages/src/message_race_strategy.rs @@ -162,6 +162,15 @@ where self.source_queue.is_empty() } + fn required_source_header_at_target( + &self, + current_best: &HeaderId, + ) -> Option> { + self.source_queue + .back() + .and_then(|(h, _)| if h.0 > current_best.0 { Some(h.clone()) } else { None }) + } + fn best_at_source(&self) -> Option { let best_in_queue = self.source_queue.back().map(|(_, range)| range.end()); match (best_in_queue, self.best_target_nonce) { diff --git a/relays/messages/src/metrics.rs b/relays/messages/src/metrics.rs index a9a0ac4081f1..51a4118be858 100644 --- a/relays/messages/src/metrics.rs +++ b/relays/messages/src/metrics.rs @@ -20,7 +20,7 @@ use crate::message_lane::MessageLane; use crate::message_lane_loop::{SourceClientState, TargetClientState}; use bp_messages::MessageNonce; -use relay_utils::metrics::{register, GaugeVec, Metrics, Opts, Registry, U64}; +use relay_utils::metrics::{metric_name, register, GaugeVec, Opts, PrometheusError, Registry, U64}; /// Message lane relay metrics. /// @@ -34,25 +34,28 @@ pub struct MessageLaneLoopMetrics { lane_state_nonces: GaugeVec, } -impl Metrics for MessageLaneLoopMetrics { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.best_block_numbers.clone(), registry).map_err(|e| e.to_string())?; - register(self.lane_state_nonces.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) - } -} - -impl Default for MessageLaneLoopMetrics { - fn default() -> Self { - MessageLaneLoopMetrics { - best_block_numbers: GaugeVec::new( - Opts::new("best_block_numbers", "Best finalized block numbers"), - &["type"], - ) - .expect("metric is static and thus valid; qed"), - lane_state_nonces: GaugeVec::new(Opts::new("lane_state_nonces", "Nonces of the lane state"), &["type"]) - .expect("metric is static and thus valid; qed"), - } +impl MessageLaneLoopMetrics { + /// Create and register messages loop metrics. + pub fn new(registry: &Registry, prefix: Option<&str>) -> Result { + Ok(MessageLaneLoopMetrics { + best_block_numbers: register( + GaugeVec::new( + Opts::new( + metric_name(prefix, "best_block_numbers"), + "Best finalized block numbers", + ), + &["type"], + )?, + registry, + )?, + lane_state_nonces: register( + GaugeVec::new( + Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"), + &["type"], + )?, + registry, + )?, + }) } } diff --git a/relays/utils/src/metrics.rs b/relays/utils/src/metrics.rs index 789ff8a10850..c0eaeae337ee 100644 --- a/relays/utils/src/metrics.rs +++ b/relays/utils/src/metrics.rs @@ -18,7 +18,7 @@ pub use float_json_value::FloatJsonValueMetric; pub use global::GlobalMetrics; pub use substrate_prometheus_endpoint::{ prometheus::core::{Atomic, Collector}, - register, Counter, CounterVec, Gauge, GaugeVec, Opts, Registry, F64, U64, + register, Counter, CounterVec, Gauge, GaugeVec, Opts, PrometheusError, Registry, F64, U64, }; use async_trait::async_trait; @@ -43,13 +43,14 @@ pub struct MetricsParams { pub address: Option, /// Metrics registry. May be `Some(_)` if several components share the same endpoint. pub registry: Option, + /// Prefix that must be used in metric names. + pub metrics_prefix: Option, } /// Metrics API. -pub trait Metrics: Clone + Send + Sync + 'static { - /// Register metrics in the registry. - fn register(&self, registry: &Registry) -> Result<(), String>; -} +pub trait Metrics: Clone + Send + Sync + 'static {} + +impl Metrics for T {} /// Standalone metrics API. /// @@ -90,8 +91,21 @@ impl MetricsParams { MetricsParams { address: None, registry: None, + metrics_prefix: None, } } + + /// Do not expose metrics. + pub fn disable(mut self) -> Self { + self.address = None; + self + } + + /// Set prefix to use in metric names. + pub fn metrics_prefix(mut self, prefix: String) -> Self { + self.metrics_prefix = Some(prefix); + self + } } impl From> for MetricsParams { @@ -99,10 +113,20 @@ impl From> for MetricsParams { MetricsParams { address, registry: None, + metrics_prefix: None, } } } +/// Returns metric name optionally prefixed with given prefix. +pub fn metric_name(prefix: Option<&str>, name: &str) -> String { + if let Some(prefix) = prefix { + format!("{}_{}", prefix, name) + } else { + name.into() + } +} + /// Set value of gauge metric. /// /// If value is `Ok(None)` or `Err(_)`, metric would have default value. diff --git a/relays/utils/src/metrics/float_json_value.rs b/relays/utils/src/metrics/float_json_value.rs index 902b3e819509..d61f9cac7c22 100644 --- a/relays/utils/src/metrics/float_json_value.rs +++ b/relays/utils/src/metrics/float_json_value.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::metrics::{register, Gauge, Metrics, Registry, StandaloneMetrics, F64}; +use crate::metrics::{metric_name, register, Gauge, PrometheusError, Registry, StandaloneMetrics, F64}; use async_trait::async_trait; use std::time::Duration; @@ -32,16 +32,19 @@ pub struct FloatJsonValueMetric { impl FloatJsonValueMetric { /// Create new metric instance with given name and help. - pub fn new(url: String, json_path: String, name: String, help: String) -> Self { - FloatJsonValueMetric { + pub fn new( + registry: &Registry, + prefix: Option<&str>, + url: String, + json_path: String, + name: String, + help: String, + ) -> Result { + Ok(FloatJsonValueMetric { url, json_path, - metric: Gauge::new(name, help).expect( - "only fails if gauge options are customized;\ - we use default options;\ - qed", - ), - } + metric: register(Gauge::new(metric_name(prefix, &name), help)?, registry)?, + }) } /// Read value from HTTP service. @@ -69,13 +72,6 @@ impl FloatJsonValueMetric { } } -impl Metrics for FloatJsonValueMetric { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.metric.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) - } -} - #[async_trait] impl StandaloneMetrics for FloatJsonValueMetric { fn update_interval(&self) -> Duration { diff --git a/relays/utils/src/metrics/global.rs b/relays/utils/src/metrics/global.rs index 98c7d9a570c0..d21248051044 100644 --- a/relays/utils/src/metrics/global.rs +++ b/relays/utils/src/metrics/global.rs @@ -16,7 +16,9 @@ //! Global system-wide Prometheus metrics exposed by relays. -use crate::metrics::{register, Gauge, GaugeVec, Metrics, Opts, Registry, StandaloneMetrics, F64, U64}; +use crate::metrics::{ + metric_name, register, Gauge, GaugeVec, Opts, PrometheusError, Registry, StandaloneMetrics, F64, U64, +}; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; @@ -35,12 +37,30 @@ pub struct GlobalMetrics { process_memory_usage_bytes: Gauge, } -impl Metrics for GlobalMetrics { - fn register(&self, registry: &Registry) -> Result<(), String> { - register(self.system_average_load.clone(), registry).map_err(|e| e.to_string())?; - register(self.process_cpu_usage_percentage.clone(), registry).map_err(|e| e.to_string())?; - register(self.process_memory_usage_bytes.clone(), registry).map_err(|e| e.to_string())?; - Ok(()) +impl GlobalMetrics { + /// Create and register global metrics. + pub fn new(registry: &Registry, prefix: Option<&str>) -> Result { + Ok(GlobalMetrics { + system: Arc::new(Mutex::new(System::new_with_specifics(RefreshKind::everything()))), + system_average_load: register( + GaugeVec::new( + Opts::new(metric_name(prefix, "system_average_load"), "System load average"), + &["over"], + )?, + registry, + )?, + process_cpu_usage_percentage: register( + Gauge::new(metric_name(prefix, "process_cpu_usage_percentage"), "Process CPU usage")?, + registry, + )?, + process_memory_usage_bytes: register( + Gauge::new( + metric_name(prefix, "process_memory_usage_bytes"), + "Process memory (resident set size) usage", + )?, + registry, + )?, + }) } } @@ -89,20 +109,3 @@ impl StandaloneMetrics for GlobalMetrics { UPDATE_INTERVAL } } - -impl Default for GlobalMetrics { - fn default() -> Self { - GlobalMetrics { - system: Arc::new(Mutex::new(System::new_with_specifics(RefreshKind::everything()))), - system_average_load: GaugeVec::new(Opts::new("system_average_load", "System load average"), &["over"]) - .expect("metric is static and thus valid; qed"), - process_cpu_usage_percentage: Gauge::new("process_cpu_usage_percentage", "Process CPU usage") - .expect("metric is static and thus valid; qed"), - process_memory_usage_bytes: Gauge::new( - "process_memory_usage_bytes", - "Process memory (resident set size) usage", - ) - .expect("metric is static and thus valid; qed"), - } - } -} diff --git a/relays/utils/src/relay_loop.rs b/relays/utils/src/relay_loop.rs index 1a8d63e1dbe7..8790b0913e17 100644 --- a/relays/utils/src/relay_loop.rs +++ b/relays/utils/src/relay_loop.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::metrics::{Metrics, MetricsAddress, MetricsParams, StandaloneMetrics}; +use crate::metrics::{Metrics, MetricsAddress, MetricsParams, PrometheusError, StandaloneMetrics}; use crate::{FailedClient, MaybeConnectionError}; use async_trait::async_trait; @@ -45,9 +45,7 @@ pub fn relay_loop(source_client: SC, target_client: TC) -> Loop) -> LoopMetrics<(), (), ()> { - assert!(!prefix.is_empty(), "Metrics prefix can not be empty"); - +pub fn relay_metrics(prefix: Option, params: MetricsParams) -> LoopMetrics<(), (), ()> { LoopMetrics { relay_loop: Loop { reconnect_delay: RECONNECT_DELAY, @@ -55,9 +53,9 @@ pub fn relay_metrics(prefix: String, address: Option) -> LoopMet target_client: (), loop_metric: None, }, - address, - registry: Registry::new_custom(Some(prefix), None) - .expect("only fails if prefix is empty; prefix is not empty; qed"), + address: params.address, + registry: params.registry.unwrap_or_else(|| create_metrics_registry(prefix)), + metrics_prefix: params.metrics_prefix, loop_metric: None, } } @@ -75,6 +73,7 @@ pub struct LoopMetrics { relay_loop: Loop, address: Option, registry: Registry, + metrics_prefix: Option, loop_metric: Option, } @@ -86,11 +85,7 @@ impl Loop { } /// Start building loop metrics using given prefix. - /// - /// Panics if `prefix` is empty. - pub fn with_metrics(self, prefix: String, params: MetricsParams) -> LoopMetrics { - assert!(!prefix.is_empty(), "Metrics prefix can not be empty"); - + pub fn with_metrics(self, prefix: Option, params: MetricsParams) -> LoopMetrics { LoopMetrics { relay_loop: Loop { reconnect_delay: self.reconnect_delay, @@ -99,11 +94,8 @@ impl Loop { loop_metric: None, }, address: params.address, - registry: match params.registry { - Some(registry) => registry, - None => Registry::new_custom(Some(prefix), None) - .expect("only fails if prefix is empty; prefix is not empty; qed"), - }, + registry: params.registry.unwrap_or_else(|| create_metrics_registry(prefix)), + metrics_prefix: params.metrics_prefix, loop_metric: None, } } @@ -177,21 +169,34 @@ impl LoopMetrics { /// Add relay loop metrics. /// /// Loop metrics will be passed to the loop callback. - pub fn loop_metric(self, loop_metric: NewLM) -> Result, String> { - loop_metric.register(&self.registry)?; + pub fn loop_metric( + self, + create_metric: impl FnOnce(&Registry, Option<&str>) -> Result, + ) -> Result, String> { + let loop_metric = create_metric(&self.registry, self.metrics_prefix.as_deref()).map_err(|e| e.to_string())?; Ok(LoopMetrics { relay_loop: self.relay_loop, address: self.address, registry: self.registry, + metrics_prefix: self.metrics_prefix, loop_metric: Some(loop_metric), }) } /// Add standalone metrics. - pub fn standalone_metric(self, standalone_metrics: M) -> Result { - standalone_metrics.register(&self.registry)?; - standalone_metrics.spawn(); + pub fn standalone_metric( + self, + create_metric: impl FnOnce(&Registry, Option<&str>) -> Result, + ) -> Result { + // since standalone metrics are updating themselves, we may just ignore the fact that the same + // standalone metric is exposed by several loops && only spawn single metric + match create_metric(&self.registry, self.metrics_prefix.as_deref()) { + Ok(standalone_metrics) => standalone_metrics.spawn(), + Err(PrometheusError::AlreadyReg) => (), + Err(e) => return Err(e.to_string()), + } + Ok(self) } @@ -200,6 +205,7 @@ impl LoopMetrics { MetricsParams { address: self.address, registry: Some(self.registry), + metrics_prefix: self.metrics_prefix, } } @@ -237,3 +243,14 @@ impl LoopMetrics { }) } } + +/// Create new registry with global metrics. +fn create_metrics_registry(prefix: Option) -> Registry { + match prefix { + Some(prefix) => { + assert!(!prefix.is_empty(), "Metrics prefix can not be empty"); + Registry::new_custom(Some(prefix), None).expect("only fails if prefix is empty; prefix is not empty; qed") + } + None => Registry::new(), + } +} diff --git a/scripts/send-message-from-millau-rialto.sh b/scripts/send-message-from-millau-rialto.sh index d14b08021ee1..10fe24087fa4 100755 --- a/scripts/send-message-from-millau-rialto.sh +++ b/scripts/send-message-from-millau-rialto.sh @@ -11,7 +11,7 @@ MILLAU_PORT="${RIALTO_PORT:-9945}" case "$1" in remark) RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message millau-to-rialto \ + ./target/debug/substrate-relay send-message MillauToRialto \ --source-host localhost \ --source-port $MILLAU_PORT \ --source-signer //Alice \ @@ -22,7 +22,7 @@ case "$1" in ;; transfer) RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message millau-to-rialto \ + ./target/debug/substrate-relay send-message MillauToRialto \ --source-host localhost \ --source-port $MILLAU_PORT \ --source-signer //Alice \ diff --git a/scripts/send-message-from-rialto-millau.sh b/scripts/send-message-from-rialto-millau.sh index 10582aa6b3a7..52d19e3af883 100755 --- a/scripts/send-message-from-rialto-millau.sh +++ b/scripts/send-message-from-rialto-millau.sh @@ -11,7 +11,7 @@ RIALTO_PORT="${RIALTO_PORT:-9944}" case "$1" in remark) RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message rialto-to-millau \ + ./target/debug/substrate-relay send-message RialtoToMillau \ --source-host localhost \ --source-port $RIALTO_PORT \ --target-signer //Alice \ @@ -22,7 +22,7 @@ case "$1" in ;; transfer) RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ - ./target/debug/substrate-relay send-message rialto-to-millau \ + ./target/debug/substrate-relay send-message RialtoToMillau \ --source-host localhost \ --source-port $RIALTO_PORT \ --target-signer //Alice \ diff --git a/scripts/update-weights.sh b/scripts/update-weights.sh index 0fb4d30d2bbe..0ac773e8d7b4 100755 --- a/scripts/update-weights.sh +++ b/scripts/update-weights.sh @@ -1,9 +1,13 @@ #!/bin/sh +# +# Runtime benchmarks for the `pallet-bridge-messages` and `pallet-bridge-grandpa` pallets. +# +# Run this script from root of the repo. -# Run this script from root of the repo +set -eux -cargo run --manifest-path=bin/rialto/node/Cargo.toml --release --features=runtime-benchmarks -- benchmark \ - --chain=local \ +time cargo run --release -p rialto-bridge-node --features=runtime-benchmarks -- benchmark \ + --chain=dev \ --steps=50 \ --repeat=20 \ --pallet=pallet_bridge_messages \ @@ -13,3 +17,15 @@ cargo run --manifest-path=bin/rialto/node/Cargo.toml --release --features=runtim --heap-pages=4096 \ --output=./modules/messages/src/weights.rs \ --template=./.maintain/rialto-weight-template.hbs + +time cargo run --release -p rialto-bridge-node --features=runtime-benchmarks -- benchmark \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet=pallet_bridge_grandpa \ + --extrinsic=* \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --output=./modules/grandpa/src/weights.rs \ + --template=./.maintain/rialto-weight-template.hbs