diff --git a/.github/env b/.github/env index 2e4d5b48100d..bb61e1f4cd99 100644 --- a/.github/env +++ b/.github/env @@ -1 +1 @@ -IMAGE="docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v202407161507" +IMAGE="docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-09-11-v202409111034" diff --git a/.github/scripts/cmd/cmd.py b/.github/scripts/cmd/cmd.py index f7dd88df4bda..b5835f1f3085 100755 --- a/.github/scripts/cmd/cmd.py +++ b/.github/scripts/cmd/cmd.py @@ -100,7 +100,7 @@ def main(): # loop over remaining runtimes to collect available pallets for runtime in runtimesMatrix.values(): - os.system(f"forklift cargo build -p {runtime['package']} --profile {profile} --features runtime-benchmarks") + os.system(f"forklift cargo build -p {runtime['package']} --profile {profile} --features={runtime['bench_features']}") print(f'-- listing pallets for benchmark for {runtime["name"]}') wasm_file = f"target/{profile}/wbuild/{runtime['package']}/{runtime['package'].replace('-', '_')}.wasm" output = os.popen( diff --git a/.github/scripts/cmd/test_cmd.py b/.github/scripts/cmd/test_cmd.py index a2f29b075dae..f4e70903347f 100644 --- a/.github/scripts/cmd/test_cmd.py +++ b/.github/scripts/cmd/test_cmd.py @@ -7,10 +7,10 @@ # Mock data for runtimes-matrix.json mock_runtimes_matrix = [ - {"name": "dev", "package": "kitchensink-runtime", "path": "substrate/frame", "header": "substrate/HEADER-APACHE2", "template": "substrate/.maintain/frame-weight-template.hbs"}, - {"name": "westend", "package": "westend-runtime", "path": "polkadot/runtime/westend", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs"}, - {"name": "rococo", "package": "rococo-runtime", "path": "polkadot/runtime/rococo", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs"}, - {"name": "asset-hub-westend", "package": "asset-hub-westend-runtime", "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", "header": "cumulus/file_header.txt", "template": "cumulus/templates/xcm-bench-template.hbs"}, + {"name": "dev", "package": "kitchensink-runtime", "path": "substrate/frame", "header": "substrate/HEADER-APACHE2", "template": "substrate/.maintain/frame-weight-template.hbs", "bench_features": "runtime-benchmarks,riscv"}, + {"name": "westend", "package": "westend-runtime", "path": "polkadot/runtime/westend", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "bench_features": "runtime-benchmarks"}, + {"name": "rococo", "package": "rococo-runtime", "path": "polkadot/runtime/rococo", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "bench_features": "runtime-benchmarks"}, + {"name": "asset-hub-westend", "package": "asset-hub-westend-runtime", "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", "header": "cumulus/file_header.txt", "template": "cumulus/templates/xcm-bench-template.hbs", "bench_features": "runtime-benchmarks"}, ] def get_mock_bench_output(runtime, pallets, output_path, header, template = None): @@ -84,10 +84,10 @@ def test_bench_command_normal_execution_all_runtimes(self): expected_calls = [ # Build calls - call("forklift cargo build -p kitchensink-runtime --profile release --features runtime-benchmarks"), - call("forklift cargo build -p westend-runtime --profile release --features runtime-benchmarks"), - call("forklift cargo build -p rococo-runtime --profile release --features runtime-benchmarks"), - call("forklift cargo build -p asset-hub-westend-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p kitchensink-runtime --profile release --features=runtime-benchmarks,riscv"), + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), + call("forklift cargo build -p rococo-runtime --profile release --features=runtime-benchmarks"), + call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), call(get_mock_bench_output('kitchensink', 'pallet_balances', './substrate/frame/balances/src/weights.rs', os.path.abspath('substrate/HEADER-APACHE2'), "substrate/.maintain/frame-weight-template.hbs")), call(get_mock_bench_output('westend', 'pallet_balances', './polkadot/runtime/westend/src/weights', os.path.abspath('polkadot/file_header.txt'))), @@ -118,7 +118,7 @@ def test_bench_command_normal_execution(self): expected_calls = [ # Build calls - call("forklift cargo build -p westend-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output('westend', 'pallet_balances', './polkadot/runtime/westend/src/weights', header_path)), @@ -149,7 +149,7 @@ def test_bench_command_normal_execution_xcm(self): expected_calls = [ # Build calls - call("forklift cargo build -p westend-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output( @@ -185,8 +185,8 @@ def test_bench_command_two_runtimes_two_pallets(self): expected_calls = [ # Build calls - call("forklift cargo build -p westend-runtime --profile release --features runtime-benchmarks"), - call("forklift cargo build -p rococo-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), + call("forklift cargo build -p rococo-runtime --profile release --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output('westend', 'pallet_staking', './polkadot/runtime/westend/src/weights', header_path)), call(get_mock_bench_output('westend', 'pallet_balances', './polkadot/runtime/westend/src/weights', header_path)), @@ -220,7 +220,7 @@ def test_bench_command_one_dev_runtime(self): expected_calls = [ # Build calls - call("forklift cargo build -p kitchensink-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p kitchensink-runtime --profile release --features=runtime-benchmarks,riscv"), # Westend runtime calls call(get_mock_bench_output( 'kitchensink', @@ -254,7 +254,7 @@ def test_bench_command_one_cumulus_runtime(self): expected_calls = [ # Build calls - call("forklift cargo build -p asset-hub-westend-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), # Asset-hub-westend runtime calls call(get_mock_bench_output( 'asset-hub-westend', @@ -288,7 +288,7 @@ def test_bench_command_one_cumulus_runtime_xcm(self): expected_calls = [ # Build calls - call("forklift cargo build -p asset-hub-westend-runtime --profile release --features runtime-benchmarks"), + call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), # Asset-hub-westend runtime calls call(get_mock_bench_output( 'asset-hub-westend', diff --git a/.github/scripts/generate-prdoc.py b/.github/scripts/generate-prdoc.py index d3b6b523ecfd..f05d517a5802 100644 --- a/.github/scripts/generate-prdoc.py +++ b/.github/scripts/generate-prdoc.py @@ -67,7 +67,6 @@ def create_prdoc(pr, audience, title, description, patch, bump, force): # Go up until we find a Cargo.toml p = os.path.join(workspace.path, p) while not os.path.exists(os.path.join(p, "Cargo.toml")): - print(f"Could not find Cargo.toml in {p}") if p == '/': exit(1) p = os.path.dirname(p) @@ -76,7 +75,6 @@ def create_prdoc(pr, audience, title, description, patch, bump, force): manifest = toml.load(f) if not "package" in manifest: - print(f"File was not in any crate: {p}") continue crate_name = manifest["package"]["name"] @@ -85,8 +83,6 @@ def create_prdoc(pr, audience, title, description, patch, bump, force): else: print(f"Skipping unpublished crate: {crate_name}") - print(f"Modified crates: {modified_crates.keys()}") - for crate_name in modified_crates.keys(): entry = { "name": crate_name } @@ -137,4 +133,4 @@ def main(args): if __name__ == "__main__": args = setup_parser().parse_args() - main(args) \ No newline at end of file + main(args) diff --git a/.github/workflows/check-runtime-migration.yml b/.github/workflows/check-runtime-migration.yml index 8185cf171aef..8d30e752b115 100644 --- a/.github/workflows/check-runtime-migration.yml +++ b/.github/workflows/check-runtime-migration.yml @@ -17,13 +17,13 @@ concurrency: cancel-in-progress: true jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml # More info can be found here: https://github.com/paritytech/polkadot/pull/5865 check-runtime-migration: runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} # We need to set this to rather long to allow the snapshot to be created, but the average time # should be much lower. timeout-minutes: 60 diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index f765d79254c8..0793c31dbb87 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -15,14 +15,13 @@ concurrency: permissions: {} jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml cargo-clippy: runs-on: ${{ needs.preflight.outputs.RUNNER }} needs: [preflight] - # if: ${{ needs.preflight.outputs.changes_rust }} + if: ${{ needs.preflight.outputs.changes_rust }} timeout-minutes: 40 container: image: ${{ needs.preflight.outputs.IMAGE }} @@ -33,12 +32,12 @@ jobs: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: script run: | - forklift cargo clippy --all-targets --locked --workspace - forklift cargo clippy --all-targets --all-features --locked --workspace + forklift cargo clippy --all-targets --locked --workspace --quiet + forklift cargo clippy --all-targets --all-features --locked --workspace --quiet check-try-runtime: runs-on: ${{ needs.preflight.outputs.RUNNER }} needs: [preflight] - # if: ${{ needs.preflight.outputs.changes_rust }} + if: ${{ needs.preflight.outputs.changes_rust }} timeout-minutes: 40 container: image: ${{ needs.preflight.outputs.IMAGE }} @@ -46,18 +45,18 @@ jobs: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: script run: | - forklift cargo check --locked --all --features try-runtime + forklift cargo check --locked --all --features try-runtime --quiet # this is taken from cumulus # Check that parachain-template will compile with `try-runtime` feature flag. forklift cargo check --locked -p parachain-template-node --features try-runtime # add after https://github.com/paritytech/substrate/pull/14502 is merged # experimental code may rely on try-runtime and vice-versa - forklift cargo check --locked --all --features try-runtime,experimental + forklift cargo check --locked --all --features try-runtime,experimental --quiet # check-core-crypto-features works fast without forklift check-core-crypto-features: runs-on: ${{ needs.preflight.outputs.RUNNER }} needs: [preflight] - # if: ${{ needs.preflight.outputs.changes_rust }} + if: ${{ needs.preflight.outputs.changes_rust }} timeout-minutes: 30 container: image: ${{ needs.preflight.outputs.IMAGE }} diff --git a/.github/workflows/cmd.yml b/.github/workflows/cmd.yml index 5498beb50ccb..e416b1202691 100644 --- a/.github/workflows/cmd.yml +++ b/.github/workflows/cmd.yml @@ -336,7 +336,9 @@ jobs: - name: Install dependencies for bench if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') - run: cargo install subweight frame-omni-bencher --locked + run: | + cargo install subweight --locked + cargo install --path substrate/utils/frame/omni-bencher --locked - name: Run cmd id: cmd diff --git a/.github/workflows/command-prdoc.yml b/.github/workflows/command-prdoc.yml index aa9de9474a7b..2154c8a987f2 100644 --- a/.github/workflows/command-prdoc.yml +++ b/.github/workflows/command-prdoc.yml @@ -28,7 +28,7 @@ on: - "Runtime Dev" - "Runtime User" - "Node Dev" - - "Node User" + - "Node Operator" overwrite: type: choice description: Overwrite existing PrDoc diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 514bac3973bf..44ad9613997a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,15 +9,17 @@ on: merge_group: concurrency: - group: ${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: preflight: + if: contains(github.event.label.name, 'GHA-migration') uses: ./.github/workflows/reusable-preflight.yml test-rustdoc: - runs-on: arc-runners-polkadot-sdk-beefy + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} needs: [preflight] container: image: ${{ needs.preflight.outputs.IMAGE }} @@ -38,7 +40,8 @@ jobs: RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" build-rustdoc: - runs-on: arc-runners-polkadot-sdk-beefy + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} needs: [preflight, test-rustdoc] container: image: ${{ needs.preflight.outputs.IMAGE }} diff --git a/.github/workflows/runtimes-matrix.json b/.github/workflows/runtimes-matrix.json index 102437876daf..50fa44b1b073 100644 --- a/.github/workflows/runtimes-matrix.json +++ b/.github/workflows/runtimes-matrix.json @@ -5,6 +5,7 @@ "path": "substrate/frame", "header": "substrate/HEADER-APACHE2", "template": "substrate/.maintain/frame-weight-template.hbs", + "bench_features": "runtime-benchmarks,riscv", "uri": null, "is_relay": false }, @@ -15,6 +16,7 @@ "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "uri": "wss://try-runtime-westend.polkadot.io:443", + "bench_features": "runtime-benchmarks", "is_relay": true }, { @@ -24,6 +26,7 @@ "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "uri": "wss://try-runtime-rococo.polkadot.io:443", + "bench_features": "runtime-benchmarks", "is_relay": true }, { @@ -32,6 +35,7 @@ "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", "header": "cumulus/file_header.txt", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", "uri": "wss://westend-asset-hub-rpc.polkadot.io:443", "is_relay": false }, @@ -40,6 +44,7 @@ "package": "asset-hub-rococo-runtime", "path": "cumulus/parachains/runtimes/assets/asset-hub-rococo", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://rococo-asset-hub-rpc.polkadot.io:443", "is_relay": false @@ -47,8 +52,9 @@ { "name": "bridge-hub-rococo", "package": "bridge-hub-rococo-runtime", - "path": "cumulus/parachains/runtimes/bridges/bridge-hub-rococo", + "path": "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://rococo-bridge-hub-rpc.polkadot.io:443", "is_relay": false @@ -56,8 +62,9 @@ { "name": "bridge-hub-westend", "package": "bridge-hub-rococo-runtime", - "path": "cumulus/parachains/runtimes/bridges/bridge-hub-westend", + "path": "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://westend-bridge-hub-rpc.polkadot.io:443", "is_relay": false @@ -67,6 +74,7 @@ "package": "collectives-westend-runtime", "path": "cumulus/parachains/runtimes/collectives/collectives-westend", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://westend-collectives-rpc.polkadot.io:443" }, @@ -75,6 +83,7 @@ "package": "contracts-rococo-runtime", "path": "cumulus/parachains/runtimes/contracts/contracts-rococo", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://rococo-contracts-rpc.polkadot.io:443", "is_relay": false @@ -84,6 +93,7 @@ "package": "coretime-rococo-runtime", "path": "cumulus/parachains/runtimes/coretime/coretime-rococo", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://rococo-coretime-rpc.polkadot.io:443", "is_relay": false @@ -93,6 +103,7 @@ "package": "coretime-westend-runtime", "path": "cumulus/parachains/runtimes/coretime/coretime-westend", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://westend-coretime-rpc.polkadot.io:443", "is_relay": false @@ -102,6 +113,7 @@ "package": "glutton-westend-runtime", "path": "cumulus/parachains/runtimes/gluttons/glutton-westend", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": null, "is_relay": false @@ -111,6 +123,7 @@ "package": "people-rococo-runtime", "path": "cumulus/parachains/runtimes/people/people-rococo", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://rococo-people-rpc.polkadot.io:443", "is_relay": false @@ -120,6 +133,7 @@ "package": "people-westend-runtime", "path": "cumulus/parachains/runtimes/people/people-westend", "header": "cumulus/file_header.txt", + "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", "uri": "wss://westend-people-rpc.polkadot.io:443", "is_relay": false diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/subsystem-benchmarks.yml index 3c0eaf30e45f..210714d847ff 100644 --- a/.github/workflows/subsystem-benchmarks.yml +++ b/.github/workflows/subsystem-benchmarks.yml @@ -22,7 +22,7 @@ jobs: build: timeout-minutes: 80 needs: [preflight] - runs-on: ${{ needs.preflight.outputs.RUNNER_BENCHMARK }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} container: image: ${{ needs.preflight.outputs.IMAGE }} strategy: diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml index 994f1c9b78ea..599edd8e69a1 100644 --- a/.github/workflows/tests-linux-stable.yml +++ b/.github/workflows/tests-linux-stable.yml @@ -13,13 +13,12 @@ concurrency: cancel-in-progress: true jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml test-linux-stable-int: needs: [preflight] - # if: ${{ needs.preflight.outputs.changes_rust }} + if: ${{ needs.preflight.outputs.changes_rust }} runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: @@ -40,7 +39,7 @@ jobs: # https://github.com/paritytech/ci_cd/issues/864 test-linux-stable-runtime-benchmarks: needs: [preflight] - # if: ${{ needs.preflight.outputs.changes_rust }} + if: ${{ needs.preflight.outputs.changes_rust }} runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: @@ -54,11 +53,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script - run: forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + run: forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet --cargo-quiet test-linux-stable: needs: [preflight] - # if: ${{ needs.preflight.outputs.changes_rust }} + if: ${{ needs.preflight.outputs.changes_rust }} runs-on: ${{ matrix.runners }} timeout-minutes: 60 strategy: @@ -91,12 +90,13 @@ jobs: --locked \ --release \ --no-fail-fast \ + --cargo-quiet \ --features try-runtime,experimental,riscv,ci-only-tests \ --partition count:${{ matrix.partition }} # run runtime-api tests with `enable-staging-api` feature on the 1st node - name: runtime-api tests if: ${{ matrix.partition == '1/3' }} - run: forklift cargo nextest run -p sp-api-test --features enable-staging-api + run: forklift cargo nextest run -p sp-api-test --features enable-staging-api --cargo-quiet confirm-required-jobs-passed: runs-on: ubuntu-latest diff --git a/.github/workflows/tests-misc.yml b/.github/workflows/tests-misc.yml index 90162adc2258..45ed4ebdc6cb 100644 --- a/.github/workflows/tests-misc.yml +++ b/.github/workflows/tests-misc.yml @@ -22,6 +22,7 @@ jobs: test-full-crypto-feature: needs: [preflight] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} timeout-minutes: 60 container: image: ${{ needs.preflight.outputs.IMAGE }} @@ -46,6 +47,7 @@ jobs: # into one job needs: [preflight, test-full-crypto-feature] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} env: @@ -67,6 +69,7 @@ jobs: timeout-minutes: 60 needs: [preflight] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} env: @@ -74,8 +77,7 @@ jobs: # but still want to have debug assertions. RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" + SKIP_WASM_BUILD: 1 # Ensure we run the UI tests. RUN_UI_TESTS: 1 steps: @@ -83,18 +85,20 @@ jobs: uses: actions/checkout@v4 - name: script run: | - forklift cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental - forklift cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental - forklift cargo test --locked -q --profile testnet -p xcm-procedural - forklift cargo test --locked -q --profile testnet -p frame-election-provider-solution-type - forklift cargo test --locked -q --profile testnet -p sp-api-test + cargo version + forklift cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental ui + forklift cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental ui + forklift cargo test --locked -q --profile testnet -p xcm-procedural ui + forklift cargo test --locked -q --profile testnet -p frame-election-provider-solution-type ui + forklift cargo test --locked -q --profile testnet -p sp-api-test ui # There is multiple version of sp-runtime-interface in the repo. So we point to the manifest. - forklift cargo test --locked -q --profile testnet --manifest-path substrate/primitives/runtime-interface/Cargo.toml + forklift cargo test --locked -q --profile testnet --manifest-path substrate/primitives/runtime-interface/Cargo.toml ui test-deterministic-wasm: timeout-minutes: 20 needs: [preflight, test-frame-examples-compile-to-wasm] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} env: @@ -194,6 +198,7 @@ jobs: needs: [preflight] timeout-minutes: 30 runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} steps: @@ -226,6 +231,7 @@ jobs: timeout-minutes: 20 needs: [preflight, test-node-metrics] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} steps: @@ -241,6 +247,7 @@ jobs: timeout-minutes: 20 needs: [preflight, check-tracing] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} steps: @@ -251,50 +258,52 @@ jobs: run: | forklift cargo build --locked -p westend-runtime --features metadata-hash - cargo-hfuzz: - timeout-minutes: 20 - needs: [preflight, check-metadata-hash] - runs-on: ${{ needs.preflight.outputs.RUNNER }} - container: - image: ${{ needs.preflight.outputs.IMAGE }} - env: - # max 10s per iteration, 60s per file - HFUZZ_RUN_ARGS: | - --exit_upon_crash - --exit_code_upon_crash 1 - --timeout 10 - --run_time 60 - - # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: - # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian - # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr - # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling absolute CARGO_TARGET_DIR - HFUZZ_BUILD_ARGS: | - --config=patch.crates-io.honggfuzz.git="https://github.com/altaua/honggfuzz-rs" - --config=patch.crates-io.honggfuzz.rev="205f7c8c059a0d98fe1cb912cdac84f324cb6981" - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Run honggfuzz - run: | - cd substrate/primitives/arithmetic/fuzzer - forklift cargo hfuzz build - for target in $(cargo read-manifest | jq -r '.targets | .[] | .name'); - do - forklift cargo hfuzz run "$target" || { printf "fuzzing failure for %s\n" "$target"; exit 1; }; - done - - - name: Upload artifacts - uses: actions/upload-artifact@v4.3.6 - with: - path: substrate/primitives/arithmetic/fuzzer/hfuzz_workspace/ - name: hfuzz-${{ github.sha }} + # disabled until https://github.com/paritytech/polkadot-sdk/issues/5812 is resolved + # cargo-hfuzz: + # timeout-minutes: 20 + # needs: [preflight, check-metadata-hash] + # runs-on: ${{ needs.preflight.outputs.RUNNER }} + # container: + # image: ${{ needs.preflight.outputs.IMAGE }} + # env: + # # max 10s per iteration, 60s per file + # HFUZZ_RUN_ARGS: | + # --exit_upon_crash + # --exit_code_upon_crash 1 + # --timeout 10 + # --run_time 60 + + # # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: + # # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian + # # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr + # # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling absolute CARGO_TARGET_DIR + # HFUZZ_BUILD_ARGS: | + # --config=patch.crates-io.honggfuzz.git="https://github.com/altaua/honggfuzz-rs" + # --config=patch.crates-io.honggfuzz.rev="205f7c8c059a0d98fe1cb912cdac84f324cb6981" + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Run honggfuzz + # run: | + # cd substrate/primitives/arithmetic/fuzzer + # forklift cargo hfuzz build + # for target in $(cargo read-manifest | jq -r '.targets | .[] | .name'); + # do + # forklift cargo hfuzz run "$target" || { printf "fuzzing failure for %s\n" "$target"; exit 1; }; + # done + + # - name: Upload artifacts + # uses: actions/upload-artifact@v4.3.6 + # with: + # path: substrate/primitives/arithmetic/fuzzer/hfuzz_workspace/ + # name: hfuzz-${{ github.sha }} cargo-check-each-crate: timeout-minutes: 140 needs: [preflight] runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} container: image: ${{ needs.preflight.outputs.IMAGE }} env: @@ -322,6 +331,7 @@ jobs: timeout-minutes: 30 needs: [preflight] runs-on: ${{ needs.preflight.outputs.RUNNER_MACOS }} + if: ${{ needs.preflight.outputs.changes_rust }} env: SKIP_WASM_BUILD: 1 steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1132c2ca4dd5..6d6e393b0410 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,21 +5,20 @@ on: branches: - master pull_request: - types: [ opened, synchronize, reopened, ready_for_review ] + types: [opened, synchronize, reopened, ready_for_review] merge_group: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml # This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. quick-benchmarks: - needs: [ preflight ] - # if: ${{ needs.preflight.outputs.changes_rust }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: @@ -33,12 +32,12 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script - run: forklift cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 --quiet + run: forklift cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks --quiet -- benchmark pallet --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 --quiet # cf https://github.com/paritytech/polkadot-sdk/issues/1652 test-syscalls: - needs: [ preflight ] - # if: ${{ needs.preflight.outputs.changes_rust }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: @@ -52,7 +51,7 @@ jobs: - name: script id: test run: | - forklift cargo build --locked --profile production --target x86_64-unknown-linux-musl --bin polkadot-execute-worker --bin polkadot-prepare-worker + forklift cargo build --locked --profile production --target x86_64-unknown-linux-musl --bin polkadot-execute-worker --bin polkadot-prepare-worker --quiet cd polkadot/scripts/list-syscalls ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-execute-worker --only-used-syscalls | diff -u execute-worker-syscalls - ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-prepare-worker --only-used-syscalls | diff -u prepare-worker-syscalls - @@ -61,10 +60,9 @@ jobs: run: | echo "The x86_64 syscalls used by the worker binaries have changed. Please review if this is expected and update polkadot/scripts/list-syscalls/*-worker-syscalls as needed." >> $GITHUB_STEP_SUMMARY - cargo-check-all-benches: - needs: [ preflight ] - # if: ${{ needs.preflight.outputs.changes_rust }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: @@ -75,4 +73,4 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script - run: forklift cargo check --all --benches + run: forklift cargo check --all --benches --quiet diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c6b3928b46e..dbc5dafeb0ae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,8 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + # CI_IMAGE: !reference [ .ci-unified, variables, CI_IMAGE ] + CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-09-11-v202409111034" # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 00a0aa2c9771..0252620cd0f3 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -110,6 +110,31 @@ test-linux-stable-codecov: codecovcli -v do-upload -f target/coverage/result/report-${CI_NODE_INDEX}.lcov --disable-search -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --git-service github; fi +# some tests do not run with `try-runtime` feature enabled +# https://github.com/paritytech/polkadot-sdk/pull/4251#discussion_r1624282143 +# Move to github after https://github.com/paritytech/ci_cd/issues/1056 is fixed +test-linux-stable-no-try-runtime: + stage: test + extends: + - .docker-env + - .common-refs + - .run-immediately + - .pipeline-stopper-artifacts + variables: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + script: + - > + time cargo nextest run \ + --workspace \ + --locked \ + --release \ + --no-fail-fast \ + --cargo-quiet \ + --features experimental,riscv,ci-only-tests + test-doc: stage: test extends: diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index c17366dbe4c2..f793271d8f4d 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,7 +1,7 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.105" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.111" PUSHGATEWAY_URL: "http://zombienet-prometheus-pushgateway.managed-monitoring:9091/metrics/job/zombie-metrics" DEBUG: "zombie,zombie::network-node,zombie::kube::client::logs" ZOMBIE_PROVIDER: "k8s" diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index 6e2b53fae619..fc88e1ff1450 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -46,7 +46,9 @@ paths: - ./zombienet-logs allow_failure: true - retry: 2 + retry: + max: 1 + when: runner_system_failure tags: - zombienet-polkadot-integration-test diff --git a/.gitlab/pipeline/zombienet/parachain-template.yml b/.gitlab/pipeline/zombienet/parachain-template.yml index 6ed63182ec53..896ba7913be7 100644 --- a/.gitlab/pipeline/zombienet/parachain-template.yml +++ b/.gitlab/pipeline/zombienet/parachain-template.yml @@ -28,7 +28,9 @@ after_script: - mkdir -p ./zombienet-logs - cp /tmp/zombie*/*/*.log ./zombienet-logs/ - retry: 2 + retry: + max: 1 + when: runner_system_failure timeout: 20m tags: - linux-docker diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 93fc4bbb578a..0da95f224cfc 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -72,7 +72,9 @@ after_script: - mkdir -p ./zombienet-logs - cp /tmp/zombie*/logs/* ./zombienet-logs/ - retry: 2 + retry: + max: 1 + when: runner_system_failure tags: - zombienet-polkadot-integration-test @@ -108,7 +110,7 @@ zombienet-polkadot-functional-0004-parachains-disputes-garbage-candidate: --local-dir="${LOCAL_DIR}/functional" --test="0004-parachains-garbage-candidate.zndsl" -zombienet-polkadot-functional-0005-parachains-disputes-past-session: +.zombienet-polkadot-functional-0005-parachains-disputes-past-session: extends: - .zombienet-polkadot-common script: @@ -223,6 +225,14 @@ zombienet-polkadot-functional-0015-coretime-shared-core: --local-dir="${LOCAL_DIR}/functional" --test="0015-coretime-shared-core.zndsl" +zombienet-polkadot-functional-0016-approval-voting-parallel: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0016-approval-voting-parallel.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common @@ -343,7 +353,7 @@ zombienet-polkadot-malus-0001-dispute-valid: --local-dir="${LOCAL_DIR}/integrationtests" --test="0001-dispute-valid-block.zndsl" -zombienet-polkadot-coretime-revenue: +.zombienet-polkadot-coretime-revenue: extends: - .zombienet-polkadot-common needs: diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 2013ffd571cf..d4ffa34f3395 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -38,7 +38,9 @@ after_script: - mkdir -p ./zombienet-logs - cp /tmp/zombie*/logs/* ./zombienet-logs/ - retry: 2 + retry: + max: 1 + when: runner_system_failure tags: - zombienet-polkadot-integration-test diff --git a/Cargo.lock b/Cargo.lock index 18517f94788a..a572c37a4060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,7 +168,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", "syn-solidity", "tiny-keccak", ] @@ -295,7 +295,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -753,7 +753,7 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", "synstructure 0.13.1", ] @@ -776,7 +776,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1380,7 +1380,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1397,7 +1397,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1612,7 +1612,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2188,12 +2188,14 @@ dependencies = [ name = "bridge-hub-rococo-emulated-chain" version = "0.0.0" dependencies = [ + "bp-messages", "bridge-hub-common", "bridge-hub-rococo-runtime", "emulated-integration-tests-common", "frame-support", "parachains-common", "sp-core 28.0.0", + "staging-xcm", "testnet-parachains-constants", ] @@ -2357,6 +2359,7 @@ dependencies = [ "pallet-bridge-relayers", "pallet-timestamp", "pallet-utility", + "pallet-xcm", "pallet-xcm-bridge-hub", "parachains-common", "parachains-runtimes-test-utils", @@ -2375,12 +2378,14 @@ dependencies = [ name = "bridge-hub-westend-emulated-chain" version = "0.0.0" dependencies = [ + "bp-messages", "bridge-hub-common", "bridge-hub-westend-runtime", "emulated-integration-tests-common", "frame-support", "parachains-common", "sp-core 28.0.0", + "staging-xcm", "testnet-parachains-constants", ] @@ -3026,7 +3031,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4348,7 +4353,6 @@ dependencies = [ "futures", "hex-literal", "impl-trait-for-tuples", - "lazy_static", "log", "pallet-message-queue", "parity-scale-codec", @@ -4384,7 +4388,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4936,7 +4940,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4976,7 +4980,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scratch", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4993,7 +4997,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5041,7 +5045,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5063,7 +5067,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5180,7 +5184,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5191,7 +5195,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5202,7 +5206,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5310,7 +5314,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5371,7 +5375,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "regex", - "syn 2.0.77", + "syn 2.0.79", "termcolor", "toml 0.8.12", "walkdir", @@ -5602,7 +5606,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5622,7 +5626,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5633,7 +5637,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5848,7 +5852,7 @@ dependencies = [ "prettyplease", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5920,7 +5924,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6205,7 +6209,6 @@ dependencies = [ "gethostname", "handlebars", "itertools 0.11.0", - "lazy_static", "linked-hash-map", "log", "parity-scale-codec", @@ -6264,7 +6267,7 @@ dependencies = [ "quote 1.0.37", "scale-info", "sp-arithmetic 23.0.0", - "syn 2.0.77", + "syn 2.0.79", "trybuild", ] @@ -6478,7 +6481,7 @@ dependencies = [ "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "static_assertions", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6489,7 +6492,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6498,7 +6501,7 @@ version = "11.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6754,7 +6757,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -8212,7 +8215,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -8944,7 +8947,7 @@ dependencies = [ "proc-macro-warning 0.4.2", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -9361,7 +9364,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -9375,7 +9378,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -9386,7 +9389,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -9397,7 +9400,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -9560,6 +9563,7 @@ dependencies = [ "parking_lot 0.12.3", "relay-utils", "sp-arithmetic 23.0.0", + "sp-core 28.0.0", ] [[package]] @@ -9742,7 +9746,7 @@ dependencies = [ "cfg-if", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -10113,7 +10117,6 @@ dependencies = [ "kitchensink-runtime", "kvdb", "kvdb-rocksdb", - "lazy_static", "log", "node-primitives", "node-testing", @@ -10347,7 +10350,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -10523,7 +10526,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -11303,7 +11306,7 @@ version = "18.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -11834,6 +11837,7 @@ dependencies = [ name = "pallet-migrations" version = "1.0.0" dependencies = [ + "cfg-if", "docify", "frame-benchmarking", "frame-executive", @@ -12406,7 +12410,7 @@ version = "0.1.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -12651,7 +12655,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-runtime 31.0.1", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -13758,7 +13762,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -13799,7 +13803,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -13895,7 +13899,6 @@ dependencies = [ "futures-timer", "itertools 0.11.0", "log", - "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -14098,7 +14101,6 @@ dependencies = [ "futures", "futures-timer", "indexmap 2.2.3", - "lazy_static", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -14142,7 +14144,6 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "lazy_static", "parking_lot 0.12.3", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -14233,7 +14234,6 @@ dependencies = [ "merlin", "parity-scale-codec", "parking_lot 0.12.3", - "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -14261,6 +14261,49 @@ dependencies = [ "tracing-gum", ] +[[package]] +name = "polkadot-node-core-approval-voting-parallel" +version = "7.0.0" +dependencies = [ + "assert_matches", + "async-trait", + "futures", + "futures-timer", + "itertools 0.11.0", + "kvdb-memorydb", + "log", + "parking_lot 0.12.3", + "polkadot-approval-distribution", + "polkadot-node-core-approval-voting", + "polkadot-node-jaeger", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-primitives", + "polkadot-primitives-test-helpers", + "polkadot-subsystem-bench", + "rand", + "rand_chacha", + "rand_core 0.6.4", + "sc-keystore", + "schnorrkel 0.11.4", + "sp-application-crypto 30.0.0", + "sp-consensus", + "sp-consensus-babe", + "sp-consensus-slots", + "sp-core 28.0.0", + "sp-keyring", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", + "thiserror", + "tracing-gum", +] + [[package]] name = "polkadot-node-core-av-store" version = "7.0.0" @@ -14648,7 +14691,6 @@ dependencies = [ name = "polkadot-node-jaeger" version = "7.0.0" dependencies = [ - "lazy_static", "log", "mick-jaeger", "parity-scale-codec", @@ -14815,7 +14857,6 @@ dependencies = [ "kvdb", "kvdb-memorydb", "kvdb-shared-tests", - "lazy_static", "log", "parity-db", "parity-scale-codec", @@ -14876,6 +14917,7 @@ version = "4.0.0" dependencies = [ "asset-hub-rococo-runtime", "asset-hub-westend-runtime", + "bp-messages", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", "collectives-westend-runtime", @@ -15389,6 +15431,7 @@ dependencies = [ "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", @@ -15728,6 +15771,7 @@ dependencies = [ "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", @@ -15884,6 +15928,7 @@ dependencies = [ "polkadot-availability-recovery", "polkadot-erasure-coding", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-chain-api", "polkadot-node-metrics", @@ -16236,7 +16281,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16248,7 +16293,7 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16260,7 +16305,7 @@ dependencies = [ "polkavm-common 0.11.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16270,7 +16315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16280,7 +16325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16290,7 +16335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf952e05bc5ce7d81293bae18cb44c271c78615b201d75e983cdcc40d5c6ef1" dependencies = [ "polkavm-derive-impl 0.11.0", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16507,7 +16552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2 1.0.86", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16598,7 +16643,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16609,7 +16654,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16690,7 +16735,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16772,7 +16817,7 @@ dependencies = [ "prost 0.12.6", "prost-types 0.12.4", "regex", - "syn 2.0.77", + "syn 2.0.79", "tempfile", ] @@ -16793,7 +16838,7 @@ dependencies = [ "prost 0.13.2", "prost-types 0.13.2", "regex", - "syn 2.0.77", + "syn 2.0.79", "tempfile", ] @@ -16820,7 +16865,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -16833,7 +16878,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -17302,7 +17347,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -17901,7 +17946,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.77", + "syn 2.0.79", "unicode-ident", ] @@ -18429,7 +18474,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -19380,7 +19425,6 @@ dependencies = [ "futures-timer", "hyper 0.14.29", "hyper-rustls 0.24.2", - "lazy_static", "log", "num_cpus", "once_cell", @@ -19763,7 +19807,6 @@ dependencies = [ "console", "criterion", "is-terminal", - "lazy_static", "libc", "log", "parity-scale-codec", @@ -19792,7 +19835,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -19852,7 +19895,6 @@ dependencies = [ "async-channel 1.9.0", "futures", "futures-timer", - "lazy_static", "log", "parking_lot 0.12.3", "prometheus", @@ -19972,7 +20014,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scale-info", - "syn 2.0.77", + "syn 2.0.79", "thiserror", ] @@ -20322,7 +20364,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -20424,7 +20466,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -21428,7 +21470,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -21443,7 +21485,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -21700,7 +21742,6 @@ name = "sp-consensus-beefy" version = "13.0.0" dependencies = [ "array-bytes", - "lazy_static", "parity-scale-codec", "scale-info", "serde", @@ -21786,7 +21827,6 @@ dependencies = [ "impl-serde", "itertools 0.11.0", "k256", - "lazy_static", "libsecp256k1", "log", "merlin", @@ -21962,7 +22002,6 @@ dependencies = [ name = "sp-core-fuzz" version = "0.0.0" dependencies = [ - "lazy_static", "libfuzzer-sys", "regex", "sp-core 28.0.0", @@ -22056,7 +22095,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22067,7 +22106,7 @@ checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22085,7 +22124,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22094,7 +22133,7 @@ version = "14.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22105,7 +22144,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22442,7 +22481,6 @@ name = "sp-panic-handler" version = "13.0.0" dependencies = [ "backtrace", - "lazy_static", "regex", ] @@ -22471,6 +22509,7 @@ dependencies = [ name = "sp-runtime" version = "31.0.1" dependencies = [ + "binary-merkle-tree", "docify", "either", "hash256-std-hasher", @@ -22666,7 +22705,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22678,7 +22717,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -22692,7 +22731,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -23033,7 +23072,6 @@ dependencies = [ "array-bytes", "criterion", "hash-db", - "lazy_static", "memory-db", "nohash-hasher", "parity-scale-codec", @@ -23168,7 +23206,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-version 29.0.0", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -23180,7 +23218,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -23645,7 +23683,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -23658,7 +23696,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -24038,6 +24076,7 @@ dependencies = [ "parity-wasm", "polkavm-linker 0.9.2", "sc-executor 0.32.0", + "shlex", "sp-core 28.0.0", "sp-io 30.0.0", "sp-maybe-compressed-blob 11.0.0", @@ -24146,7 +24185,7 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.77", + "syn 2.0.79", "thiserror", "tokio", ] @@ -24209,7 +24248,7 @@ dependencies = [ "quote 1.0.37", "scale-typegen", "subxt-codegen", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -24362,9 +24401,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", @@ -24380,7 +24419,7 @@ dependencies = [ "paste", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -24409,7 +24448,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -24539,7 +24578,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -24714,7 +24753,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -24890,7 +24929,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -25166,7 +25205,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -25208,7 +25247,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -25848,7 +25887,7 @@ dependencies = [ "once_cell", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -25882,7 +25921,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -26966,7 +27005,6 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "lazy_static", "log", "pallet-balances", "pallet-message-queue", @@ -27017,7 +27055,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "staging-xcm", - "syn 2.0.77", + "syn 2.0.79", "trybuild", ] @@ -27188,7 +27226,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -27208,7 +27246,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -27216,7 +27254,6 @@ name = "zombienet-backchannel" version = "1.0.0" dependencies = [ "futures-util", - "lazy_static", "parity-scale-codec", "reqwest 0.11.20", "serde", @@ -27230,17 +27267,19 @@ dependencies = [ [[package]] name = "zombienet-configuration" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23322e411b8d19b41b5c20ab8e88c10822189a4fcfd069c7fcd1542b8d3035aa" +checksum = "ebbfc98adb25076777967f7aad078e74029e129b102eb0812c425432f8c2be7b" dependencies = [ "anyhow", "lazy_static", "multiaddr 0.18.1", "regex", + "reqwest 0.11.20", "serde", "serde_json", "thiserror", + "tokio", "toml 0.7.8", "url", "zombienet-support", @@ -27248,9 +27287,9 @@ dependencies = [ [[package]] name = "zombienet-orchestrator" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381f701565b3918a909132743b3674569ce3da25b5c3a6493883abaf1046577a" +checksum = "5b17f4d1d05b3aedf02818eb0f4d5a76664da0e07bb2f7e7d02613e0ef0f316a" dependencies = [ "anyhow", "async-trait", @@ -27281,9 +27320,9 @@ dependencies = [ [[package]] name = "zombienet-prom-metrics-parser" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab79fa58bcfecbcd41485c6f13052853ccde8b09f173b601f78747d7abc2b7f" +checksum = "7203390ab88919240da3a3eb06b625b6e300e94f98e04ba5141e9138dc663b7d" dependencies = [ "pest", "pest_derive", @@ -27292,9 +27331,9 @@ dependencies = [ [[package]] name = "zombienet-provider" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af0264938da61b25da89f17ee0630393a4ba793582a4a8a1650eb15b47fc1ef" +checksum = "ee02ee957ec39b698798fa6dc2a0d5ba4524198471c37d57755e9685b67fb50c" dependencies = [ "anyhow", "async-trait", @@ -27323,9 +27362,9 @@ dependencies = [ [[package]] name = "zombienet-sdk" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc5b7ebfba4ab62486c8cb5bcd7345c4376487487cfe3481476cb4d4accc75e" +checksum = "f594e67922182277a3da0926f21b693eb5a0c38b32ca7fd6ef16167809fe5064" dependencies = [ "async-trait", "futures", @@ -27340,9 +27379,9 @@ dependencies = [ [[package]] name = "zombienet-support" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5b80d34a0eecca69dd84c2e13f84f1fae0cc378baf4f15f769027af068418b" +checksum = "93d3144537df7c8939bbb355cc5245a6dc0078446a6cdaf9272268bd1043c788" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 8e3330e4e614..e2c6d6c8dedc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -158,6 +158,7 @@ members = [ "polkadot/erasure-coding/fuzzer", "polkadot/node/collation-generation", "polkadot/node/core/approval-voting", + "polkadot/node/core/approval-voting-parallel", "polkadot/node/core/av-store", "polkadot/node/core/backing", "polkadot/node/core/bitfield-signing", @@ -551,7 +552,7 @@ default-members = [ [workspace.lints.rust] suspicious_double_ref_op = { level = "allow", priority = 2 } # `substrate_runtime` is a common `cfg` condition name used in the repo. -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(substrate_runtime)'] } +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(build_opt_level, values("3"))', 'cfg(build_profile, values("debug", "release"))', 'cfg(enable_alloc_error_handler)', 'cfg(fuzzing)', 'cfg(substrate_runtime)'] } [workspace.lints.clippy] all = { level = "allow", priority = 0 } @@ -737,6 +738,7 @@ either = { version = "1.8.1", default-features = false } emulated-integration-tests-common = { path = "cumulus/parachains/integration-tests/emulated/common", default-features = false } enumflags2 = { version = "0.7.7" } enumn = { version = "0.1.13" } +env_logger = { version = "0.11.2" } environmental = { version = "1.1.4", default-features = false } equivocation-detector = { path = "bridges/relays/equivocation" } ethabi = { version = "1.0.0", default-features = false, package = "ethabi-decode" } @@ -824,7 +826,6 @@ kvdb-memorydb = { version = "0.13.0" } kvdb-rocksdb = { version = "0.19.0" } kvdb-shared-tests = { version = "0.11.0" } landlock = { version = "0.3.0" } -lazy_static = { version = "1.5.0" } libc = { version = "0.2.155" } libfuzzer-sys = { version = "0.4" } libp2p = { version = "0.52.4" } @@ -1031,6 +1032,7 @@ polkadot-gossip-support = { path = "polkadot/node/network/gossip-support", defau polkadot-network-bridge = { path = "polkadot/node/network/bridge", default-features = false } polkadot-node-collation-generation = { path = "polkadot/node/collation-generation", default-features = false } polkadot-node-core-approval-voting = { path = "polkadot/node/core/approval-voting", default-features = false } +polkadot-node-core-approval-voting-parallel = { path = "polkadot/node/core/approval-voting-parallel", default-features = false } polkadot-node-core-av-store = { path = "polkadot/node/core/av-store", default-features = false } polkadot-node-core-backing = { path = "polkadot/node/core/backing", default-features = false } polkadot-node-core-bitfield-signing = { path = "polkadot/node/core/bitfield-signing", default-features = false } @@ -1197,6 +1199,7 @@ sha1 = { version = "0.10.6" } sha2 = { version = "0.10.7", default-features = false } sha3 = { version = "0.10.0", default-features = false } shell-runtime = { path = "cumulus/parachains/runtimes/starters/shell" } +shlex = { version = "1.3.0" } slot-range-helper = { path = "polkadot/runtime/common/slot_range_helper", default-features = false } slotmap = { version = "1.0" } smallvec = { version = "1.11.0", default-features = false } @@ -1299,7 +1302,9 @@ substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } substrate-test-utils = { path = "substrate/test-utils" } substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } -syn = { version = "2.0.77" } +subxt = { version = "0.37", default-features = false } +subxt-signer = { version = "0.37" } +syn = { version = "2.0.79" } sysinfo = { version = "0.30" } tar = { version = "0.4" } tempfile = { version = "3.8.1" } @@ -1368,6 +1373,7 @@ xcm-procedural = { path = "polkadot/xcm/procedural", default-features = false } xcm-runtime-apis = { path = "polkadot/xcm/xcm-runtime-apis", default-features = false } xcm-simulator = { path = "polkadot/xcm/xcm-simulator", default-features = false } zeroize = { version = "1.7.0", default-features = false } +zombienet-sdk = { version = "0.2.13" } zstd = { version = "0.12.4", default-features = false } [profile.release] diff --git a/bridges/bin/runtime-common/src/extensions.rs b/bridges/bin/runtime-common/src/extensions.rs index dc7e14de28f3..dced50239471 100644 --- a/bridges/bin/runtime-common/src/extensions.rs +++ b/bridges/bin/runtime-common/src/extensions.rs @@ -374,7 +374,7 @@ mod tests { use super::*; use crate::mock::*; use bp_header_chain::StoredHeaderDataBuilder; - use bp_messages::{InboundLaneData, LaneId, MessageNonce, OutboundLaneData}; + use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData}; use bp_parachains::{BestParaHeadHash, ParaInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; @@ -390,17 +390,16 @@ mod tests { }; parameter_types! { - pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::ThisChain, ); - pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain, ); - pub TestLaneId: LaneId = test_lane_id(); } pub struct MockCall { @@ -476,10 +475,6 @@ mod tests { } } - fn test_lane_id() -> LaneId { - LaneId::new(1, 2) - } - fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = TestStake::get(); ExistentialDeposit::get().saturating_add(test_stake * 100) diff --git a/bridges/bin/runtime-common/src/messages_api.rs b/bridges/bin/runtime-common/src/messages_api.rs index 7fbdeb366124..c8522d4d1f27 100644 --- a/bridges/bin/runtime-common/src/messages_api.rs +++ b/bridges/bin/runtime-common/src/messages_api.rs @@ -16,14 +16,12 @@ //! Helpers for implementing various message-related runtime API methods. -use bp_messages::{ - InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, -}; +use bp_messages::{InboundMessageDetails, MessageNonce, MessagePayload, OutboundMessageDetails}; use sp_std::vec::Vec; /// Implementation of the `To*OutboundLaneApi::message_details`. pub fn outbound_message_details( - lane: LaneId, + lane: Runtime::LaneId, begin: MessageNonce, end: MessageNonce, ) -> Vec @@ -48,7 +46,7 @@ where /// Implementation of the `To*InboundLaneApi::message_details`. pub fn inbound_message_details( - lane: LaneId, + lane: Runtime::LaneId, messages: Vec<(MessagePayload, OutboundMessageDetails)>, ) -> Vec where diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs index 1880e65547fe..acbdbcda8dea 100644 --- a/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -33,15 +33,15 @@ use pallet_bridge_messages::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, - BridgedChainOf, ThisChainOf, + BridgedChainOf, LaneIdOf, ThisChainOf, }; use sp_runtime::traits::{Header, Zero}; use sp_std::prelude::*; use xcm::latest::prelude::*; /// Prepare inbound bridge message according to given message proof parameters. -fn prepare_inbound_message( - params: &MessageProofParams, +fn prepare_inbound_message( + params: &MessageProofParams, successful_dispatch_message_generator: impl Fn(usize) -> MessagePayload, ) -> MessagePayload { let expected_size = params.proof_params.db_size.unwrap_or(0) as usize; @@ -71,9 +71,9 @@ fn prepare_inbound_message( /// uses GRANDPA finality. For parachains, please use the `prepare_message_proof_from_parachain` /// function. pub fn prepare_message_proof_from_grandpa_chain( - params: MessageProofParams, + params: MessageProofParams>, message_generator: impl Fn(usize) -> MessagePayload, -) -> (FromBridgedChainMessagesProof>>, Weight) +) -> (FromBridgedChainMessagesProof>, LaneIdOf>, Weight) where R: pallet_bridge_grandpa::Config> + pallet_bridge_messages::Config< @@ -84,18 +84,21 @@ where MI: 'static, { // prepare storage proof - let (state_root, storage_proof) = - prepare_messages_storage_proof::, ThisChainOf>( - params.lane, - params.message_nonces.clone(), - params.outbound_lane_data.clone(), - params.proof_params, - |_| prepare_inbound_message(¶ms, &message_generator), - encode_all_messages, - encode_lane_data, - false, - false, - ); + let (state_root, storage_proof) = prepare_messages_storage_proof::< + BridgedChainOf, + ThisChainOf, + LaneIdOf, + >( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.proof_params, + |_| prepare_inbound_message(¶ms, &message_generator), + encode_all_messages, + encode_lane_data, + false, + false, + ); // update runtime storage let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); @@ -121,9 +124,9 @@ where /// uses parachain finality. For GRANDPA chains, please use the /// `prepare_message_proof_from_grandpa_chain` function. pub fn prepare_message_proof_from_parachain( - params: MessageProofParams, + params: MessageProofParams>, message_generator: impl Fn(usize) -> MessagePayload, -) -> (FromBridgedChainMessagesProof>>, Weight) +) -> (FromBridgedChainMessagesProof>, LaneIdOf>, Weight) where R: pallet_bridge_parachains::Config + pallet_bridge_messages::Config, PI: 'static, @@ -131,18 +134,21 @@ where BridgedChainOf: Chain + Parachain, { // prepare storage proof - let (state_root, storage_proof) = - prepare_messages_storage_proof::, ThisChainOf>( - params.lane, - params.message_nonces.clone(), - params.outbound_lane_data.clone(), - params.proof_params, - |_| prepare_inbound_message(¶ms, &message_generator), - encode_all_messages, - encode_lane_data, - false, - false, - ); + let (state_root, storage_proof) = prepare_messages_storage_proof::< + BridgedChainOf, + ThisChainOf, + LaneIdOf, + >( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.proof_params, + |_| prepare_inbound_message(¶ms, &message_generator), + encode_all_messages, + encode_lane_data, + false, + false, + ); // update runtime storage let (_, bridged_header_hash) = @@ -166,8 +172,8 @@ where /// uses GRANDPA finality. For parachains, please use the /// `prepare_message_delivery_proof_from_parachain` function. pub fn prepare_message_delivery_proof_from_grandpa_chain( - params: MessageDeliveryProofParams>>, -) -> FromBridgedChainMessagesDeliveryProof>> + params: MessageDeliveryProofParams>, LaneIdOf>, +) -> FromBridgedChainMessagesDeliveryProof>, LaneIdOf> where R: pallet_bridge_grandpa::Config> + pallet_bridge_messages::Config< @@ -182,6 +188,7 @@ where let (state_root, storage_proof) = prepare_message_delivery_storage_proof::< BridgedChainOf, ThisChainOf, + LaneIdOf, >(params.lane, params.inbound_lane_data, params.proof_params); // update runtime storage @@ -200,8 +207,8 @@ where /// uses parachain finality. For GRANDPA chains, please use the /// `prepare_message_delivery_proof_from_grandpa_chain` function. pub fn prepare_message_delivery_proof_from_parachain( - params: MessageDeliveryProofParams>>, -) -> FromBridgedChainMessagesDeliveryProof>> + params: MessageDeliveryProofParams>, LaneIdOf>, +) -> FromBridgedChainMessagesDeliveryProof>, LaneIdOf> where R: pallet_bridge_parachains::Config + pallet_bridge_messages::Config, PI: 'static, @@ -213,6 +220,7 @@ where let (state_root, storage_proof) = prepare_message_delivery_storage_proof::< BridgedChainOf, ThisChainOf, + LaneIdOf, >(params.lane, params.inbound_lane_data, params.proof_params); // update runtime storage diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index fed0d15cc080..1d4043fc4b61 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -21,7 +21,7 @@ use bp_header_chain::ChainWithGrandpa; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - ChainWithMessages, LaneId, MessageNonce, + ChainWithMessages, HashedLaneId, LaneIdType, MessageNonce, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::PayRewardFromAccount; @@ -70,7 +70,7 @@ pub type BridgedChainHeader = sp_runtime::generic::Header; /// Rewards payment procedure. -pub type TestPaymentProcedure = PayRewardFromAccount; +pub type TestPaymentProcedure = PayRewardFromAccount; /// Stake that we are using in tests. pub type TestStake = ConstU64<5_000>; /// Stake and slash mechanism to use in tests. @@ -83,10 +83,11 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< ConstU32<8>, >; -/// Message lane used in tests. -#[allow(unused)] -pub fn test_lane_id() -> LaneId { - LaneId::new(1, 2) +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; +/// Lane that we're using in tests. +pub fn test_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 2).unwrap() } /// Bridged chain id used in tests. @@ -189,10 +190,10 @@ impl pallet_bridge_messages::Config for TestRuntime { type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; type OutboundPayload = Vec; - type InboundPayload = Vec; - type DeliveryPayments = (); + type LaneId = TestLaneIdType; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, (), @@ -213,13 +214,14 @@ impl pallet_bridge_relayers::Config for TestRuntime { type PaymentProcedure = TestPaymentProcedure; type StakeAndSlash = TestStakeAndSlash; type WeightInfo = (); + type LaneId = TestLaneIdType; } /// Dummy message dispatcher. pub struct DummyMessageDispatch; impl DummyMessageDispatch { - pub fn deactivate(lane: LaneId) { + pub fn deactivate(lane: TestLaneIdType) { frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); } } @@ -227,18 +229,21 @@ impl DummyMessageDispatch { impl MessageDispatch for DummyMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); + type LaneId = TestLaneIdType; - fn is_active(lane: LaneId) -> bool { + fn is_active(lane: Self::LaneId) -> bool { frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != Some(false) } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::zero() } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } diff --git a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs index c990e8a12f36..485fb3d31f20 100644 --- a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs @@ -93,4 +93,4 @@ pub const WITH_BRIDGE_HUB_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessa pub const WITH_BRIDGE_HUB_KUSAMA_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; decl_bridge_finality_runtime_apis!(bridge_hub_kusama); -decl_bridge_messages_runtime_apis!(bridge_hub_kusama); +decl_bridge_messages_runtime_apis!(bridge_hub_kusama, LegacyLaneId); diff --git a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs index 7379b8863b1d..7a1793b4da4a 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs @@ -85,4 +85,4 @@ pub const WITH_BRIDGE_HUB_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotM pub const WITH_BRIDGE_HUB_POLKADOT_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; decl_bridge_finality_runtime_apis!(bridge_hub_polkadot); -decl_bridge_messages_runtime_apis!(bridge_hub_polkadot); +decl_bridge_messages_runtime_apis!(bridge_hub_polkadot, LegacyLaneId); diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index 7920eb934033..538bc44019f5 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -99,7 +99,7 @@ pub const WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX: u8 = 51; pub const WITH_BRIDGE_ROCOCO_TO_BULLETIN_MESSAGES_PALLET_INDEX: u8 = 61; decl_bridge_finality_runtime_apis!(bridge_hub_rococo); -decl_bridge_messages_runtime_apis!(bridge_hub_rococo); +decl_bridge_messages_runtime_apis!(bridge_hub_rococo, LegacyLaneId); frame_support::parameter_types! { /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Rococo diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 644fa64c687b..7a213fdb28c8 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -88,7 +88,7 @@ pub const WITH_BRIDGE_HUB_WESTEND_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; pub const WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 44; decl_bridge_finality_runtime_apis!(bridge_hub_westend); -decl_bridge_messages_runtime_apis!(bridge_hub_westend); +decl_bridge_messages_runtime_apis!(bridge_hub_westend, LegacyLaneId); frame_support::parameter_types! { /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Westend diff --git a/bridges/chains/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index 88980a957501..d00936919721 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -228,4 +228,4 @@ impl ChainWithMessages for PolkadotBulletin { } decl_bridge_finality_runtime_apis!(polkadot_bulletin, grandpa); -decl_bridge_messages_runtime_apis!(polkadot_bulletin); +decl_bridge_messages_runtime_apis!(polkadot_bulletin, bp_messages::HashedLaneId); diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index dff4b98fd919..22a15ec4062f 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -728,15 +728,13 @@ pub mod pallet { init_params; let authority_set_length = authority_list.len(); let authority_set = StoredAuthoritySet::::try_new(authority_list, set_id) - .map_err(|e| { + .inspect_err(|_| { log::error!( target: LOG_TARGET, "Failed to initialize bridge. Number of authorities in the set {} is larger than the configured value {}", authority_set_length, T::BridgedChain::MAX_AUTHORITIES_COUNT, ); - - e })?; let initial_hash = header.hash(); diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index b3a4447fb021..355fb08ab28a 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -26,7 +26,7 @@ use crate::{ use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, ChainWithMessages, DeliveredMessages, - InboundLaneData, LaneId, LaneState, MessageNonce, OutboundLaneData, UnrewardedRelayer, + InboundLaneData, LaneState, MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; use bp_runtime::{AccountIdOf, HashOf, UnverifiedStorageProofParams}; @@ -44,7 +44,7 @@ pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Benchmark-specific message proof parameters. #[derive(Debug)] -pub struct MessageProofParams { +pub struct MessageProofParams { /// Id of the lane. pub lane: LaneId, /// Range of messages to include in the proof. @@ -62,7 +62,7 @@ pub struct MessageProofParams { /// Benchmark-specific message delivery proof parameters. #[derive(Debug)] -pub struct MessageDeliveryProofParams { +pub struct MessageDeliveryProofParams { /// Id of the lane. pub lane: LaneId, /// The proof needs to include this inbound lane data. @@ -74,8 +74,8 @@ pub struct MessageDeliveryProofParams { /// Trait that must be implemented by runtime. pub trait Config: crate::Config { /// Lane id to use in benchmarks. - fn bench_lane_id() -> LaneId { - LaneId::new(1, 2) + fn bench_lane_id() -> Self::LaneId { + Self::LaneId::default() } /// Return id of relayer account at the bridged chain. @@ -94,12 +94,12 @@ pub trait Config: crate::Config { /// Prepare messages proof to receive by the module. fn prepare_message_proof( - params: MessageProofParams, - ) -> (FromBridgedChainMessagesProof>>, Weight); + params: MessageProofParams, + ) -> (FromBridgedChainMessagesProof>, Self::LaneId>, Weight); /// Prepare messages delivery proof to receive by the module. fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> FromBridgedChainMessagesDeliveryProof>>; + params: MessageDeliveryProofParams, + ) -> FromBridgedChainMessagesDeliveryProof>, Self::LaneId>; /// Returns true if message has been successfully dispatched or not. fn is_message_successfully_dispatched(_nonce: MessageNonce) -> bool { diff --git a/bridges/modules/messages/src/call_ext.rs b/bridges/modules/messages/src/call_ext.rs index 8e021c8e5e24..9e5f5f8d1129 100644 --- a/bridges/modules/messages/src/call_ext.rs +++ b/bridges/modules/messages/src/call_ext.rs @@ -20,8 +20,8 @@ use crate::{BridgedChainOf, Config, InboundLanes, OutboundLanes, Pallet, LOG_TAR use bp_messages::{ target_chain::MessageDispatch, BaseMessagesProofInfo, ChainWithMessages, InboundLaneData, - LaneId, MessageNonce, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, - ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, + MessageNonce, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, + UnrewardedRelayerOccupation, }; use bp_runtime::{AccountIdOf, OwnedBridgeModule}; use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; @@ -39,7 +39,7 @@ impl, I: 'static> CallHelper { /// /// - call is `receive_messages_delivery_proof` and all messages confirmations have been /// received. - pub fn was_successful(info: &MessagesCallInfo) -> bool { + pub fn was_successful(info: &MessagesCallInfo) -> bool { match info { MessagesCallInfo::ReceiveMessagesProof(info) => { let inbound_lane_data = match InboundLanes::::get(info.base.lane_id) { @@ -75,19 +75,21 @@ pub trait CallSubType, I: 'static>: IsSubType, T>> { /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call. - fn receive_messages_proof_info(&self) -> Option; + fn receive_messages_proof_info(&self) -> Option>; /// Create a new instance of `ReceiveMessagesDeliveryProofInfo` from /// a `ReceiveMessagesDeliveryProof` call. - fn receive_messages_delivery_proof_info(&self) -> Option; + fn receive_messages_delivery_proof_info( + &self, + ) -> Option>; /// Create a new instance of `MessagesCallInfo` from a `ReceiveMessagesProof` /// or a `ReceiveMessagesDeliveryProof` call. - fn call_info(&self) -> Option; + fn call_info(&self) -> Option>; /// Create a new instance of `MessagesCallInfo` from a `ReceiveMessagesProof` /// or a `ReceiveMessagesDeliveryProof` call, if the call is for the provided lane. - fn call_info_for(&self, lane_id: LaneId) -> Option; + fn call_info_for(&self, lane_id: T::LaneId) -> Option>; /// Ensures that a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call: /// @@ -114,7 +116,7 @@ impl< I: 'static, > CallSubType for T::RuntimeCall { - fn receive_messages_proof_info(&self) -> Option { + fn receive_messages_proof_info(&self) -> Option> { if let Some(crate::Call::::receive_messages_proof { ref proof, .. }) = self.is_sub_type() { @@ -135,7 +137,9 @@ impl< None } - fn receive_messages_delivery_proof_info(&self) -> Option { + fn receive_messages_delivery_proof_info( + &self, + ) -> Option> { if let Some(crate::Call::::receive_messages_delivery_proof { ref proof, ref relayers_state, @@ -159,7 +163,7 @@ impl< None } - fn call_info(&self) -> Option { + fn call_info(&self) -> Option> { if let Some(info) = self.receive_messages_proof_info() { return Some(MessagesCallInfo::ReceiveMessagesProof(info)) } @@ -171,7 +175,7 @@ impl< None } - fn call_info_for(&self, lane_id: LaneId) -> Option { + fn call_info_for(&self, lane_id: T::LaneId) -> Option> { self.call_info().filter(|info| { let actual_lane_id = match info { MessagesCallInfo::ReceiveMessagesProof(info) => info.base.lane_id, @@ -251,10 +255,6 @@ mod tests { }; use sp_std::ops::RangeInclusive; - fn test_lane_id() -> LaneId { - LaneId::new(1, 2) - } - fn fill_unrewarded_relayers() { let mut inbound_lane_state = InboundLanes::::get(test_lane_id()).unwrap(); for n in 0..BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 65240feb7194..91f1159f8f91 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -20,8 +20,8 @@ use crate::{BridgedChainOf, Config}; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, LaneState, MessageKey, - MessageNonce, OutboundLaneData, ReceptionResult, UnrewardedRelayer, + ChainWithMessages, DeliveredMessages, InboundLaneData, LaneState, MessageKey, MessageNonce, + OutboundLaneData, ReceptionResult, UnrewardedRelayer, }; use bp_runtime::AccountIdOf; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; @@ -33,9 +33,11 @@ use sp_std::prelude::PartialEq; pub trait InboundLaneStorage { /// Id of relayer on source chain. type Relayer: Clone + PartialEq; + /// Lane identifier type. + type LaneId: Encode; /// Lane id. - fn id(&self) -> LaneId; + fn id(&self) -> Self::LaneId; /// Return maximal number of unrewarded relayer entries in inbound lane. fn max_unrewarded_relayer_entries(&self) -> MessageNonce; /// Return maximal number of unconfirmed messages in inbound lane. @@ -181,7 +183,7 @@ impl InboundLane { } /// Receive new message. - pub fn receive_message( + pub fn receive_message>( &mut self, relayer_at_bridged_chain: &S::Relayer, nonce: MessageNonce, diff --git a/bridges/modules/messages/src/lanes_manager.rs b/bridges/modules/messages/src/lanes_manager.rs index 4f5ac1c0a403..27cab48535d7 100644 --- a/bridges/modules/messages/src/lanes_manager.rs +++ b/bridges/modules/messages/src/lanes_manager.rs @@ -21,8 +21,8 @@ use crate::{ }; use bp_messages::{ - target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneId, LaneState, - MessageKey, MessageNonce, OutboundLaneData, + target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneState, MessageKey, + MessageNonce, OutboundLaneData, }; use bp_runtime::AccountIdOf; use codec::{Decode, Encode, MaxEncodedLen}; @@ -68,7 +68,7 @@ impl, I: 'static> LanesManager { /// Create new inbound lane in `Opened` state. pub fn create_inbound_lane( &self, - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, LanesManagerError> { InboundLanes::::try_mutate(lane_id, |lane| match lane { Some(_) => Err(LanesManagerError::InboundLaneAlreadyExists), @@ -87,7 +87,7 @@ impl, I: 'static> LanesManager { /// Create new outbound lane in `Opened` state. pub fn create_outbound_lane( &self, - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, LanesManagerError> { OutboundLanes::::try_mutate(lane_id, |lane| match lane { Some(_) => Err(LanesManagerError::OutboundLaneAlreadyExists), @@ -103,7 +103,7 @@ impl, I: 'static> LanesManager { /// Get existing inbound lane, checking that it is in usable state. pub fn active_inbound_lane( &self, - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, LanesManagerError> { Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, true)?)) } @@ -111,7 +111,7 @@ impl, I: 'static> LanesManager { /// Get existing outbound lane, checking that it is in usable state. pub fn active_outbound_lane( &self, - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, LanesManagerError> { Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, true)?)) } @@ -119,7 +119,7 @@ impl, I: 'static> LanesManager { /// Get existing inbound lane without any additional state checks. pub fn any_state_inbound_lane( &self, - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, LanesManagerError> { Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, false)?)) } @@ -127,7 +127,7 @@ impl, I: 'static> LanesManager { /// Get existing outbound lane without any additional state checks. pub fn any_state_outbound_lane( &self, - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, LanesManagerError> { Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, false)?)) } @@ -135,14 +135,14 @@ impl, I: 'static> LanesManager { /// Runtime inbound lane storage. pub struct RuntimeInboundLaneStorage, I: 'static = ()> { - pub(crate) lane_id: LaneId, + pub(crate) lane_id: T::LaneId, pub(crate) cached_data: InboundLaneData>>, } impl, I: 'static> RuntimeInboundLaneStorage { /// Creates new runtime inbound lane storage for given **existing** lane. fn from_lane_id( - lane_id: LaneId, + lane_id: T::LaneId, check_active: bool, ) -> Result, LanesManagerError> { let cached_data = @@ -196,8 +196,9 @@ impl, I: 'static> RuntimeInboundLaneStorage { impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { type Relayer = AccountIdOf>; + type LaneId = T::LaneId; - fn id(&self) -> LaneId { + fn id(&self) -> Self::LaneId { self.lane_id } @@ -225,15 +226,15 @@ impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< /// Runtime outbound lane storage. #[derive(Debug, PartialEq, Eq)] -pub struct RuntimeOutboundLaneStorage { - pub(crate) lane_id: LaneId, +pub struct RuntimeOutboundLaneStorage, I: 'static> { + pub(crate) lane_id: T::LaneId, pub(crate) cached_data: OutboundLaneData, pub(crate) _phantom: PhantomData<(T, I)>, } impl, I: 'static> RuntimeOutboundLaneStorage { /// Creates new runtime outbound lane storage for given **existing** lane. - fn from_lane_id(lane_id: LaneId, check_active: bool) -> Result { + fn from_lane_id(lane_id: T::LaneId, check_active: bool) -> Result { let cached_data = OutboundLanes::::get(lane_id).ok_or(LanesManagerError::UnknownOutboundLane)?; ensure!( @@ -246,8 +247,9 @@ impl, I: 'static> RuntimeOutboundLaneStorage { impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { type StoredMessagePayload = StoredMessagePayload; + type LaneId = T::LaneId; - fn id(&self) -> LaneId { + fn id(&self) -> Self::LaneId { self.lane_id } diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index b7fe1c7dbb19..af14257db99c 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -60,9 +60,9 @@ use bp_messages::{ DeliveryPayments, DispatchMessage, FromBridgedChainMessagesProof, MessageDispatch, ProvedLaneMessages, ProvedMessages, }, - ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, - MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, - OutboundMessageDetails, UnrewardedRelayersState, VerificationError, + ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, MessageKey, + MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, + UnrewardedRelayersState, VerificationError, }; use bp_runtime::{ AccountIdOf, BasicOperatingMode, HashOf, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, @@ -97,7 +97,7 @@ pub const LOG_TARGET: &str = "runtime::bridge-messages"; #[frame_support::pallet] pub mod pallet { use super::*; - use bp_messages::{ReceivedMessages, ReceptionResult}; + use bp_messages::{LaneIdType, ReceivedMessages, ReceptionResult}; use bp_runtime::RangeInclusiveExt; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -123,17 +123,25 @@ pub mod pallet { type OutboundPayload: Parameter + Size; /// Payload type of inbound messages. This payload is dispatched on this chain. type InboundPayload: Decode; + /// Lane identifier type. + type LaneId: LaneIdType; /// Handler for relayer payments that happen during message delivery transaction. type DeliveryPayments: DeliveryPayments; /// Handler for relayer payments that happen during message delivery confirmation /// transaction. - type DeliveryConfirmationPayments: DeliveryConfirmationPayments; + type DeliveryConfirmationPayments: DeliveryConfirmationPayments< + Self::AccountId, + Self::LaneId, + >; /// Delivery confirmation callback. - type OnMessagesDelivered: OnMessagesDelivered; + type OnMessagesDelivered: OnMessagesDelivered; /// Message dispatch handler. - type MessageDispatch: MessageDispatch; + type MessageDispatch: MessageDispatch< + DispatchPayload = Self::InboundPayload, + LaneId = Self::LaneId, + >; } /// Shortcut to this chain type for Config. @@ -142,6 +150,8 @@ pub mod pallet { pub type BridgedChainOf = >::BridgedChain; /// Shortcut to bridged header chain type for Config. pub type BridgedHeaderChainOf = >::BridgedHeaderChain; + /// Shortcut to lane identifier type for Config. + pub type LaneIdOf = >::LaneId; #[pallet::pallet] #[pallet::storage_version(migration::STORAGE_VERSION)] @@ -203,7 +213,7 @@ pub mod pallet { pub fn receive_messages_proof( origin: OriginFor, relayer_id_at_bridged_chain: AccountIdOf>, - proof: Box>>>, + proof: Box>, T::LaneId>>, messages_count: u32, dispatch_weight: Weight, ) -> DispatchResultWithPostInfo { @@ -350,7 +360,7 @@ pub mod pallet { ))] pub fn receive_messages_delivery_proof( origin: OriginFor, - proof: FromBridgedChainMessagesDeliveryProof>>, + proof: FromBridgedChainMessagesDeliveryProof>, T::LaneId>, mut relayers_state: UnrewardedRelayersState, ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; @@ -387,7 +397,7 @@ pub mod pallet { // emit 'delivered' event let received_range = confirmed_messages.begin..=confirmed_messages.end; Self::deposit_event(Event::MessagesDelivered { - lane_id, + lane_id: lane_id.into(), messages: confirmed_messages, }); @@ -441,19 +451,22 @@ pub mod pallet { /// Message has been accepted and is waiting to be delivered. MessageAccepted { /// Lane, which has accepted the message. - lane_id: LaneId, + lane_id: T::LaneId, /// Nonce of accepted message. nonce: MessageNonce, }, /// Messages have been received from the bridged chain. MessagesReceived( /// Result of received messages dispatch. - ReceivedMessages<::DispatchLevelResult>, + ReceivedMessages< + ::DispatchLevelResult, + T::LaneId, + >, ), /// Messages in the inclusive range have been delivered to the bridged chain. MessagesDelivered { /// Lane for which the delivery has been confirmed. - lane_id: LaneId, + lane_id: T::LaneId, /// Delivered messages. messages: DeliveredMessages, }, @@ -510,13 +523,13 @@ pub mod pallet { /// Map of lane id => inbound lane data. #[pallet::storage] pub type InboundLanes, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData, OptionQuery>; + StorageMap<_, Blake2_128Concat, T::LaneId, StoredInboundLaneData, OptionQuery>; /// Map of lane id => outbound lane data. #[pallet::storage] pub type OutboundLanes, I: 'static = ()> = StorageMap< Hasher = Blake2_128Concat, - Key = LaneId, + Key = T::LaneId, Value = OutboundLaneData, QueryKind = OptionQuery, >; @@ -524,7 +537,7 @@ pub mod pallet { /// All queued outbound messages. #[pallet::storage] pub type OutboundMessages, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; + StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; #[pallet::genesis_config] #[derive(DefaultNoBound)] @@ -534,7 +547,7 @@ pub mod pallet { /// Initial pallet owner. pub owner: Option, /// Opened lanes. - pub opened_lanes: Vec, + pub opened_lanes: Vec, /// Dummy marker. #[serde(skip)] pub _phantom: sp_std::marker::PhantomData, @@ -565,13 +578,16 @@ pub mod pallet { impl, I: 'static> Pallet { /// Get stored data of the outbound message with given nonce. - pub fn outbound_message_data(lane: LaneId, nonce: MessageNonce) -> Option { + pub fn outbound_message_data( + lane: T::LaneId, + nonce: MessageNonce, + ) -> Option { OutboundMessages::::get(MessageKey { lane_id: lane, nonce }).map(Into::into) } /// Prepare data, related to given inbound message. pub fn inbound_message_data( - lane: LaneId, + lane: T::LaneId, payload: MessagePayload, outbound_details: OutboundMessageDetails, ) -> InboundMessageDetails { @@ -585,13 +601,13 @@ pub mod pallet { } /// Return outbound lane data. - pub fn outbound_lane_data(lane: LaneId) -> Option { + pub fn outbound_lane_data(lane: T::LaneId) -> Option { OutboundLanes::::get(lane) } /// Return inbound lane data. pub fn inbound_lane_data( - lane: LaneId, + lane: T::LaneId, ) -> Option>>> { InboundLanes::::get(lane).map(|lane| lane.0) } @@ -654,12 +670,12 @@ pub mod pallet { /// to send it on the bridge. #[derive(Debug, PartialEq, Eq)] pub struct SendMessageArgs, I: 'static> { - lane_id: LaneId, + lane_id: T::LaneId, lane: OutboundLane>, payload: StoredMessagePayload, } -impl bp_messages::source_chain::MessagesBridge for Pallet +impl bp_messages::source_chain::MessagesBridge for Pallet where T: Config, I: 'static, @@ -668,7 +684,7 @@ where type SendMessageArgs = SendMessageArgs; fn validate_message( - lane_id: LaneId, + lane_id: T::LaneId, message: &T::OutboundPayload, ) -> Result, Self::Error> { // we can't accept any messages if the pallet is halted @@ -703,7 +719,10 @@ where message_len, ); - Pallet::::deposit_event(Event::MessageAccepted { lane_id: args.lane_id, nonce }); + Pallet::::deposit_event(Event::MessageAccepted { + lane_id: args.lane_id.into(), + nonce, + }); SendMessageArtifacts { nonce, enqueued_messages } } @@ -722,7 +741,7 @@ fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error< /// Creates new inbound lane object, backed by runtime storage. Lane must be active. fn active_inbound_lane, I: 'static>( - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, Error> { LanesManager::::new() .active_inbound_lane(lane_id) @@ -731,7 +750,7 @@ fn active_inbound_lane, I: 'static>( /// Creates new outbound lane object, backed by runtime storage. Lane must be active. fn active_outbound_lane, I: 'static>( - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, Error> { LanesManager::::new() .active_outbound_lane(lane_id) @@ -740,7 +759,7 @@ fn active_outbound_lane, I: 'static>( /// Creates new outbound lane object, backed by runtime storage. fn any_state_outbound_lane, I: 'static>( - lane_id: LaneId, + lane_id: T::LaneId, ) -> Result>, Error> { LanesManager::::new() .any_state_outbound_lane(lane_id) @@ -749,9 +768,12 @@ fn any_state_outbound_lane, I: 'static>( /// Verify messages proof and return proved messages with decoded payload. fn verify_and_decode_messages_proof, I: 'static>( - proof: FromBridgedChainMessagesProof>>, + proof: FromBridgedChainMessagesProof>, T::LaneId>, messages_count: u32, -) -> Result>, VerificationError> { +) -> Result< + ProvedMessages>, + VerificationError, +> { // `receive_messages_proof` weight formula and `MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` // check guarantees that the `message_count` is sane and Vec may be allocated. // (tx with too many messages will either be rejected from the pool, or will fail earlier) diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index f71240ab7c70..c72713e7455a 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -19,7 +19,7 @@ use crate::{Config, LOG_TARGET}; use bp_messages::{ - ChainWithMessages, DeliveredMessages, LaneId, LaneState, MessageNonce, OutboundLaneData, + ChainWithMessages, DeliveredMessages, LaneState, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; use codec::{Decode, Encode}; @@ -32,9 +32,11 @@ use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeIn pub trait OutboundLaneStorage { /// Stored message payload type. type StoredMessagePayload; + /// Lane identifier type. + type LaneId: Encode; /// Lane id. - fn id(&self) -> LaneId; + fn id(&self) -> Self::LaneId; /// Get lane data from the storage. fn data(&self) -> OutboundLaneData; /// Update lane data in the storage. diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs index f35eb24d98c5..dcd642341d77 100644 --- a/bridges/modules/messages/src/proofs.rs +++ b/bridges/modules/messages/src/proofs.rs @@ -22,7 +22,7 @@ use bp_header_chain::{HeaderChain, HeaderChainError}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::{FromBridgedChainMessagesProof, ProvedLaneMessages, ProvedMessages}, - ChainWithMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, + ChainWithMessages, InboundLaneData, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, VerificationError, }; use bp_runtime::{ @@ -32,8 +32,8 @@ use codec::Decode; use sp_std::vec::Vec; /// 'Parsed' message delivery proof - inbound lane id and its state. -pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = - (LaneId, InboundLaneData<::AccountId>); +pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = + (>::LaneId, InboundLaneData<::AccountId>); /// Verify proof of Bridged -> This chain messages. /// @@ -44,9 +44,9 @@ pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = /// outside of this function. This function only verifies that the proof declares exactly /// `messages_count` messages. pub fn verify_messages_proof, I: 'static>( - proof: FromBridgedChainMessagesProof>>, + proof: FromBridgedChainMessagesProof>, T::LaneId>, messages_count: u32, -) -> Result, VerificationError> { +) -> Result>, VerificationError> { let FromBridgedChainMessagesProof { bridged_header_hash, storage_proof, @@ -103,8 +103,8 @@ pub fn verify_messages_proof, I: 'static>( /// Verify proof of This -> Bridged chain messages delivery. pub fn verify_messages_delivery_proof, I: 'static>( - proof: FromBridgedChainMessagesDeliveryProof>>, -) -> Result, VerificationError> { + proof: FromBridgedChainMessagesDeliveryProof>, T::LaneId>, +) -> Result, VerificationError> { let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = proof; let mut parser: MessagesStorageProofAdapter = MessagesStorageProofAdapter::try_new_with_verified_storage_proof( @@ -143,7 +143,7 @@ trait StorageProofAdapter, I: 'static> { fn read_and_decode_outbound_lane_data( &mut self, - lane_id: &LaneId, + lane_id: &T::LaneId, ) -> Result, StorageProofError> { let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key( T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, @@ -154,7 +154,7 @@ trait StorageProofAdapter, I: 'static> { fn read_and_decode_message_payload( &mut self, - message_key: &MessageKey, + message_key: &MessageKey, ) -> Result { let storage_message_key = bp_messages::storage_keys::message_key( T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, @@ -229,19 +229,20 @@ mod tests { encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, add_duplicate_key: bool, add_unused_key: bool, - test: impl Fn(FromBridgedChainMessagesProof) -> R, + test: impl Fn(FromBridgedChainMessagesProof) -> R, ) -> R { - let (state_root, storage_proof) = prepare_messages_storage_proof::( - test_lane_id(), - 1..=nonces_end, - outbound_lane_data, - bp_runtime::UnverifiedStorageProofParams::default(), - generate_dummy_message, - encode_message, - encode_outbound_lane_data, - add_duplicate_key, - add_unused_key, - ); + let (state_root, storage_proof) = + prepare_messages_storage_proof::( + test_lane_id(), + 1..=nonces_end, + outbound_lane_data, + bp_runtime::UnverifiedStorageProofParams::default(), + generate_dummy_message, + encode_message, + encode_outbound_lane_data, + add_duplicate_key, + add_unused_key, + ); sp_io::TestExternalities::new(Default::default()).execute_with(move || { let bridged_header = BridgedChainHeader::new( diff --git a/bridges/modules/messages/src/tests/messages_generation.rs b/bridges/modules/messages/src/tests/messages_generation.rs index 6c4867fa6de3..00b1d3eefe43 100644 --- a/bridges/modules/messages/src/tests/messages_generation.rs +++ b/bridges/modules/messages/src/tests/messages_generation.rs @@ -17,8 +17,8 @@ //! Helpers for generating message storage proofs, that are used by tests and by benchmarks. use bp_messages::{ - storage_keys, ChainWithMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, - MessagePayload, OutboundLaneData, + storage_keys, ChainWithMessages, InboundLaneData, MessageKey, MessageNonce, MessagePayload, + OutboundLaneData, }; use bp_runtime::{ grow_storage_value, record_all_trie_keys, AccountIdOf, Chain, HashOf, HasherOf, @@ -47,7 +47,11 @@ pub fn encode_lane_data(d: &OutboundLaneData) -> Vec { /// /// Returns state trie root and nodes with prepared messages. #[allow(clippy::too_many_arguments)] -pub fn prepare_messages_storage_proof( +pub fn prepare_messages_storage_proof< + BridgedChain: Chain, + ThisChain: ChainWithMessages, + LaneId: Encode + Copy, +>( lane: LaneId, message_nonces: RangeInclusive, outbound_lane_data: Option, @@ -132,7 +136,11 @@ where /// Prepare storage proof of given messages delivery. /// /// Returns state trie root and nodes with prepared messages. -pub fn prepare_message_delivery_storage_proof( +pub fn prepare_message_delivery_storage_proof< + BridgedChain: Chain, + ThisChain: ChainWithMessages, + LaneId: Encode, +>( lane: LaneId, inbound_lane_data: InboundLaneData>, proof_params: UnverifiedStorageProofParams, diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index 2caea9813e82..2935ebd69610 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -35,8 +35,9 @@ use bp_messages::{ DeliveryPayments, DispatchMessage, DispatchMessageData, FromBridgedChainMessagesProof, MessageDispatch, }, - ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, LaneState, Message, MessageKey, - MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, + ChainWithMessages, DeliveredMessages, HashedLaneId, InboundLaneData, LaneIdType, LaneState, + Message, MessageKey, MessageNonce, OutboundLaneData, UnrewardedRelayer, + UnrewardedRelayersState, }; use bp_runtime::{ messages::MessageDispatchResult, Chain, ChainId, Size, UnverifiedStorageProofParams, @@ -195,10 +196,10 @@ impl Config for TestRuntime { type BridgedHeaderChain = BridgedChainGrandpa; type OutboundPayload = TestPayload; - type InboundPayload = TestPayload; - type DeliveryPayments = TestDeliveryPayments; + type LaneId = TestLaneIdType; + type DeliveryPayments = TestDeliveryPayments; type DeliveryConfirmationPayments = TestDeliveryConfirmationPayments; type OnMessagesDelivered = TestOnMessagesDelivered; @@ -207,13 +208,13 @@ impl Config for TestRuntime { #[cfg(feature = "runtime-benchmarks")] impl crate::benchmarking::Config<()> for TestRuntime { - fn bench_lane_id() -> LaneId { + fn bench_lane_id() -> Self::LaneId { test_lane_id() } fn prepare_message_proof( - params: crate::benchmarking::MessageProofParams, - ) -> (FromBridgedChainMessagesProof, Weight) { + params: crate::benchmarking::MessageProofParams, + ) -> (FromBridgedChainMessagesProof, Weight) { use bp_runtime::RangeInclusiveExt; let dispatch_weight = @@ -228,8 +229,8 @@ impl crate::benchmarking::Config<()> for TestRuntime { } fn prepare_message_delivery_proof( - params: crate::benchmarking::MessageDeliveryProofParams, - ) -> FromBridgedChainMessagesDeliveryProof { + params: crate::benchmarking::MessageDeliveryProofParams, + ) -> FromBridgedChainMessagesDeliveryProof { // in mock run we only care about benchmarks correctness, not the benchmark results // => ignore size related arguments prepare_messages_delivery_proof(params.lane, params.inbound_lane_data) @@ -258,19 +259,21 @@ pub const TEST_RELAYER_B: AccountId = 101; /// Account id of additional test relayer - C. pub const TEST_RELAYER_C: AccountId = 102; +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; /// Lane that we're using in tests. -pub fn test_lane_id() -> LaneId { - LaneId::new(1, 2) +pub fn test_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 2).unwrap() } /// Lane that is completely unknown to our runtime. -pub fn unknown_lane_id() -> LaneId { - LaneId::new(1, 3) +pub fn unknown_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 3).unwrap() } /// Lane that is registered, but it is closed. -pub fn closed_lane_id() -> LaneId { - LaneId::new(1, 4) +pub fn closed_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 4).unwrap() } /// Regular message payload. @@ -316,11 +319,11 @@ impl TestDeliveryConfirmationPayments { } } -impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayments { +impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayments { type Error = &'static str; fn pay_reward( - _lane_id: LaneId, + _lane_id: TestLaneIdType, messages_relayers: VecDeque>, _confirmation_relayer: &AccountId, received_range: &RangeInclusive, @@ -341,7 +344,7 @@ impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayment pub struct TestMessageDispatch; impl TestMessageDispatch { - pub fn deactivate(lane: LaneId) { + pub fn deactivate(lane: TestLaneIdType) { // "enqueue" enough (to deactivate dispatcher) messages at dispatcher let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1; for _ in 1..=latest_received_nonce { @@ -349,7 +352,7 @@ impl TestMessageDispatch { } } - pub fn emulate_enqueued_message(lane: LaneId) { + pub fn emulate_enqueued_message(lane: TestLaneIdType) { let key = (b"dispatched", lane).encode(); let dispatched = frame_support::storage::unhashed::get_or_default::(&key[..]); frame_support::storage::unhashed::put(&key[..], &(dispatched + 1)); @@ -359,14 +362,15 @@ impl TestMessageDispatch { impl MessageDispatch for TestMessageDispatch { type DispatchPayload = TestPayload; type DispatchLevelResult = TestDispatchLevelResult; + type LaneId = TestLaneIdType; - fn is_active(lane: LaneId) -> bool { + fn is_active(lane: Self::LaneId) -> bool { frame_support::storage::unhashed::get_or_default::( &(b"dispatched", lane).encode()[..], ) <= BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX } - fn dispatch_weight(message: &mut DispatchMessage) -> Weight { + fn dispatch_weight(message: &mut DispatchMessage) -> Weight { match message.data.payload.as_ref() { Ok(payload) => payload.declared_weight, Err(_) => Weight::zero(), @@ -374,7 +378,7 @@ impl MessageDispatch for TestMessageDispatch { } fn dispatch( - message: DispatchMessage, + message: DispatchMessage, ) -> MessageDispatchResult { match message.data.payload.as_ref() { Ok(payload) => { @@ -390,13 +394,13 @@ impl MessageDispatch for TestMessageDispatch { pub struct TestOnMessagesDelivered; impl TestOnMessagesDelivered { - pub fn call_arguments() -> Option<(LaneId, MessageNonce)> { + pub fn call_arguments() -> Option<(TestLaneIdType, MessageNonce)> { frame_support::storage::unhashed::get(b"TestOnMessagesDelivered.OnMessagesDelivered") } } -impl OnMessagesDelivered for TestOnMessagesDelivered { - fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) { +impl OnMessagesDelivered for TestOnMessagesDelivered { + fn on_messages_delivered(lane: TestLaneIdType, enqueued_messages: MessageNonce) { frame_support::storage::unhashed::put( b"TestOnMessagesDelivered.OnMessagesDelivered", &(lane, enqueued_messages), @@ -405,7 +409,7 @@ impl OnMessagesDelivered for TestOnMessagesDelivered { } /// Return test lane message with given nonce and payload. -pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message { +pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message { Message { key: MessageKey { lane_id: test_lane_id(), nonce }, payload: payload.encode() } } @@ -449,7 +453,7 @@ pub fn unrewarded_relayer( } /// Returns unrewarded relayers state at given lane. -pub fn inbound_unrewarded_relayers_state(lane: bp_messages::LaneId) -> UnrewardedRelayersState { +pub fn inbound_unrewarded_relayers_state(lane: TestLaneIdType) -> UnrewardedRelayersState { let inbound_lane_data = crate::InboundLanes::::get(lane).unwrap().0; UnrewardedRelayersState::from(&inbound_lane_data) } @@ -486,24 +490,25 @@ pub fn run_test(test: impl FnOnce() -> T) -> T { /// Since this function changes the runtime storage, you can't "inline" it in the /// `asset_noop` macro calls. pub fn prepare_messages_proof( - messages: Vec, + messages: Vec>, outbound_lane_data: Option, -) -> Box> { +) -> Box> { // first - let's generate storage proof let lane = messages.first().unwrap().key.lane_id; let nonces_start = messages.first().unwrap().key.nonce; let nonces_end = messages.last().unwrap().key.nonce; - let (storage_root, storage_proof) = prepare_messages_storage_proof::( - lane, - nonces_start..=nonces_end, - outbound_lane_data, - UnverifiedStorageProofParams::default(), - |nonce| messages[(nonce - nonces_start) as usize].payload.clone(), - encode_all_messages, - encode_lane_data, - false, - false, - ); + let (storage_root, storage_proof) = + prepare_messages_storage_proof::( + lane, + nonces_start..=nonces_end, + outbound_lane_data, + UnverifiedStorageProofParams::default(), + |nonce| messages[(nonce - nonces_start) as usize].payload.clone(), + encode_all_messages, + encode_lane_data, + false, + false, + ); // let's now insert bridged chain header into the storage let bridged_header_hash = Default::default(); @@ -512,7 +517,7 @@ pub fn prepare_messages_proof( StoredHeaderData { number: 0, state_root: storage_root }, ); - Box::new(FromBridgedChainMessagesProof:: { + Box::new(FromBridgedChainMessagesProof:: { bridged_header_hash, storage_proof, lane, @@ -527,12 +532,12 @@ pub fn prepare_messages_proof( /// Since this function changes the runtime storage, you can't "inline" it in the /// `asset_noop` macro calls. pub fn prepare_messages_delivery_proof( - lane: LaneId, + lane: TestLaneIdType, inbound_lane_data: InboundLaneData, -) -> FromBridgedChainMessagesDeliveryProof { +) -> FromBridgedChainMessagesDeliveryProof { // first - let's generate storage proof let (storage_root, storage_proof) = - prepare_message_delivery_storage_proof::( + prepare_message_delivery_storage_proof::( lane, inbound_lane_data, UnverifiedStorageProofParams::default(), @@ -545,7 +550,7 @@ pub fn prepare_messages_delivery_proof( StoredHeaderData { number: 0, state_root: storage_root }, ); - FromBridgedChainMessagesDeliveryProof:: { + FromBridgedChainMessagesDeliveryProof:: { bridged_header_hash, storage_proof, lane, diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index ceb1744c0665..9df103a7cf6f 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -30,7 +30,7 @@ use bp_messages::{ source_chain::{FromBridgedChainMessagesDeliveryProof, MessagesBridge}, target_chain::{FromBridgedChainMessagesProof, MessageDispatch}, BridgeMessagesCall, ChainWithMessages, DeliveredMessages, InboundLaneData, - InboundMessageDetails, LaneId, LaneState, MessageKey, MessageNonce, MessagesOperatingMode, + InboundMessageDetails, LaneIdType, LaneState, MessageKey, MessageNonce, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState, VerificationError, }; @@ -51,7 +51,7 @@ fn get_ready_for_events() { System::::reset_events(); } -fn send_regular_message(lane_id: LaneId) { +fn send_regular_message(lane_id: TestLaneIdType) { get_ready_for_events(); let outbound_lane = active_outbound_lane::(lane_id).unwrap(); @@ -67,7 +67,10 @@ fn send_regular_message(lane_id: LaneId) { System::::events(), vec![EventRecord { phase: Phase::Initialization, - event: TestEvent::Messages(Event::MessageAccepted { lane_id, nonce: message_nonce }), + event: TestEvent::Messages(Event::MessageAccepted { + lane_id: lane_id.into(), + nonce: message_nonce + }), topics: vec![], }], ); @@ -105,7 +108,7 @@ fn receive_messages_delivery_proof() { vec![EventRecord { phase: Phase::Initialization, event: TestEvent::Messages(Event::MessagesDelivered { - lane_id: test_lane_id(), + lane_id: test_lane_id().into(), messages: DeliveredMessages::new(1), }), topics: vec![], @@ -629,7 +632,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { fn receive_messages_delivery_proof_rejects_invalid_proof() { run_test(|| { let mut proof = prepare_messages_delivery_proof(test_lane_id(), Default::default()); - proof.lane = bp_messages::LaneId::new(42, 84); + proof.lane = TestLaneIdType::try_new(42, 84).unwrap(); assert_noop!( Pallet::::receive_messages_delivery_proof( @@ -1038,8 +1041,8 @@ fn test_bridge_messages_call_is_correctly_defined() { }; let indirect_receive_messages_proof_call = BridgeMessagesCall::< AccountId, - FromBridgedChainMessagesProof, - FromBridgedChainMessagesDeliveryProof, + FromBridgedChainMessagesProof, + FromBridgedChainMessagesDeliveryProof, >::receive_messages_proof { relayer_id_at_bridged_chain: account_id, proof: *message_proof, @@ -1058,8 +1061,8 @@ fn test_bridge_messages_call_is_correctly_defined() { }; let indirect_receive_messages_delivery_proof_call = BridgeMessagesCall::< AccountId, - FromBridgedChainMessagesProof, - FromBridgedChainMessagesDeliveryProof, + FromBridgedChainMessagesProof, + FromBridgedChainMessagesDeliveryProof, >::receive_messages_delivery_proof { proof: message_delivery_proof, relayers_state: unrewarded_relayer_state, @@ -1084,7 +1087,7 @@ fn inbound_storage_extra_proof_size_bytes_works() { fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { RuntimeInboundLaneStorage { - lane_id: LaneId::new(1, 2), + lane_id: TestLaneIdType::try_new(1, 2).unwrap(), cached_data: InboundLaneData { state: LaneState::Opened, relayers: vec![relayer_entry(); relayer_entries].into(), @@ -1165,7 +1168,7 @@ fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { #[test] fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { run_test(|| { - let make_proof = |lane: LaneId| { + let make_proof = |lane: TestLaneIdType| { prepare_messages_delivery_proof( lane, InboundLaneData { diff --git a/bridges/modules/relayers/src/benchmarking.rs b/bridges/modules/relayers/src/benchmarking.rs index 8a3f905a8f29..8fe3fc11d6ae 100644 --- a/bridges/modules/relayers/src/benchmarking.rs +++ b/bridges/modules/relayers/src/benchmarking.rs @@ -20,9 +20,8 @@ use crate::*; -use bp_messages::LaneId; use bp_relayers::RewardsAccountOwner; -use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::One; @@ -30,27 +29,34 @@ use sp_runtime::traits::One; const REWARD_AMOUNT: u32 = u32::MAX; /// Pallet we're benchmarking here. -pub struct Pallet(crate::Pallet); +pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Trait that must be implemented by runtime. -pub trait Config: crate::Config { +pub trait Config: crate::Config { + /// Lane id to use in benchmarks. + fn bench_lane_id() -> Self::LaneId { + Self::LaneId::default() + } /// Prepare environment for paying given reward for serving given lane. - fn prepare_rewards_account(account_params: RewardsAccountParams, reward: Self::Reward); + fn prepare_rewards_account( + account_params: RewardsAccountParams, + reward: Self::Reward, + ); /// Give enough balance to given account. fn deposit_account(account: Self::AccountId, balance: Self::Reward); } -benchmarks! { +benchmarks_instance_pallet! { // Benchmark `claim_rewards` call. claim_rewards { - let lane = LaneId::new(1, 2); + let lane = T::bench_lane_id(); let account_params = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); let relayer: T::AccountId = whitelisted_caller(); let reward = T::Reward::from(REWARD_AMOUNT); T::prepare_rewards_account(account_params, reward); - RelayerRewards::::insert(&relayer, account_params, reward); + RelayerRewards::::insert(&relayer, account_params, reward); }: _(RawOrigin::Signed(relayer), account_params) verify { // we can't check anything here, because `PaymentProcedure` is responsible for @@ -62,30 +68,30 @@ benchmarks! { register { let relayer: T::AccountId = whitelisted_caller(); let valid_till = frame_system::Pallet::::block_number() - .saturating_add(crate::Pallet::::required_registration_lease()) + .saturating_add(crate::Pallet::::required_registration_lease()) .saturating_add(One::one()) .saturating_add(One::one()); - T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); + T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); }: _(RawOrigin::Signed(relayer.clone()), valid_till) verify { - assert!(crate::Pallet::::is_registration_active(&relayer)); + assert!(crate::Pallet::::is_registration_active(&relayer)); } // Benchmark `deregister` call. deregister { let relayer: T::AccountId = whitelisted_caller(); let valid_till = frame_system::Pallet::::block_number() - .saturating_add(crate::Pallet::::required_registration_lease()) + .saturating_add(crate::Pallet::::required_registration_lease()) .saturating_add(One::one()) .saturating_add(One::one()); - T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); - crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); + T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); + crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); frame_system::Pallet::::set_block_number(valid_till.saturating_add(One::one())); }: _(RawOrigin::Signed(relayer.clone())) verify { - assert!(!crate::Pallet::::is_registration_active(&relayer)); + assert!(!crate::Pallet::::is_registration_active(&relayer)); } // Benchmark `slash_and_deregister` method of the pallet. We are adding this weight to @@ -95,36 +101,36 @@ benchmarks! { // prepare and register relayer account let relayer: T::AccountId = whitelisted_caller(); let valid_till = frame_system::Pallet::::block_number() - .saturating_add(crate::Pallet::::required_registration_lease()) + .saturating_add(crate::Pallet::::required_registration_lease()) .saturating_add(One::one()) .saturating_add(One::one()); - T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); - crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); + T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); + crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); // create slash destination account - let lane = LaneId::new(1, 2); + let lane = T::bench_lane_id(); let slash_destination = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); T::prepare_rewards_account(slash_destination, Zero::zero()); }: { - crate::Pallet::::slash_and_deregister(&relayer, slash_destination.into()) + crate::Pallet::::slash_and_deregister(&relayer, slash_destination.into()) } verify { - assert!(!crate::Pallet::::is_registration_active(&relayer)); + assert!(!crate::Pallet::::is_registration_active(&relayer)); } // Benchmark `register_relayer_reward` method of the pallet. We are adding this weight to // the weight of message delivery call if `RefundBridgedParachainMessages` signed extension // is deployed at runtime level. register_relayer_reward { - let lane = LaneId::new(1, 2); + let lane = T::bench_lane_id(); let relayer: T::AccountId = whitelisted_caller(); let account_params = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); }: { - crate::Pallet::::register_relayer_reward(account_params, &relayer, One::one()); + crate::Pallet::::register_relayer_reward(account_params, &relayer, One::one()); } verify { - assert_eq!(RelayerRewards::::get(relayer, &account_params), Some(One::one())); + assert_eq!(RelayerRewards::::get(relayer, &account_params), Some(One::one())); } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) diff --git a/bridges/modules/relayers/src/extension/grandpa_adapter.rs b/bridges/modules/relayers/src/extension/grandpa_adapter.rs index 6c9ae1c2968c..2a8a6e78ef9c 100644 --- a/bridges/modules/relayers/src/extension/grandpa_adapter.rs +++ b/bridges/modules/relayers/src/extension/grandpa_adapter.rs @@ -30,7 +30,7 @@ use pallet_bridge_grandpa::{ SubmitFinalityProofHelper, }; use pallet_bridge_messages::{ - CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf, }; use sp_runtime::{ traits::{Dispatchable, Get}, @@ -54,6 +54,8 @@ pub struct WithGrandpaChainExtensionConfig< BridgeGrandpaPalletInstance, // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension BridgeMessagesPalletInstance, + // instance of `pallet-bridge-relayers`, tracked by this extension + BridgeRelayersPalletInstance, // message delivery transaction priority boost for every additional message PriorityBoostPerMessage, >( @@ -63,20 +65,22 @@ pub struct WithGrandpaChainExtensionConfig< BatchCallUnpacker, BridgeGrandpaPalletInstance, BridgeMessagesPalletInstance, + BridgeRelayersPalletInstance, PriorityBoostPerMessage, )>, ); -impl ExtensionConfig - for WithGrandpaChainExtensionConfig +impl ExtensionConfig + for WithGrandpaChainExtensionConfig where ID: StaticStrProvider, - R: BridgeRelayersConfig + R: BridgeRelayersConfig + BridgeMessagesConfig> + BridgeGrandpaConfig, BCU: BatchCallUnpacker, GI: 'static, MI: 'static, + RI: 'static, P: Get, R::RuntimeCall: Dispatchable + BridgeGrandpaCallSubtype @@ -85,14 +89,15 @@ where type IdProvider = ID; type Runtime = R; type BridgeMessagesPalletInstance = MI; + type BridgeRelayersPalletInstance = RI; type PriorityBoostPerMessage = P; - type Reward = R::Reward; type RemoteGrandpaChainBlockNumber = pallet_bridge_grandpa::BridgedBlockNumber; + type LaneId = LaneIdOf; fn parse_and_check_for_obsolete_call( call: &R::RuntimeCall, ) -> Result< - Option>, + Option>, TransactionValidityError, > { let calls = BCU::unpack(call, 2); @@ -120,12 +125,12 @@ where } fn check_call_result( - call_info: &ExtensionCallInfo, + call_info: &ExtensionCallInfo, call_data: &mut ExtensionCallData, relayer: &R::AccountId, ) -> bool { verify_submit_finality_proof_succeeded::(call_info, call_data, relayer) && - verify_messages_call_succeeded::(call_info, call_data, relayer) + verify_messages_call_succeeded::(call_info, call_data, relayer) } } @@ -134,7 +139,7 @@ where /// /// Only returns false when GRANDPA chain state update call has failed. pub(crate) fn verify_submit_finality_proof_succeeded( - call_info: &ExtensionCallInfo, + call_info: &ExtensionCallInfo, call_data: &mut ExtensionCallData, relayer: &::AccountId, ) -> bool diff --git a/bridges/modules/relayers/src/extension/messages_adapter.rs b/bridges/modules/relayers/src/extension/messages_adapter.rs index ecb575524bb0..e8c2088b7f2d 100644 --- a/bridges/modules/relayers/src/extension/messages_adapter.rs +++ b/bridges/modules/relayers/src/extension/messages_adapter.rs @@ -23,7 +23,7 @@ use bp_relayers::{ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; use bp_runtime::StaticStrProvider; use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; use pallet_bridge_messages::{ - CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf, }; use sp_runtime::{ traits::{Dispatchable, Get}, @@ -37,6 +37,7 @@ pub struct WithMessagesExtensionConfig< IdProvider, Runtime, BridgeMessagesPalletInstance, + BridgeRelayersPalletInstance, PriorityBoostPerMessage, >( PhantomData<( @@ -46,16 +47,19 @@ pub struct WithMessagesExtensionConfig< Runtime, // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension BridgeMessagesPalletInstance, + // instance of `pallet-bridge-relayers`, tracked by this extension + BridgeRelayersPalletInstance, // message delivery transaction priority boost for every additional message PriorityBoostPerMessage, )>, ); -impl ExtensionConfig for WithMessagesExtensionConfig +impl ExtensionConfig for WithMessagesExtensionConfig where ID: StaticStrProvider, - R: BridgeRelayersConfig + BridgeMessagesConfig, + R: BridgeRelayersConfig + BridgeMessagesConfig, MI: 'static, + RI: 'static, P: Get, R::RuntimeCall: Dispatchable + BridgeMessagesCallSubType, @@ -63,14 +67,15 @@ where type IdProvider = ID; type Runtime = R; type BridgeMessagesPalletInstance = MI; + type BridgeRelayersPalletInstance = RI; type PriorityBoostPerMessage = P; - type Reward = R::Reward; type RemoteGrandpaChainBlockNumber = (); + type LaneId = LaneIdOf; fn parse_and_check_for_obsolete_call( call: &R::RuntimeCall, ) -> Result< - Option>, + Option>, TransactionValidityError, > { let call = Self::check_obsolete_parsed_call(call)?; @@ -85,10 +90,10 @@ where } fn check_call_result( - call_info: &ExtensionCallInfo, + call_info: &ExtensionCallInfo, call_data: &mut ExtensionCallData, relayer: &R::AccountId, ) -> bool { - verify_messages_call_succeeded::(call_info, call_data, relayer) + verify_messages_call_succeeded::(call_info, call_data, relayer) } } diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index e1a7abd0ad1c..9a248eb8e798 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -36,7 +36,9 @@ use frame_support::{ CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use frame_system::Config as SystemConfig; -use pallet_bridge_messages::{CallHelper as MessagesCallHelper, Config as BridgeMessagesConfig}; +use pallet_bridge_messages::{ + CallHelper as MessagesCallHelper, Config as BridgeMessagesConfig, LaneIdOf, +}; use pallet_transaction_payment::{ Config as TransactionPaymentConfig, OnChargeTransaction, Pallet as TransactionPaymentPallet, }; @@ -62,15 +64,19 @@ mod priority; /// Data that is crafted in `pre_dispatch` method and used at `post_dispatch`. #[cfg_attr(test, derive(Debug, PartialEq))] -pub struct PreDispatchData { +pub struct PreDispatchData< + AccountId, + RemoteGrandpaChainBlockNumber: Debug, + LaneId: Clone + Copy + Debug, +> { /// Transaction submitter (relayer) account. relayer: AccountId, /// Type of the call. - call_info: ExtensionCallInfo, + call_info: ExtensionCallInfo, } -impl - PreDispatchData +impl + PreDispatchData { /// Returns mutable reference to pre-dispatch `finality_target` sent to the /// `SubmitFinalityProof` call. @@ -88,13 +94,13 @@ impl /// The actions on relayer account that need to be performed because of his actions. #[derive(RuntimeDebug, PartialEq)] -pub enum RelayerAccountAction { +pub enum RelayerAccountAction { /// Do nothing with relayer account. None, /// Reward the relayer. - Reward(AccountId, RewardsAccountParams, Reward), + Reward(AccountId, RewardsAccountParams, Reward), /// Slash the relayer. - Slash(AccountId, RewardsAccountParams), + Slash(AccountId, RewardsAccountParams), } /// A signed extension, built around `pallet-bridge-relayers`. @@ -112,19 +118,22 @@ pub enum RelayerAccountAction { RuntimeDebugNoBound, TypeInfo, )] -#[scale_info(skip_type_params(Runtime, Config))] -pub struct BridgeRelayersSignedExtension(PhantomData<(Runtime, Config)>); +#[scale_info(skip_type_params(Runtime, Config, LaneId))] +pub struct BridgeRelayersSignedExtension( + PhantomData<(Runtime, Config, LaneId)>, +); -impl BridgeRelayersSignedExtension +impl BridgeRelayersSignedExtension where Self: 'static + Send + Sync, - R: RelayersConfig - + BridgeMessagesConfig + R: RelayersConfig + + BridgeMessagesConfig + TransactionPaymentConfig, - C: ExtensionConfig, + C: ExtensionConfig, R::RuntimeCall: Dispatchable, ::OnChargeTransaction: OnChargeTransaction, + LaneId: Clone + Copy + Decode + Encode + Debug + TypeInfo, { /// Returns number of bundled messages `Some(_)`, if the given call info is a: /// @@ -136,7 +145,7 @@ where /// virtually boosted. The relayer registration (we only boost priority for registered /// relayer transactions) must be checked outside. fn bundled_messages_for_priority_boost( - call_info: Option<&ExtensionCallInfo>, + call_info: Option<&ExtensionCallInfo>, ) -> Option { // we only boost priority of message delivery transactions let parsed_call = match call_info { @@ -160,12 +169,14 @@ where /// Given post-dispatch information, analyze the outcome of relayer call and return /// actions that need to be performed on relayer account. fn analyze_call_result( - pre: Option>>, + pre: Option< + Option>, + >, info: &DispatchInfo, post_info: &PostDispatchInfo, len: usize, result: &DispatchResult, - ) -> RelayerAccountAction { + ) -> RelayerAccountAction { // We don't refund anything for transactions that we don't support. let (relayer, call_info) = match pre { Some(Some(pre)) => (pre.relayer, pre.call_info), @@ -263,22 +274,23 @@ where } } -impl SignedExtension for BridgeRelayersSignedExtension +impl SignedExtension for BridgeRelayersSignedExtension where Self: 'static + Send + Sync, - R: RelayersConfig - + BridgeMessagesConfig + R: RelayersConfig + + BridgeMessagesConfig + TransactionPaymentConfig, - C: ExtensionConfig, + C: ExtensionConfig, R::RuntimeCall: Dispatchable, ::OnChargeTransaction: OnChargeTransaction, + LaneId: Clone + Copy + Decode + Encode + Debug + TypeInfo, { const IDENTIFIER: &'static str = C::IdProvider::STR; type AccountId = R::AccountId; type Call = R::RuntimeCall; type AdditionalSigned = (); - type Pre = Option>; + type Pre = Option>; fn additional_signed(&self) -> Result<(), TransactionValidityError> { Ok(()) @@ -392,19 +404,23 @@ where } /// Verify that the messages pallet call, supported by extension has succeeded. -pub(crate) fn verify_messages_call_succeeded( - call_info: &ExtensionCallInfo, +pub(crate) fn verify_messages_call_succeeded( + call_info: &ExtensionCallInfo< + C::RemoteGrandpaChainBlockNumber, + LaneIdOf, + >, _call_data: &mut ExtensionCallData, relayer: &::AccountId, ) -> bool where C: ExtensionConfig, - MI: 'static, - C::Runtime: BridgeMessagesConfig, + C::Runtime: BridgeMessagesConfig, { let messages_call = call_info.messages_call_info(); - if !MessagesCallHelper::::was_successful(messages_call) { + if !MessagesCallHelper::::was_successful( + messages_call, + ) { log::trace!( target: LOG_TARGET, "{}.{:?}: relayer {:?} has submitted invalid messages call", @@ -427,9 +443,9 @@ mod tests { use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, DeliveredMessages, - InboundLaneData, LaneId, MessageNonce, MessagesCallInfo, MessagesOperatingMode, - OutboundLaneData, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, - UnrewardedRelayer, UnrewardedRelayerOccupation, UnrewardedRelayersState, + InboundLaneData, MessageNonce, MessagesCallInfo, MessagesOperatingMode, OutboundLaneData, + ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayer, + UnrewardedRelayerOccupation, UnrewardedRelayersState, }; use bp_parachains::{BestParaHeadHash, ParaInfo, SubmitParachainHeadsInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; @@ -454,17 +470,16 @@ mod tests { parameter_types! { TestParachain: u32 = BridgedUnderlyingParachain::PARACHAIN_ID; - pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::ThisChain, ); - pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain, ); - pub TestLaneId: LaneId = test_lane_id(); } bp_runtime::generate_static_str_provider!(TestGrandpaExtension); @@ -477,31 +492,31 @@ mod tests { RuntimeWithUtilityPallet, (), (), + (), ConstU64<1>, >; type TestGrandpaExtension = - BridgeRelayersSignedExtension; + BridgeRelayersSignedExtension; type TestExtensionConfig = parachain_adapter::WithParachainExtensionConfig< StrTestExtension, TestRuntime, RuntimeWithUtilityPallet, (), (), + (), ConstU64<1>, >; - type TestExtension = BridgeRelayersSignedExtension; + type TestExtension = + BridgeRelayersSignedExtension; type TestMessagesExtensionConfig = messages_adapter::WithMessagesExtensionConfig< StrTestMessagesExtension, TestRuntime, (), + (), ConstU64<1>, >; type TestMessagesExtension = - BridgeRelayersSignedExtension; - - fn test_lane_id() -> LaneId { - LaneId::new(1, 2) - } + BridgeRelayersSignedExtension; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = Stake::get(); @@ -795,7 +810,7 @@ mod tests { } fn all_finality_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::AllFinalityAndMsgs( @@ -832,14 +847,14 @@ mod tests { #[cfg(test)] fn all_finality_pre_dispatch_data_ex( - ) -> PreDispatchData { + ) -> PreDispatchData { let mut data = all_finality_pre_dispatch_data(); data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } fn all_finality_confirmation_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::AllFinalityAndMsgs( @@ -869,14 +884,14 @@ mod tests { } fn all_finality_confirmation_pre_dispatch_data_ex( - ) -> PreDispatchData { + ) -> PreDispatchData { let mut data = all_finality_confirmation_pre_dispatch_data(); data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } fn relay_finality_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::RelayFinalityAndMsgs( @@ -906,14 +921,14 @@ mod tests { } fn relay_finality_pre_dispatch_data_ex( - ) -> PreDispatchData { + ) -> PreDispatchData { let mut data = relay_finality_pre_dispatch_data(); data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } fn relay_finality_confirmation_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::RelayFinalityAndMsgs( @@ -937,14 +952,14 @@ mod tests { } fn relay_finality_confirmation_pre_dispatch_data_ex( - ) -> PreDispatchData { + ) -> PreDispatchData { let mut data = relay_finality_confirmation_pre_dispatch_data(); data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } fn parachain_finality_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::ParachainFinalityAndMsgs( @@ -972,7 +987,7 @@ mod tests { } fn parachain_finality_confirmation_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::ParachainFinalityAndMsgs( @@ -994,7 +1009,7 @@ mod tests { } fn delivery_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( @@ -1016,7 +1031,7 @@ mod tests { } fn confirmation_pre_dispatch_data( - ) -> PreDispatchData { + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( @@ -1030,9 +1045,13 @@ mod tests { } fn set_bundled_range_end( - mut pre_dispatch_data: PreDispatchData, + mut pre_dispatch_data: PreDispatchData< + ThisChainAccountId, + BridgedChainBlockNumber, + TestLaneIdType, + >, end: MessageNonce, - ) -> PreDispatchData { + ) -> PreDispatchData { let msg_info = match pre_dispatch_data.call_info { ExtensionCallInfo::AllFinalityAndMsgs(_, _, ref mut info) => info, ExtensionCallInfo::RelayFinalityAndMsgs(_, ref mut info) => info, @@ -1072,7 +1091,7 @@ mod tests { fn run_pre_dispatch( call: RuntimeCall, ) -> Result< - Option>, + Option>, TransactionValidityError, > { sp_tracing::try_init_simple(); @@ -1083,7 +1102,7 @@ mod tests { fn run_grandpa_pre_dispatch( call: RuntimeCall, ) -> Result< - Option>, + Option>, TransactionValidityError, > { let extension: TestGrandpaExtension = BridgeRelayersSignedExtension(PhantomData); @@ -1092,7 +1111,10 @@ mod tests { fn run_messages_pre_dispatch( call: RuntimeCall, - ) -> Result>, TransactionValidityError> { + ) -> Result< + Option>, + TransactionValidityError, + > { let extension: TestMessagesExtension = BridgeRelayersSignedExtension(PhantomData); extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } @@ -1113,7 +1135,9 @@ mod tests { } fn run_post_dispatch( - pre_dispatch_data: Option>, + pre_dispatch_data: Option< + PreDispatchData, + >, dispatch_result: DispatchResult, ) { let post_dispatch_result = TestExtension::post_dispatch( @@ -1886,9 +1910,13 @@ mod tests { } fn run_analyze_call_result( - pre_dispatch_data: PreDispatchData, + pre_dispatch_data: PreDispatchData< + ThisChainAccountId, + BridgedChainBlockNumber, + TestLaneIdType, + >, dispatch_result: DispatchResult, - ) -> RelayerAccountAction { + ) -> RelayerAccountAction { TestExtension::analyze_call_result( Some(Some(pre_dispatch_data)), &dispatch_info(), @@ -2318,7 +2346,7 @@ mod tests { .unwrap(); // allow empty message delivery transactions - let lane_id = TestLaneId::get(); + let lane_id = test_lane_id(); let in_lane_data = InboundLaneData { last_confirmed_nonce: 0, relayers: vec![UnrewardedRelayer { diff --git a/bridges/modules/relayers/src/extension/parachain_adapter.rs b/bridges/modules/relayers/src/extension/parachain_adapter.rs index b6f57cebc309..69cf766dd674 100644 --- a/bridges/modules/relayers/src/extension/parachain_adapter.rs +++ b/bridges/modules/relayers/src/extension/parachain_adapter.rs @@ -32,7 +32,7 @@ use pallet_bridge_grandpa::{ CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig, }; use pallet_bridge_messages::{ - CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf, }; use pallet_bridge_parachains::{ CallSubType as BridgeParachainsCallSubtype, Config as BridgeParachainsConfig, @@ -58,6 +58,8 @@ pub struct WithParachainExtensionConfig< BridgeParachainsPalletInstance, // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension BridgeMessagesPalletInstance, + // instance of `pallet-bridge-relayers`, tracked by this extension + BridgeRelayersPalletInstance, // message delivery transaction priority boost for every additional message PriorityBoostPerMessage, >( @@ -67,20 +69,23 @@ pub struct WithParachainExtensionConfig< BatchCallUnpacker, BridgeParachainsPalletInstance, BridgeMessagesPalletInstance, + BridgeRelayersPalletInstance, PriorityBoostPerMessage, )>, ); -impl ExtensionConfig for WithParachainExtensionConfig +impl ExtensionConfig + for WithParachainExtensionConfig where ID: StaticStrProvider, - R: BridgeRelayersConfig + R: BridgeRelayersConfig + BridgeMessagesConfig + BridgeParachainsConfig + BridgeGrandpaConfig, BCU: BatchCallUnpacker, PI: 'static, MI: 'static, + RI: 'static, P: Get, R::RuntimeCall: Dispatchable + BridgeGrandpaCallSubtype @@ -91,15 +96,16 @@ where type IdProvider = ID; type Runtime = R; type BridgeMessagesPalletInstance = MI; + type BridgeRelayersPalletInstance = RI; type PriorityBoostPerMessage = P; - type Reward = R::Reward; type RemoteGrandpaChainBlockNumber = pallet_bridge_grandpa::BridgedBlockNumber; + type LaneId = LaneIdOf; fn parse_and_check_for_obsolete_call( call: &R::RuntimeCall, ) -> Result< - Option>, + Option>, TransactionValidityError, > { let calls = BCU::unpack(call, 3); @@ -109,7 +115,7 @@ where let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info()); let para_finality_call = calls.next().transpose()?.and_then(|c| { let r = c.submit_parachain_heads_info_for( - >::BridgedChain::PARACHAIN_ID, + >::BridgedChain::PARACHAIN_ID, ); r }); @@ -139,14 +145,14 @@ where } fn check_call_result( - call_info: &ExtensionCallInfo, + call_info: &ExtensionCallInfo, call_data: &mut ExtensionCallData, relayer: &R::AccountId, ) -> bool { verify_submit_finality_proof_succeeded::( call_info, call_data, relayer, ) && verify_submit_parachain_head_succeeded::(call_info, call_data, relayer) && - verify_messages_call_succeeded::(call_info, call_data, relayer) + verify_messages_call_succeeded::(call_info, call_data, relayer) } } @@ -155,7 +161,7 @@ where /// /// Only returns false when parachain state update call has failed. pub(crate) fn verify_submit_parachain_head_succeeded( - call_info: &ExtensionCallInfo, + call_info: &ExtensionCallInfo, _call_data: &mut ExtensionCallData, relayer: &::AccountId, ) -> bool diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index b9627774db1e..f06c2e16ac24 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -43,6 +43,7 @@ mod weights_ext; pub mod benchmarking; pub mod extension; +pub mod migration; pub mod weights; /// The target that will be used when publishing logs related to this pallet. @@ -51,46 +52,58 @@ pub const LOG_TARGET: &str = "runtime::bridge-relayers"; #[frame_support::pallet] pub mod pallet { use super::*; + use bp_messages::LaneIdType; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; /// `RelayerRewardsKeyProvider` for given configuration. - type RelayerRewardsKeyProviderOf = - RelayerRewardsKeyProvider<::AccountId, ::Reward>; + type RelayerRewardsKeyProviderOf = RelayerRewardsKeyProvider< + ::AccountId, + >::Reward, + >::LaneId, + >; #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config { /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Type of relayer reward. type Reward: AtLeast32BitUnsigned + Copy + Member + Parameter + MaxEncodedLen; /// Pay rewards scheme. - type PaymentProcedure: PaymentProcedure; + type PaymentProcedure: PaymentProcedure< + Self::AccountId, + Self::Reward, + LaneId = Self::LaneId, + >; /// Stake and slash scheme. type StakeAndSlash: StakeAndSlash, Self::Reward>; /// Pallet call weights. type WeightInfo: WeightInfoExt; + /// Lane identifier type. + type LaneId: LaneIdType + Send + Sync; } #[pallet::pallet] - pub struct Pallet(PhantomData); + #[pallet::storage_version(migration::STORAGE_VERSION)] + pub struct Pallet(PhantomData<(T, I)>); #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Claim accumulated rewards. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::claim_rewards())] pub fn claim_rewards( origin: OriginFor, - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, ) -> DispatchResult { let relayer = ensure_signed(origin)?; - RelayerRewards::::try_mutate_exists( + RelayerRewards::::try_mutate_exists( &relayer, rewards_account_params, |maybe_reward| -> DispatchResult { - let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; + let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; T::PaymentProcedure::pay_reward(&relayer, rewards_account_params, reward) .map_err(|e| { log::trace!( @@ -100,10 +113,10 @@ pub mod pallet { relayer, e, ); - Error::::FailedToPayReward + Error::::FailedToPayReward })?; - Self::deposit_event(Event::::RewardPaid { + Self::deposit_event(Event::::RewardPaid { relayer: relayer.clone(), rewards_account_params, reward, @@ -125,53 +138,57 @@ pub mod pallet { // than the `RequiredRegistrationLease` let lease = valid_till.saturating_sub(frame_system::Pallet::::block_number()); ensure!( - lease > Pallet::::required_registration_lease(), - Error::::InvalidRegistrationLease + lease > Self::required_registration_lease(), + Error::::InvalidRegistrationLease ); - RegisteredRelayers::::try_mutate(&relayer, |maybe_registration| -> DispatchResult { - let mut registration = maybe_registration - .unwrap_or_else(|| Registration { valid_till, stake: Zero::zero() }); + RegisteredRelayers::::try_mutate( + &relayer, + |maybe_registration| -> DispatchResult { + let mut registration = maybe_registration + .unwrap_or_else(|| Registration { valid_till, stake: Zero::zero() }); + + // new `valid_till` must be larger (or equal) than the old one + ensure!( + valid_till >= registration.valid_till, + Error::::CannotReduceRegistrationLease, + ); + registration.valid_till = valid_till; + + // regarding stake, there are three options: + // - if relayer stake is larger than required stake, we may do unreserve + // - if relayer stake equals to required stake, we do nothing + // - if relayer stake is smaller than required stake, we do additional reserve + let required_stake = Self::required_stake(); + if let Some(to_unreserve) = registration.stake.checked_sub(&required_stake) { + Self::do_unreserve(&relayer, to_unreserve)?; + } else if let Some(to_reserve) = required_stake.checked_sub(®istration.stake) + { + T::StakeAndSlash::reserve(&relayer, to_reserve).map_err(|e| { + log::trace!( + target: LOG_TARGET, + "Failed to reserve {:?} on relayer {:?} account: {:?}", + to_reserve, + relayer, + e, + ); - // new `valid_till` must be larger (or equal) than the old one - ensure!( - valid_till >= registration.valid_till, - Error::::CannotReduceRegistrationLease, - ); - registration.valid_till = valid_till; - - // regarding stake, there are three options: - // - if relayer stake is larger than required stake, we may do unreserve - // - if relayer stake equals to required stake, we do nothing - // - if relayer stake is smaller than required stake, we do additional reserve - let required_stake = Pallet::::required_stake(); - if let Some(to_unreserve) = registration.stake.checked_sub(&required_stake) { - Self::do_unreserve(&relayer, to_unreserve)?; - } else if let Some(to_reserve) = required_stake.checked_sub(®istration.stake) { - T::StakeAndSlash::reserve(&relayer, to_reserve).map_err(|e| { - log::trace!( - target: LOG_TARGET, - "Failed to reserve {:?} on relayer {:?} account: {:?}", - to_reserve, - relayer, - e, - ); - - Error::::FailedToReserve - })?; - } - registration.stake = required_stake; - - log::trace!(target: LOG_TARGET, "Successfully registered relayer: {:?}", relayer); - Self::deposit_event(Event::::RegistrationUpdated { - relayer: relayer.clone(), - registration, - }); - - *maybe_registration = Some(registration); - - Ok(()) - }) + Error::::FailedToReserve + })?; + } + registration.stake = required_stake; + + log::trace!(target: LOG_TARGET, "Successfully registered relayer: {:?}", relayer); + Self::deposit_event(Event::::RegistrationUpdated { + relayer: relayer.clone(), + registration, + }); + + *maybe_registration = Some(registration); + + Ok(()) + }, + ) } /// `Deregister` relayer. @@ -183,34 +200,37 @@ pub mod pallet { pub fn deregister(origin: OriginFor) -> DispatchResult { let relayer = ensure_signed(origin)?; - RegisteredRelayers::::try_mutate(&relayer, |maybe_registration| -> DispatchResult { - let registration = match maybe_registration.take() { - Some(registration) => registration, - None => fail!(Error::::NotRegistered), - }; - - // we can't deregister until `valid_till + 1` - ensure!( - registration.valid_till < frame_system::Pallet::::block_number(), - Error::::RegistrationIsStillActive, - ); + RegisteredRelayers::::try_mutate( + &relayer, + |maybe_registration| -> DispatchResult { + let registration = match maybe_registration.take() { + Some(registration) => registration, + None => fail!(Error::::NotRegistered), + }; + + // we can't deregister until `valid_till + 1` + ensure!( + registration.valid_till < frame_system::Pallet::::block_number(), + Error::::RegistrationIsStillActive, + ); - // if stake is non-zero, we should do unreserve - if !registration.stake.is_zero() { - Self::do_unreserve(&relayer, registration.stake)?; - } + // if stake is non-zero, we should do unreserve + if !registration.stake.is_zero() { + Self::do_unreserve(&relayer, registration.stake)?; + } - log::trace!(target: LOG_TARGET, "Successfully deregistered relayer: {:?}", relayer); - Self::deposit_event(Event::::Deregistered { relayer: relayer.clone() }); + log::trace!(target: LOG_TARGET, "Successfully deregistered relayer: {:?}", relayer); + Self::deposit_event(Event::::Deregistered { relayer: relayer.clone() }); - *maybe_registration = None; + *maybe_registration = None; - Ok(()) - }) + Ok(()) + }, + ) } } - impl Pallet { + impl, I: 'static> Pallet { /// Returns true if given relayer registration is active at current block. /// /// This call respects both `RequiredStake` and `RequiredRegistrationLease`, meaning that @@ -243,9 +263,9 @@ pub mod pallet { /// It may fail inside, but error is swallowed and we only log it. pub fn slash_and_deregister( relayer: &T::AccountId, - slash_destination: ExplicitOrAccountParams, + slash_destination: ExplicitOrAccountParams, ) { - let registration = match RegisteredRelayers::::take(relayer) { + let registration = match RegisteredRelayers::::take(relayer) { Some(registration) => registration, None => { log::trace!( @@ -304,7 +324,7 @@ pub mod pallet { /// Register reward for given relayer. pub fn register_relayer_reward( - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, relayer: &T::AccountId, reward: T::Reward, ) { @@ -312,7 +332,7 @@ pub mod pallet { return } - RelayerRewards::::mutate( + RelayerRewards::::mutate( relayer, rewards_account_params, |old_reward: &mut Option| { @@ -327,7 +347,7 @@ pub mod pallet { new_reward, ); - Self::deposit_event(Event::::RewardRegistered { + Self::deposit_event(Event::::RewardRegistered { relayer: relayer.clone(), rewards_account_params, reward, @@ -366,7 +386,7 @@ pub mod pallet { relayer, ); - fail!(Error::::FailedToUnreserve) + fail!(Error::::FailedToUnreserve) } Ok(()) @@ -375,13 +395,13 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// Relayer reward has been registered and may be claimed later. RewardRegistered { /// Relayer account that can claim reward. relayer: T::AccountId, /// Relayer can claim reward from this account. - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, /// Reward amount. reward: T::Reward, }, @@ -390,7 +410,7 @@ pub mod pallet { /// Relayer account that has been rewarded. relayer: T::AccountId, /// Relayer has received reward from this account. - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, /// Reward amount. reward: T::Reward, }, @@ -416,7 +436,7 @@ pub mod pallet { } #[pallet::error] - pub enum Error { + pub enum Error { /// No reward can be claimed by given relayer. NoRewardForRelayer, /// Reward payment procedure has failed. @@ -439,13 +459,13 @@ pub mod pallet { /// Map of the relayer => accumulated reward. #[pallet::storage] #[pallet::getter(fn relayer_reward)] - pub type RelayerRewards = StorageDoubleMap< + pub type RelayerRewards, I: 'static = ()> = StorageDoubleMap< _, - as StorageDoubleMapKeyProvider>::Hasher1, - as StorageDoubleMapKeyProvider>::Key1, - as StorageDoubleMapKeyProvider>::Hasher2, - as StorageDoubleMapKeyProvider>::Key2, - as StorageDoubleMapKeyProvider>::Value, + as StorageDoubleMapKeyProvider>::Hasher1, + as StorageDoubleMapKeyProvider>::Key1, + as StorageDoubleMapKeyProvider>::Hasher2, + as StorageDoubleMapKeyProvider>::Key2, + as StorageDoubleMapKeyProvider>::Value, OptionQuery, >; @@ -457,7 +477,7 @@ pub mod pallet { /// relayer is present. #[pallet::storage] #[pallet::getter(fn registered_relayer)] - pub type RegisteredRelayers = StorageMap< + pub type RegisteredRelayers, I: 'static = ()> = StorageMap< _, Blake2_128Concat, T::AccountId, @@ -469,10 +489,10 @@ pub mod pallet { #[cfg(test)] mod tests { use super::*; + use bp_messages::LaneIdType; use mock::{RuntimeEvent as TestEvent, *}; use crate::Event::{RewardPaid, RewardRegistered}; - use bp_messages::LaneId; use bp_relayers::RewardsAccountOwner; use frame_support::{ assert_noop, assert_ok, @@ -596,16 +616,16 @@ mod tests { fn pay_reward_from_account_actually_pays_reward() { type Balances = pallet_balances::Pallet; type PayLaneRewardFromAccount = - bp_relayers::PayRewardFromAccount; + bp_relayers::PayRewardFromAccount; run_test(|| { let in_lane_0 = RewardsAccountParams::new( - LaneId::new(1, 2), + TestLaneIdType::try_new(1, 2).unwrap(), *b"test", RewardsAccountOwner::ThisChain, ); let out_lane_1 = RewardsAccountParams::new( - LaneId::new(1, 3), + TestLaneIdType::try_new(1, 3).unwrap(), *b"test", RewardsAccountOwner::BridgedChain, ); diff --git a/bridges/modules/relayers/src/migration.rs b/bridges/modules/relayers/src/migration.rs new file mode 100644 index 000000000000..8bf473b300c2 --- /dev/null +++ b/bridges/modules/relayers/src/migration.rs @@ -0,0 +1,243 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! A module that is responsible for migration of storage. + +use frame_support::{ + traits::{Get, StorageVersion}, + weights::Weight, +}; + +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + +/// This module contains data structures that are valid for the initial state of `0`. +/// (used with v1 migration). +pub mod v0 { + use crate::{Config, Pallet}; + use bp_relayers::RewardsAccountOwner; + use bp_runtime::{ChainId, StorageDoubleMapKeyProvider}; + use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; + use frame_support::{pallet_prelude::OptionQuery, Blake2_128Concat, Identity}; + use scale_info::TypeInfo; + use sp_runtime::traits::AccountIdConversion; + use sp_std::marker::PhantomData; + + /// Structure used to identify the account that pays a reward to the relayer. + #[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] + pub struct RewardsAccountParams { + /// lane_id + pub lane_id: LaneId, + /// bridged_chain_id + pub bridged_chain_id: ChainId, + /// owner + pub owner: RewardsAccountOwner, + } + + impl RewardsAccountParams { + /// Create a new instance of `RewardsAccountParams`. + pub const fn new( + lane_id: LaneId, + bridged_chain_id: ChainId, + owner: RewardsAccountOwner, + ) -> Self { + Self { lane_id, bridged_chain_id, owner } + } + } + + impl sp_runtime::TypeId for RewardsAccountParams { + const TYPE_ID: [u8; 4] = *b"brap"; + } + + pub(crate) struct RelayerRewardsKeyProvider( + PhantomData<(AccountId, Reward, LaneId)>, + ); + + impl StorageDoubleMapKeyProvider + for RelayerRewardsKeyProvider + where + AccountId: 'static + Codec + EncodeLike + Send + Sync, + Reward: 'static + Codec + EncodeLike + Send + Sync, + LaneId: Codec + EncodeLike + Send + Sync, + { + const MAP_NAME: &'static str = "RelayerRewards"; + + type Hasher1 = Blake2_128Concat; + type Key1 = AccountId; + type Hasher2 = Identity; + type Key2 = RewardsAccountParams; + type Value = Reward; + } + + pub(crate) type RelayerRewardsKeyProviderOf = RelayerRewardsKeyProvider< + ::AccountId, + >::Reward, + >::LaneId, + >; + + #[frame_support::storage_alias] + pub(crate) type RelayerRewards, I: 'static> = StorageDoubleMap< + Pallet, + as StorageDoubleMapKeyProvider>::Hasher1, + as StorageDoubleMapKeyProvider>::Key1, + as StorageDoubleMapKeyProvider>::Hasher2, + as StorageDoubleMapKeyProvider>::Key2, + as StorageDoubleMapKeyProvider>::Value, + OptionQuery, + >; + + /// Reward account generator for `v0`. + pub struct PayRewardFromAccount(PhantomData<(Account, LaneId)>); + impl PayRewardFromAccount + where + Account: Decode + Encode, + LaneId: Decode + Encode, + { + /// Return account that pays rewards based on the provided parameters. + pub fn rewards_account(params: RewardsAccountParams) -> Account { + params.into_sub_account_truncating(b"rewards-account") + } + } +} + +/// This migration updates `RelayerRewards` where `RewardsAccountParams` was used as the key with +/// `lane_id` as the first attribute, which affects `into_sub_account_truncating`. We are migrating +/// this key to use the new `RewardsAccountParams` where `lane_id` is the last attribute. +pub mod v1 { + use super::*; + use crate::{Config, Pallet}; + use bp_relayers::RewardsAccountParams; + use frame_support::traits::UncheckedOnRuntimeUpgrade; + use sp_std::marker::PhantomData; + + #[cfg(feature = "try-runtime")] + use crate::RelayerRewards; + + /// Migrates the pallet storage to v1. + pub struct UncheckedMigrationV0ToV1(PhantomData<(T, I)>); + + #[cfg(feature = "try-runtime")] + const LOG_TARGET: &str = "runtime::bridge-relayers-migration"; + + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrationV0ToV1 { + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // list all rewards (we cannot do this as one step because of `drain` limitation) + let mut rewards_to_migrate = + sp_std::vec::Vec::with_capacity(v0::RelayerRewards::::iter().count()); + for (key1, key2, reward) in v0::RelayerRewards::::drain() { + rewards_to_migrate.push((key1, key2, reward)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + + // re-register rewards with new format of `RewardsAccountParams`. + for (key1, key2, reward) in rewards_to_migrate { + // expand old key + let v0::RewardsAccountParams { owner, lane_id, bridged_chain_id } = key2; + + // re-register reward + Pallet::::register_relayer_reward( + v1::RewardsAccountParams::new(lane_id, bridged_chain_id, owner), + &key1, + reward, + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + use codec::Encode; + use frame_support::BoundedBTreeMap; + use sp_runtime::traits::ConstU32; + + // collect actual rewards + let mut rewards: BoundedBTreeMap< + (T::AccountId, T::LaneId), + T::Reward, + ConstU32<{ u32::MAX }>, + > = BoundedBTreeMap::new(); + for (key1, key2, reward) in v0::RelayerRewards::::iter() { + log::info!(target: LOG_TARGET, "Reward to migrate: {key1:?}::{key2:?} - {reward:?}"); + rewards = rewards + .try_mutate(|inner| { + inner + .entry((key1.clone(), key2.lane_id)) + .and_modify(|value| *value += reward) + .or_insert(reward); + }) + .unwrap(); + } + log::info!(target: LOG_TARGET, "Found total rewards to migrate: {rewards:?}"); + + Ok(rewards.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: sp_std::vec::Vec) -> Result<(), sp_runtime::DispatchError> { + use codec::Decode; + use frame_support::BoundedBTreeMap; + use sp_runtime::traits::ConstU32; + + let rewards_before: BoundedBTreeMap< + (T::AccountId, T::LaneId), + T::Reward, + ConstU32<{ u32::MAX }>, + > = Decode::decode(&mut &state[..]).unwrap(); + + // collect migrated rewards + let mut rewards_after: BoundedBTreeMap< + (T::AccountId, T::LaneId), + T::Reward, + ConstU32<{ u32::MAX }>, + > = BoundedBTreeMap::new(); + for (key1, key2, reward) in v1::RelayerRewards::::iter() { + log::info!(target: LOG_TARGET, "Migrated rewards: {key1:?}::{key2:?} - {reward:?}"); + rewards_after = rewards_after + .try_mutate(|inner| { + inner + .entry((key1.clone(), *key2.lane_id())) + .and_modify(|value| *value += reward) + .or_insert(reward); + }) + .unwrap(); + } + log::info!(target: LOG_TARGET, "Found total migrated rewards: {rewards_after:?}"); + + frame_support::ensure!( + rewards_before == rewards_after, + "The rewards were not migrated correctly!." + ); + + log::info!(target: LOG_TARGET, "migrated all."); + Ok(()) + } + } + + /// [`UncheckedMigrationV0ToV1`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. + pub type MigrationToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + UncheckedMigrationV0ToV1, + Pallet, + ::DbWeight, + >; +} diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index de1d292b7c0f..d186e968e648 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -21,7 +21,7 @@ use crate as pallet_bridge_relayers; use bp_header_chain::ChainWithGrandpa; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - ChainWithMessages, LaneId, MessageNonce, + ChainWithMessages, HashedLaneId, LaneIdType, MessageNonce, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::{ @@ -75,6 +75,13 @@ pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; /// Maximal extrinsic size at the `BridgedChain`. pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; +/// Lane that we're using in tests. +pub fn test_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 2).unwrap() +} + /// Underlying chain of `ThisChain`. pub struct ThisUnderlyingChain; @@ -253,10 +260,10 @@ impl pallet_bridge_messages::Config for TestRuntime { type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; type OutboundPayload = Vec; - type InboundPayload = Vec; - type DeliveryPayments = (); + type LaneId = TestLaneIdType; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, (), @@ -276,15 +283,20 @@ impl pallet_bridge_relayers::Config for TestRuntime { type PaymentProcedure = TestPaymentProcedure; type StakeAndSlash = TestStakeAndSlash; type WeightInfo = (); + type LaneId = TestLaneIdType; } #[cfg(feature = "runtime-benchmarks")] impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { - fn prepare_rewards_account(account_params: RewardsAccountParams, reward: ThisChainBalance) { - let rewards_account = - bp_relayers::PayRewardFromAccount::::rewards_account( - account_params, - ); + fn prepare_rewards_account( + account_params: RewardsAccountParams, + reward: Self::Reward, + ) { + let rewards_account = bp_relayers::PayRewardFromAccount::< + Balances, + ThisChainAccountId, + Self::LaneId, + >::rewards_account(account_params); Self::deposit_account(rewards_account, reward); } @@ -306,17 +318,18 @@ pub const REGISTER_RELAYER: ThisChainAccountId = 42; pub struct TestPaymentProcedure; impl TestPaymentProcedure { - pub fn rewards_account(params: RewardsAccountParams) -> ThisChainAccountId { - PayRewardFromAccount::<(), ThisChainAccountId>::rewards_account(params) + pub fn rewards_account(params: RewardsAccountParams) -> ThisChainAccountId { + PayRewardFromAccount::<(), ThisChainAccountId, TestLaneIdType>::rewards_account(params) } } impl PaymentProcedure for TestPaymentProcedure { type Error = (); + type LaneId = TestLaneIdType; fn pay_reward( relayer: &ThisChainAccountId, - _lane_id: RewardsAccountParams, + _lane_id: RewardsAccountParams, _reward: ThisChainBalance, ) -> Result<(), Self::Error> { match *relayer { @@ -330,7 +343,7 @@ impl PaymentProcedure for TestPaymentProce pub struct DummyMessageDispatch; impl DummyMessageDispatch { - pub fn deactivate(lane: LaneId) { + pub fn deactivate(lane: TestLaneIdType) { frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); } } @@ -338,26 +351,33 @@ impl DummyMessageDispatch { impl MessageDispatch for DummyMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); + type LaneId = TestLaneIdType; - fn is_active(lane: LaneId) -> bool { + fn is_active(lane: Self::LaneId) -> bool { frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != Some(false) } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::zero() } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } } /// Reward account params that we are using in tests. -pub fn test_reward_account_param() -> RewardsAccountParams { - RewardsAccountParams::new(LaneId::new(1, 2), *b"test", RewardsAccountOwner::ThisChain) +pub fn test_reward_account_param() -> RewardsAccountParams { + RewardsAccountParams::new( + TestLaneIdType::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain, + ) } /// Return test externalities to use in tests. diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index 3693793a3e5c..5383cba5ecbd 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -20,11 +20,12 @@ use crate::{Config, Pallet}; use bp_messages::{ source_chain::{DeliveryConfirmationPayments, RelayersRewards}, - LaneId, MessageNonce, + MessageNonce, }; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::Chain; use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; +use pallet_bridge_messages::LaneIdOf; use sp_arithmetic::traits::{Saturating, Zero}; use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; @@ -34,17 +35,17 @@ pub struct DeliveryConfirmationPaymentsAdapter( PhantomData<(T, MI, DeliveryReward)>, ); -impl DeliveryConfirmationPayments +impl DeliveryConfirmationPayments> for DeliveryConfirmationPaymentsAdapter where - T: Config + pallet_bridge_messages::Config, + T: Config + pallet_bridge_messages::Config::LaneId>, MI: 'static, DeliveryReward: Get, { type Error = &'static str; fn pay_reward( - lane_id: LaneId, + lane_id: LaneIdOf, messages_relayers: VecDeque>, confirmation_relayer: &T::AccountId, received_range: &RangeInclusive, @@ -72,7 +73,7 @@ where fn register_relayers_rewards( confirmation_relayer: &T::AccountId, relayers_rewards: RelayersRewards, - lane_id: RewardsAccountParams, + lane_id: RewardsAccountParams, delivery_fee: T::Reward, ) { // reward every relayer except `confirmation_relayer` diff --git a/bridges/modules/relayers/src/stake_adapter.rs b/bridges/modules/relayers/src/stake_adapter.rs index 0c965e9e6bff..1792f0be8316 100644 --- a/bridges/modules/relayers/src/stake_adapter.rs +++ b/bridges/modules/relayers/src/stake_adapter.rs @@ -18,7 +18,7 @@ //! mechanism of the relayers pallet. use bp_relayers::{ExplicitOrAccountParams, PayRewardFromAccount, StakeAndSlash}; -use codec::Codec; +use codec::{Codec, Decode, Encode}; use frame_support::traits::{tokens::BalanceStatus, NamedReservableCurrency}; use sp_runtime::{traits::Get, DispatchError, DispatchResult}; use sp_std::{fmt::Debug, marker::PhantomData}; @@ -53,15 +53,15 @@ where Currency::unreserve_named(&ReserveId::get(), relayer, amount) } - fn repatriate_reserved( + fn repatriate_reserved( relayer: &AccountId, - beneficiary: ExplicitOrAccountParams, + beneficiary: ExplicitOrAccountParams, amount: Currency::Balance, ) -> Result { let beneficiary_account = match beneficiary { ExplicitOrAccountParams::Explicit(account) => account, ExplicitOrAccountParams::Params(params) => - PayRewardFromAccount::<(), AccountId>::rewards_account(params), + PayRewardFromAccount::<(), AccountId, LaneId>::rewards_account(params), }; Currency::repatriate_reserved_named( &ReserveId::get(), diff --git a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs index 2412bb0f3bb0..dd855c7069aa 100644 --- a/bridges/modules/xcm-bridge-hub/src/dispatcher.rs +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -23,10 +23,7 @@ use crate::{Config, Pallet, LOG_TARGET}; -use bp_messages::{ - target_chain::{DispatchMessage, MessageDispatch}, - LaneId, -}; +use bp_messages::target_chain::{DispatchMessage, MessageDispatch}; use bp_runtime::messages::MessageDispatchResult; use bp_xcm_bridge_hub::{LocalXcmChannelManager, XcmAsPlainPayload}; use codec::{Decode, Encode}; @@ -58,15 +55,18 @@ where { type DispatchPayload = XcmAsPlainPayload; type DispatchLevelResult = XcmBlobMessageDispatchResult; + type LaneId = T::LaneId; - fn is_active(lane: LaneId) -> bool { + fn is_active(lane: Self::LaneId) -> bool { Pallet::::bridge_by_lane_id(&lane) .and_then(|(_, bridge)| bridge.bridge_origin_relative_location.try_as().cloned().ok()) .map(|recipient: Location| !T::LocalXcmChannelManager::is_congested(&recipient)) .unwrap_or(false) } - fn dispatch_weight(message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + message: &mut DispatchMessage, + ) -> Weight { match message.data.payload { Ok(ref payload) => { let payload_size = payload.encoded_size().saturated_into(); @@ -77,14 +77,14 @@ where } fn dispatch( - message: DispatchMessage, + message: DispatchMessage, ) -> MessageDispatchResult { let payload = match message.data.payload { Ok(payload) => payload, Err(e) => { log::error!( target: LOG_TARGET, - "dispatch - payload error: {e:?} for lane_id: {} and message_nonce: {:?}", + "dispatch - payload error: {e:?} for lane_id: {:?} and message_nonce: {:?}", message.key.lane_id, message.key.nonce ); @@ -98,7 +98,7 @@ where Ok(_) => { log::debug!( target: LOG_TARGET, - "dispatch - `DispatchBlob::dispatch_blob` was ok for lane_id: {} and message_nonce: {:?}", + "dispatch - `DispatchBlob::dispatch_blob` was ok for lane_id: {:?} and message_nonce: {:?}", message.key.lane_id, message.key.nonce ); @@ -107,7 +107,7 @@ where Err(e) => { log::error!( target: LOG_TARGET, - "dispatch - `DispatchBlob::dispatch_blob` failed with error: {e:?} for lane_id: {} and message_nonce: {:?}", + "dispatch - `DispatchBlob::dispatch_blob` failed with error: {e:?} for lane_id: {:?} and message_nonce: {:?}", message.key.lane_id, message.key.nonce ); @@ -123,13 +123,13 @@ mod tests { use super::*; use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; - use bp_messages::{target_chain::DispatchMessageData, MessageKey}; + use bp_messages::{target_chain::DispatchMessageData, LaneIdType, MessageKey}; use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; use pallet_bridge_messages::InboundLaneStorage; use xcm_executor::traits::ConvertLocation; - fn bridge() -> (Box, LaneId) { + fn bridge() -> (Box, TestLaneIdType) { let origin = OpenBridgeOrigin::sibling_parachain_origin(); let with = bridged_asset_hub_universal_location(); let locations = @@ -194,16 +194,16 @@ mod tests { }); } - fn invalid_message() -> DispatchMessage> { + fn invalid_message() -> DispatchMessage, TestLaneIdType> { DispatchMessage { - key: MessageKey { lane_id: LaneId::new(1, 2), nonce: 1 }, + key: MessageKey { lane_id: TestLaneIdType::try_new(1, 2).unwrap(), nonce: 1 }, data: DispatchMessageData { payload: Err(codec::Error::from("test")) }, } } - fn valid_message() -> DispatchMessage> { + fn valid_message() -> DispatchMessage, TestLaneIdType> { DispatchMessage { - key: MessageKey { lane_id: LaneId::new(1, 2), nonce: 1 }, + key: MessageKey { lane_id: TestLaneIdType::try_new(1, 2).unwrap(), nonce: 1 }, data: DispatchMessageData { payload: Ok(vec![42]) }, } } diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index b42ae1e267f4..5afb9f36bc94 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -26,7 +26,7 @@ use crate::{BridgeOf, Bridges}; use bp_messages::{ source_chain::{MessagesBridge, OnMessagesDelivered}, - LaneId, MessageNonce, + MessageNonce, }; use bp_xcm_bridge_hub::{BridgeId, BridgeState, LocalXcmChannelManager, XcmAsPlainPayload}; use frame_support::{ensure, traits::Get}; @@ -62,7 +62,7 @@ where type Ticket = ( BridgeId, BridgeOf, - as MessagesBridge>::SendMessageArgs, + as MessagesBridge>::SendMessageArgs, XcmHash, ); @@ -94,7 +94,7 @@ where "Destination: {dest:?} is already universal, checking dest_network: {dest_network:?} and network: {network:?} if matches: {:?}", dest_network == network ); - ensure!(dest_network == network, SendError::Unroutable); + ensure!(dest_network == network, SendError::NotApplicable); // ok, `dest` looks like a universal location, so let's use it dest }, @@ -108,23 +108,12 @@ where error_data.0, error_data.1, ); - SendError::Unroutable + SendError::NotApplicable })? }, } }; - // check if we are able to route the message. We use existing `HaulBlobExporter` for that. - // It will make all required changes and will encode message properly, so that the - // `DispatchBlob` at the bridged bridge hub will be able to decode it - let ((blob, id), price) = PalletAsHaulBlobExporter::::validate( - network, - channel, - universal_source, - destination, - message, - )?; - // prepare the origin relative location let bridge_origin_relative_location = bridge_origin_universal_location.relative_to(&T::UniversalLocation::get()); @@ -139,9 +128,28 @@ where target: LOG_TARGET, "Validate `bridge_locations` with error: {e:?}", ); - SendError::Unroutable + SendError::NotApplicable + })?; + let bridge = Self::bridge(locations.bridge_id()).ok_or_else(|| { + log::error!( + target: LOG_TARGET, + "No opened bridge for requested bridge_origin_relative_location: {:?} and bridge_destination_universal_location: {:?}", + locations.bridge_origin_relative_location(), + locations.bridge_destination_universal_location(), + ); + SendError::NotApplicable })?; - let bridge = Self::bridge(locations.bridge_id()).ok_or(SendError::Unroutable)?; + + // check if we are able to route the message. We use existing `HaulBlobExporter` for that. + // It will make all required changes and will encode message properly, so that the + // `DispatchBlob` at the bridged bridge hub will be able to decode it + let ((blob, id), price) = PalletAsHaulBlobExporter::::validate( + network, + channel, + universal_source, + destination, + message, + )?; let bridge_message = MessagesPallet::::validate_message(bridge.lane_id, &blob) .map_err(|e| { @@ -190,8 +198,8 @@ where } } -impl, I: 'static> OnMessagesDelivered for Pallet { - fn on_messages_delivered(lane_id: LaneId, enqueued_messages: MessageNonce) { +impl, I: 'static> OnMessagesDelivered for Pallet { + fn on_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) { Self::on_bridge_messages_delivered(lane_id, enqueued_messages); } } @@ -265,7 +273,7 @@ impl, I: 'static> Pallet { } /// Must be called whenever we receive a message delivery confirmation. - fn on_bridge_messages_delivered(lane_id: LaneId, enqueued_messages: MessageNonce) { + fn on_bridge_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) { // if the bridge queue is still congested, we don't want to do anything let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD; if is_congested { @@ -373,7 +381,7 @@ mod tests { BridgedUniversalDestination::get() } - fn open_lane() -> (BridgeLocations, LaneId) { + fn open_lane() -> (BridgeLocations, TestLaneIdType) { // open expected outbound lane let origin = OpenBridgeOrigin::sibling_parachain_origin(); let with = bridged_asset_hub_universal_location(); @@ -430,7 +438,7 @@ mod tests { (*locations, lane_id) } - fn open_lane_and_send_regular_message() -> (BridgeId, LaneId) { + fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) { let (locations, lane_id) = open_lane(); // now let's try to enqueue message using our `ExportXcm` implementation @@ -466,7 +474,7 @@ mod tests { run_test(|| { let (bridge_id, _) = open_lane_and_send_regular_message(); assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); - assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -495,11 +503,11 @@ mod tests { } assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); - assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); open_lane_and_send_regular_message(); assert!(TestLocalXcmChannelManager::is_bridge_suspened()); - assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Suspended); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); }); } @@ -516,7 +524,7 @@ mod tests { ); assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); - assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Suspended); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); }); } @@ -530,7 +538,7 @@ mod tests { ); assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); - assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -547,7 +555,7 @@ mod tests { ); assert!(TestLocalXcmChannelManager::is_bridge_resumed()); - assert_eq!(XcmOverBridge::bridge(bridge_id).unwrap().state, BridgeState::Opened); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); }); } @@ -679,4 +687,97 @@ mod tests { ); }) } + + #[test] + fn validate_works() { + run_test(|| { + let xcm: Xcm<()> = vec![ClearOrigin].into(); + + // check that router does not consume when `NotApplicable` + let mut xcm_wrapper = Some(xcm.clone()); + let mut universal_source_wrapper = Some(universal_source()); + + // wrong `NetworkId` + let mut dest_wrapper = Some(bridged_relative_destination()); + assert_eq!( + XcmOverBridge::validate( + NetworkId::ByGenesis([0; 32]), + 0, + &mut universal_source_wrapper, + &mut dest_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!(&Some(bridged_relative_destination()), &dest_wrapper); + + // dest starts with wrong `NetworkId` + let mut invalid_dest_wrapper = Some( + [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(BRIDGED_ASSET_HUB_ID)] + .into(), + ); + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut invalid_dest_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!( + &Some( + [ + GlobalConsensus(NetworkId::ByGenesis([0; 32]),), + Parachain(BRIDGED_ASSET_HUB_ID) + ] + .into() + ), + &invalid_dest_wrapper + ); + + // no opened lane for dest + let mut dest_without_lane_wrapper = + Some([GlobalConsensus(BridgedRelayNetwork::get()), Parachain(5679)].into()); + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut dest_without_lane_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!( + &Some([GlobalConsensus(BridgedRelayNetwork::get(),), Parachain(5679)].into()), + &dest_without_lane_wrapper + ); + + // ok + let _ = open_lane(); + let mut dest_wrapper = Some(bridged_relative_destination()); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut dest_wrapper, + &mut xcm_wrapper, + )); + // dest and xcm IS consumed + assert_eq!(None, xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!(None, dest_wrapper); + }); + } } diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 02d578386a75..1b2536598a20 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -143,7 +143,7 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use bp_messages::{LaneId, LaneState, MessageNonce}; +use bp_messages::{LaneState, MessageNonce}; use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use bp_xcm_bridge_hub::{BridgeLocations, BridgeLocationsError, LocalXcmChannelManager}; @@ -213,9 +213,8 @@ pub mod pallet { type DestinationVersion: GetVersion; /// The origin that is allowed to call privileged operations on the pallet, e.g. open/close - /// bridge for location that coresponds to `Self::BridgeOriginAccountIdConverter` and - /// `Self::BridgedNetwork`. - type AdminOrigin: EnsureOrigin<::RuntimeOrigin>; + /// bridge for locations. + type ForceOrigin: EnsureOrigin<::RuntimeOrigin>; /// A set of XCM locations within local consensus system that are allowed to open /// bridges with remote destinations. type OpenBridgeOrigin: EnsureOrigin< @@ -248,10 +247,13 @@ pub mod pallet { } /// An alias for the bridge metadata. - pub type BridgeOf = Bridge>; + pub type BridgeOf = Bridge, LaneIdOf>; /// An alias for this chain. pub type ThisChainOf = pallet_bridge_messages::ThisChainOf>::BridgeMessagesPalletInstance>; + /// An alias for lane identifier type. + pub type LaneIdOf = + >::BridgeMessagesPalletInstance>>::LaneId; /// An alias for the associated lanes manager. pub type LanesManagerOf = pallet_bridge_messages::LanesManager>::BridgeMessagesPalletInstance>; @@ -392,7 +394,7 @@ pub mod pallet { // deposit the `ClosingBridge` event Self::deposit_event(Event::::ClosingBridge { bridge_id: *locations.bridge_id(), - lane_id: bridge.lane_id, + lane_id: bridge.lane_id.into(), pruned_messages, enqueued_messages, }); @@ -413,7 +415,7 @@ pub mod pallet { bridge.deposit, Precision::BestEffort, ) - .map_err(|e| { + .inspect_err(|e| { // we can't do anything here - looks like funds have been (partially) unreserved // before by someone else. Let's not fail, though - it'll be worse for the caller log::error!( @@ -421,7 +423,6 @@ pub mod pallet { "Failed to unreserve during the bridge {:?} closure with error: {e:?}", locations.bridge_id(), ); - e }) .ok() .unwrap_or(BalanceOf::>::zero()); @@ -439,7 +440,7 @@ pub mod pallet { // deposit the `BridgePruned` event Self::deposit_event(Event::::BridgePruned { bridge_id: *locations.bridge_id(), - lane_id: bridge.lane_id, + lane_id: bridge.lane_id.into(), bridge_deposit: released_deposit, pruned_messages, }); @@ -449,9 +450,10 @@ pub mod pallet { } impl, I: 'static> Pallet { - pub(crate) fn do_open_bridge( + /// Open bridge for lane. + pub fn do_open_bridge( locations: Box, - lane_id: LaneId, + lane_id: T::LaneId, create_lanes: bool, ) -> Result<(), DispatchError> { // reserve balance on the origin's sovereign account (if needed) @@ -542,7 +544,7 @@ pub mod pallet { remote_endpoint: Box::new( locations.bridge_destination_universal_location().clone(), ), - lane_id, + lane_id: lane_id.into(), }); Ok(()) @@ -585,10 +587,15 @@ pub mod pallet { }) } + /// Return bridge metadata by bridge_id + pub fn bridge(bridge_id: &BridgeId) -> Option> { + Bridges::::get(bridge_id) + } + /// Return bridge metadata by lane_id - pub fn bridge_by_lane_id(lane_id: &LaneId) -> Option<(BridgeId, BridgeOf)> { + pub fn bridge_by_lane_id(lane_id: &T::LaneId) -> Option<(BridgeId, BridgeOf)> { LaneToBridge::::get(lane_id) - .and_then(|bridge_id| Self::bridge(bridge_id).map(|bridge| (bridge_id, bridge))) + .and_then(|bridge_id| Self::bridge(&bridge_id).map(|bridge| (bridge_id, bridge))) } } @@ -634,7 +641,7 @@ pub mod pallet { pub fn do_try_state_for_bridge( bridge_id: BridgeId, bridge: BridgeOf, - ) -> Result { + ) -> Result { log::info!(target: LOG_TARGET, "Checking `do_try_state_for_bridge` for bridge_id: {bridge_id:?} and bridge: {bridge:?}"); // check `BridgeId` points to the same `LaneId` and vice versa. @@ -707,13 +714,12 @@ pub mod pallet { /// All registered bridges. #[pallet::storage] - #[pallet::getter(fn bridge)] pub type Bridges, I: 'static = ()> = StorageMap<_, Identity, BridgeId, BridgeOf>; /// All registered `lane_id` and `bridge_id` mappings. #[pallet::storage] pub type LaneToBridge, I: 'static = ()> = - StorageMap<_, Identity, LaneId, BridgeId>; + StorageMap<_, Identity, T::LaneId, BridgeId>; #[pallet::genesis_config] #[derive(DefaultNoBound)] @@ -723,7 +729,7 @@ pub mod pallet { /// Keep in mind that we are **NOT** reserving any amount for the bridges opened at /// genesis. We are **NOT** opening lanes, used by this bridge. It all must be done using /// other pallets genesis configuration or some other means. - pub opened_bridges: Vec<(Location, InteriorLocation)>, + pub opened_bridges: Vec<(Location, InteriorLocation, Option)>, /// Dummy marker. #[serde(skip)] pub _phantom: sp_std::marker::PhantomData<(T, I)>, @@ -735,48 +741,26 @@ pub mod pallet { T: frame_system::Config>>, { fn build(&self) { - for (bridge_origin_relative_location, bridge_destination_universal_location) in - &self.opened_bridges + for ( + bridge_origin_relative_location, + bridge_destination_universal_location, + maybe_lane_id, + ) in &self.opened_bridges { let locations = Pallet::::bridge_locations( bridge_origin_relative_location.clone(), bridge_destination_universal_location.clone().into(), ) .expect("Invalid genesis configuration"); - let lane_id = - locations.calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"); - let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( - locations.bridge_origin_relative_location(), - ) - .expect("Invalid genesis configuration"); - Bridges::::insert( - locations.bridge_id(), - Bridge { - bridge_origin_relative_location: Box::new( - locations.bridge_origin_relative_location().clone().into(), - ), - bridge_origin_universal_location: Box::new( - locations.bridge_origin_universal_location().clone().into(), - ), - bridge_destination_universal_location: Box::new( - locations.bridge_destination_universal_location().clone().into(), - ), - state: BridgeState::Opened, - bridge_owner_account, - deposit: Zero::zero(), - lane_id, - }, - ); - LaneToBridge::::insert(lane_id, locations.bridge_id()); + let lane_id = match maybe_lane_id { + Some(lane_id) => *lane_id, + None => + locations.calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"), + }; - let lanes_manager = LanesManagerOf::::new(); - lanes_manager - .create_inbound_lane(lane_id) - .expect("Invalid genesis configuration"); - lanes_manager - .create_outbound_lane(lane_id) - .expect("Invalid genesis configuration"); + Pallet::::do_open_bridge(locations, lane_id, true) + .expect("Valid opened bridge!"); } } } @@ -796,14 +780,14 @@ pub mod pallet { /// Universal location of remote bridge endpoint. remote_endpoint: Box, /// Lane identifier. - lane_id: LaneId, + lane_id: T::LaneId, }, /// Bridge is going to be closed, but not yet fully pruned from the runtime storage. ClosingBridge { /// Bridge identifier. bridge_id: BridgeId, /// Lane identifier. - lane_id: LaneId, + lane_id: T::LaneId, /// Number of pruned messages during the close call. pruned_messages: MessageNonce, /// Number of enqueued messages that need to be pruned in follow up calls. @@ -815,7 +799,7 @@ pub mod pallet { /// Bridge identifier. bridge_id: BridgeId, /// Lane identifier. - lane_id: LaneId, + lane_id: T::LaneId, /// Amount of deposit released. bridge_deposit: BalanceOf>, /// Number of pruned messages during the close call. @@ -849,12 +833,11 @@ pub mod pallet { #[cfg(test)] mod tests { use super::*; + use bp_messages::LaneIdType; use mock::*; - use bp_messages::LaneId; use frame_support::{assert_err, assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; use frame_system::{EventRecord, Phase}; - use sp_core::H256; use sp_runtime::TryRuntimeError; fn fund_origin_sovereign_account(locations: &BridgeLocations, balance: Balance) -> AccountId { @@ -911,7 +894,7 @@ mod tests { mock_open_bridge_from_with(origin, deposit, bridged_asset_hub_universal_location()) } - fn enqueue_message(lane: LaneId) { + fn enqueue_message(lane: TestLaneIdType) { let lanes_manager = LanesManagerOf::::new(); lanes_manager .active_outbound_lane(lane) @@ -1212,7 +1195,7 @@ mod tests { remote_endpoint: Box::new( locations.bridge_destination_universal_location().clone() ), - lane_id + lane_id: lane_id.into() }), topics: vec![], }), @@ -1355,7 +1338,7 @@ mod tests { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { bridge_id: *locations.bridge_id(), - lane_id: bridge.lane_id, + lane_id: bridge.lane_id.into(), pruned_messages: 16, enqueued_messages: 16, }), @@ -1403,7 +1386,7 @@ mod tests { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { bridge_id: *locations.bridge_id(), - lane_id: bridge.lane_id, + lane_id: bridge.lane_id.into(), pruned_messages: 8, enqueued_messages: 8, }), @@ -1444,7 +1427,7 @@ mod tests { phase: Phase::Initialization, event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { bridge_id: *locations.bridge_id(), - lane_id: bridge.lane_id, + lane_id: bridge.lane_id.into(), bridge_deposit: expected_deposit, pruned_messages: 8, }), @@ -1456,8 +1439,6 @@ mod tests { #[test] fn do_try_state_works() { - use sp_runtime::Either; - let bridge_origin_relative_location = SiblingLocation::get(); let bridge_origin_universal_location = SiblingUniversalLocation::get(); let bridge_destination_universal_location = BridgedUniversalDestination::get(); @@ -1471,28 +1452,29 @@ mod tests { &bridge_destination_universal_location, ); let bridge_id_mismatch = BridgeId::new(&InteriorLocation::Here, &InteriorLocation::Here); - let lane_id = LaneId::from_inner(Either::Left(H256::default())); - let lane_id_mismatch = LaneId::from_inner(Either::Left(H256::from([1u8; 32]))); + let lane_id = TestLaneIdType::try_new(1, 2).unwrap(); + let lane_id_mismatch = TestLaneIdType::try_new(3, 4).unwrap(); + + let test_bridge_state = + |id, + bridge, + (lane_id, bridge_id), + (inbound_lane_id, outbound_lane_id), + expected_error: Option| { + Bridges::::insert(id, bridge); + LaneToBridge::::insert(lane_id, bridge_id); - let test_bridge_state = |id, - bridge, - (lane_id, bridge_id), - (inbound_lane_id, outbound_lane_id), - expected_error: Option| { - Bridges::::insert(id, bridge); - LaneToBridge::::insert(lane_id, bridge_id); - - let lanes_manager = LanesManagerOf::::new(); - lanes_manager.create_inbound_lane(inbound_lane_id).unwrap(); - lanes_manager.create_outbound_lane(outbound_lane_id).unwrap(); - - let result = XcmOverBridge::do_try_state(); - if let Some(e) = expected_error { - assert_err!(result, e); - } else { - assert_ok!(result); - } - }; + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.create_inbound_lane(inbound_lane_id).unwrap(); + lanes_manager.create_outbound_lane(outbound_lane_id).unwrap(); + + let result = XcmOverBridge::do_try_state(); + if let Some(e) = expected_error { + assert_err!(result, e); + } else { + assert_ok!(result); + } + }; let cleanup = |bridge_id, lane_ids| { Bridges::::remove(bridge_id); for lane_id in lane_ids { diff --git a/bridges/modules/xcm-bridge-hub/src/migration.rs b/bridges/modules/xcm-bridge-hub/src/migration.rs index c9d8b67176a5..ffd5233a917b 100644 --- a/bridges/modules/xcm-bridge-hub/src/migration.rs +++ b/bridges/modules/xcm-bridge-hub/src/migration.rs @@ -17,7 +17,6 @@ //! A module that is responsible for migration of storage. use crate::{Config, Pallet, LOG_TARGET}; -use bp_messages::LaneId; use frame_support::{ traits::{Get, OnRuntimeUpgrade, StorageVersion}, weights::Weight, @@ -52,7 +51,7 @@ pub struct OpenBridgeForLane< impl< T: Config, I: 'static, - Lane: Get, + Lane: Get, CreateLane: Get, SourceRelativeLocation: Get, BridgedUniversalLocation: Get, diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index aff3526b5589..6511b9fc5b04 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -20,7 +20,7 @@ use crate as pallet_xcm_bridge_hub; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - ChainWithMessages, LaneId, MessageNonce, + ChainWithMessages, HashedLaneId, MessageNonce, }; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; @@ -50,6 +50,9 @@ pub type AccountId = AccountId32; pub type Balance = u64; type Block = frame_system::mocking::MockBlock; +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; + pub const SIBLING_ASSET_HUB_ID: u32 = 2001; pub const THIS_BRIDGE_HUB_ID: u32 = 2002; pub const BRIDGED_ASSET_HUB_ID: u32 = 1001; @@ -92,6 +95,7 @@ impl pallet_bridge_messages::Config for TestRuntime { type OutboundPayload = Vec; type InboundPayload = Vec; + type LaneId = TestLaneIdType; type DeliveryPayments = (); type DeliveryConfirmationPayments = (); @@ -152,7 +156,7 @@ parameter_types! { pub SiblingLocation: Location = Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]); pub SiblingUniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into(); - pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; + pub const BridgedRelayNetwork: NetworkId = NetworkId::ByGenesis([1; 32]); pub BridgedRelayNetworkLocation: Location = (Parent, GlobalConsensus(BridgedRelayNetwork::get())).into(); pub BridgedRelativeDestination: InteriorLocation = [Parachain(BRIDGED_ASSET_HUB_ID)].into(); pub BridgedUniversalDestination: InteriorLocation = [GlobalConsensus(BridgedRelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)].into(); @@ -190,7 +194,7 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type MessageExportPrice = (); type DestinationVersion = AlwaysLatest; - type AdminOrigin = frame_system::EnsureNever<()>; + type ForceOrigin = frame_system::EnsureNever<()>; type OpenBridgeOrigin = OpenBridgeOrigin; type BridgeOriginAccountIdConverter = LocationToAccountId; @@ -523,7 +527,7 @@ impl bp_header_chain::HeaderChain for BridgedHeaderChain pub struct TestMessageDispatch; impl TestMessageDispatch { - pub fn deactivate(lane: LaneId) { + pub fn deactivate(lane: TestLaneIdType) { frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); } } @@ -531,18 +535,21 @@ impl TestMessageDispatch { impl MessageDispatch for TestMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); + type LaneId = TestLaneIdType; - fn is_active(lane: LaneId) -> bool { + fn is_active(lane: Self::LaneId) -> bool { frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != Some(false) } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::zero() } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } diff --git a/bridges/primitives/header-chain/src/justification/mod.rs b/bridges/primitives/header-chain/src/justification/mod.rs index d7c2cbf429e2..87f53dac6463 100644 --- a/bridges/primitives/header-chain/src/justification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/mod.rs @@ -32,7 +32,6 @@ pub use verification::{ use bp_runtime::{BlockNumberOf, Chain, HashOf, HeaderId}; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::RuntimeDebugNoBound; use scale_info::TypeInfo; use sp_consensus_grandpa::{AuthorityId, AuthoritySignature}; use sp_runtime::{traits::Header as HeaderT, RuntimeDebug, SaturatedConversion}; @@ -43,7 +42,8 @@ use sp_std::prelude::*; /// /// This particular proof is used to prove that headers on a bridged chain /// (so not our chain) have been finalized correctly. -#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, RuntimeDebugNoBound)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] pub struct GrandpaJustification { /// The round (voting period) this justification is valid for. pub round: u64, @@ -54,6 +54,17 @@ pub struct GrandpaJustification { pub votes_ancestries: Vec
, } +// A proper Debug impl for no-std is not possible for the `GrandpaJustification` since the `Commit` +// type only implements Debug that for `std` here: +// https://github.com/paritytech/finality-grandpa/blob/8c45a664c05657f0c71057158d3ba555ba7d20de/src/lib.rs#L275 +// so we do a manual impl. +#[cfg(not(feature = "std"))] +impl core::fmt::Debug for GrandpaJustification { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "GrandpaJustification {{ round: {:?}, commit: , votes_ancestries: {:?} }}", self.round, self.votes_ancestries) + } +} + impl GrandpaJustification { /// Returns reasonable size of justification using constants from the provided chain. /// diff --git a/bridges/primitives/messages/src/call_info.rs b/bridges/primitives/messages/src/call_info.rs index c8f06ed8cb7c..dfd076f029b4 100644 --- a/bridges/primitives/messages/src/call_info.rs +++ b/bridges/primitives/messages/src/call_info.rs @@ -16,22 +16,14 @@ //! Defines structures related to calls of the `pallet-bridge-messages` pallet. -use crate::{source_chain, target_chain, LaneId, MessageNonce, UnrewardedRelayersState}; +use crate::{MessageNonce, UnrewardedRelayersState}; -use bp_runtime::{AccountIdOf, HashOf}; use codec::{Decode, Encode}; use frame_support::weights::Weight; use scale_info::TypeInfo; use sp_core::RuntimeDebug; use sp_std::ops::RangeInclusive; -/// The `BridgeMessagesCall` used to bridge with a given chain. -pub type BridgeMessagesCallOf = BridgeMessagesCall< - AccountIdOf, - target_chain::FromBridgedChainMessagesProof>, - source_chain::FromBridgedChainMessagesDeliveryProof>, ->; - /// A minimized version of `pallet-bridge-messages::Call` that can be used without a runtime. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] #[allow(non_camel_case_types)] @@ -60,7 +52,7 @@ pub enum BridgeMessagesCall { /// Generic info about a messages delivery/confirmation proof. #[derive(PartialEq, RuntimeDebug)] -pub struct BaseMessagesProofInfo { +pub struct BaseMessagesProofInfo { /// Message lane, used by the call. pub lane_id: LaneId, /// Nonces of messages, included in the call. @@ -75,7 +67,7 @@ pub struct BaseMessagesProofInfo { pub best_stored_nonce: MessageNonce, } -impl BaseMessagesProofInfo { +impl BaseMessagesProofInfo { /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. pub fn appends_to_stored_nonce(&self) -> bool { Some(*self.bundled_range.start()) == self.best_stored_nonce.checked_add(1) @@ -94,14 +86,14 @@ pub struct UnrewardedRelayerOccupation { /// Info about a `ReceiveMessagesProof` call which tries to update a single lane. #[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesProofInfo { +pub struct ReceiveMessagesProofInfo { /// Base messages proof info - pub base: BaseMessagesProofInfo, + pub base: BaseMessagesProofInfo, /// State of unrewarded relayers vector. pub unrewarded_relayers: UnrewardedRelayerOccupation, } -impl ReceiveMessagesProofInfo { +impl ReceiveMessagesProofInfo { /// Returns true if: /// /// - either inbound lane is ready to accept bundled messages; @@ -134,9 +126,9 @@ impl ReceiveMessagesProofInfo { /// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. #[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); +pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); -impl ReceiveMessagesDeliveryProofInfo { +impl ReceiveMessagesDeliveryProofInfo { /// Returns true if outbound lane is ready to accept confirmations of bundled messages. pub fn is_obsolete(&self) -> bool { self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() @@ -146,14 +138,14 @@ impl ReceiveMessagesDeliveryProofInfo { /// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call /// which tries to update a single lane. #[derive(PartialEq, RuntimeDebug)] -pub enum MessagesCallInfo { +pub enum MessagesCallInfo { /// Messages delivery call info. - ReceiveMessagesProof(ReceiveMessagesProofInfo), + ReceiveMessagesProof(ReceiveMessagesProofInfo), /// Messages delivery confirmation call info. - ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), + ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), } -impl MessagesCallInfo { +impl MessagesCallInfo { /// Returns lane, used by the call. pub fn lane_id(&self) -> LaneId { match *self { diff --git a/bridges/primitives/messages/src/lane.rs b/bridges/primitives/messages/src/lane.rs index 6d4ca402eb34..0f14ce93e114 100644 --- a/bridges/primitives/messages/src/lane.rs +++ b/bridges/primitives/messages/src/lane.rs @@ -16,12 +16,88 @@ //! Primitives of messages module, that represents lane id. -use codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen}; -use frame_support::sp_runtime::Either; +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_core::{RuntimeDebug, TypeId, H256}; use sp_io::hashing::blake2_256; +use sp_std::fmt::Debug; + +/// Trait representing a generic `LaneId` type. +pub trait LaneIdType: + Clone + + Copy + + Codec + + EncodeLike + + Debug + + Default + + PartialEq + + Eq + + Ord + + TypeInfo + + MaxEncodedLen + + Serialize + + DeserializeOwned +{ + /// Creates a new `LaneId` type (if supported). + fn try_new(endpoint1: E, endpoint2: E) -> Result; +} + +/// Bridge lane identifier (legacy). +/// +/// Note: For backwards compatibility reasons, we also handle the older format `[u8; 4]`. +#[derive( + Clone, + Copy, + Decode, + Default, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct LegacyLaneId(pub [u8; 4]); + +impl LaneIdType for LegacyLaneId { + /// Create lane identifier from two locations. + fn try_new(_endpoint1: T, _endpoint2: T) -> Result { + // we don't support this for `LegacyLaneId`, because it was hard-coded before + Err(()) + } +} + +#[cfg(feature = "std")] +impl TryFrom> for LegacyLaneId { + type Error = (); + + fn try_from(value: Vec) -> Result { + if value.len() == 4 { + return <[u8; 4]>::try_from(value).map(Self).map_err(|_| ()); + } + Err(()) + } +} + +impl core::fmt::Debug for LegacyLaneId { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(fmt) + } +} + +impl AsRef<[u8]> for LegacyLaneId { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl TypeId for LegacyLaneId { + const TYPE_ID: [u8; 4] = *b"blan"; +} /// Bridge lane identifier. /// @@ -41,12 +117,11 @@ use sp_io::hashing::blake2_256; /// (endpoint2, VALUES_SEPARATOR, endpoint1) /// }.using_encoded(blake2_256); /// ``` -/// -/// Note: For backwards compatibility reasons, we also handle the older format `[u8; 4]`. #[derive( Clone, Copy, Decode, + Default, Encode, Eq, Ord, @@ -57,115 +132,67 @@ use sp_io::hashing::blake2_256; Serialize, Deserialize, )] -pub struct LaneId(InnerLaneId); - -impl LaneId { - /// Create lane identifier from two locations. - pub fn new(endpoint1: T, endpoint2: T) -> Self { - const VALUES_SEPARATOR: [u8; 31] = *b"bridges-lane-id-value-separator"; - - LaneId(InnerLaneId::Hash( - if endpoint1 < endpoint2 { - (endpoint1, VALUES_SEPARATOR, endpoint2) - } else { - (endpoint2, VALUES_SEPARATOR, endpoint1) - } - .using_encoded(blake2_256) - .into(), - )) - } +pub struct HashedLaneId(H256); +impl HashedLaneId { /// Create lane identifier from given hash. /// /// There's no `From` implementation for the `LaneId`, because using this conversion /// in a wrong way (i.e. computing hash of endpoints manually) may lead to issues. So we /// want the call to be explicit. - pub const fn from_inner(inner: Either) -> Self { - LaneId(match inner { - Either::Left(hash) => InnerLaneId::Hash(hash), - Either::Right(array) => InnerLaneId::Array(array), - }) + #[cfg(feature = "std")] + pub const fn from_inner(inner: H256) -> Self { + Self(inner) + } + + /// Access the inner lane representation. + pub fn inner(&self) -> &H256 { + &self.0 } } -impl core::fmt::Display for LaneId { +impl core::fmt::Display for HashedLaneId { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { core::fmt::Display::fmt(&self.0, f) } } -impl core::fmt::Debug for LaneId { +impl core::fmt::Debug for HashedLaneId { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { core::fmt::Debug::fmt(&self.0, f) } } -impl AsRef<[u8]> for LaneId { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } +impl TypeId for HashedLaneId { + const TYPE_ID: [u8; 4] = *b"hlan"; } -impl TypeId for LaneId { - const TYPE_ID: [u8; 4] = *b"blan"; -} - -#[derive( - Clone, Copy, Eq, Ord, PartialOrd, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize, -)] -enum InnerLaneId { - /// Old format (for backwards compatibility). - Array([u8; 4]), - /// New format 32-byte hash generated by `blake2_256`. - Hash(H256), -} - -impl Encode for InnerLaneId { - fn encode(&self) -> sp_std::vec::Vec { - match self { - InnerLaneId::Array(array) => array.encode(), - InnerLaneId::Hash(hash) => hash.encode(), - } - } -} - -impl Decode for InnerLaneId { - fn decode(input: &mut I) -> Result { - // check backwards compatibly first - if input.remaining_len() == Ok(Some(4)) { - let array: [u8; 4] = Decode::decode(input)?; - return Ok(InnerLaneId::Array(array)) - } - - // else check new format - H256::decode(input).map(InnerLaneId::Hash) - } -} +impl LaneIdType for HashedLaneId { + /// Create lane identifier from two locations. + fn try_new(endpoint1: T, endpoint2: T) -> Result { + const VALUES_SEPARATOR: [u8; 31] = *b"bridges-lane-id-value-separator"; -impl core::fmt::Display for InnerLaneId { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - InnerLaneId::Array(array) => write!(f, "Array({:?})", array), - InnerLaneId::Hash(hash) => write!(f, "Hash({:?})", hash), - } + Ok(Self( + if endpoint1 < endpoint2 { + (endpoint1, VALUES_SEPARATOR, endpoint2) + } else { + (endpoint2, VALUES_SEPARATOR, endpoint1) + } + .using_encoded(blake2_256) + .into(), + )) } } -impl core::fmt::Debug for InnerLaneId { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - InnerLaneId::Array(array) => array.fmt(fmt), - InnerLaneId::Hash(hash) => hash.fmt(fmt), - } - } -} +#[cfg(feature = "std")] +impl TryFrom> for HashedLaneId { + type Error = (); -impl AsRef<[u8]> for InnerLaneId { - fn as_ref(&self) -> &[u8] { - match self { - InnerLaneId::Array(array) => array.as_ref(), - InnerLaneId::Hash(hash) => hash.as_ref(), + fn try_from(value: Vec) -> Result { + if value.len() == 32 { + return <[u8; 32]>::try_from(value).map(|v| Self(H256::from(v))).map_err(|_| ()); } + Err(()) } } @@ -194,63 +221,89 @@ impl LaneState { #[cfg(test)] mod tests { use super::*; + use crate::MessageNonce; #[test] fn lane_id_debug_format_matches_inner_hash_format() { assert_eq!( - format!("{:?}", LaneId(InnerLaneId::Hash(H256::from([1u8; 32])))), + format!("{:?}", HashedLaneId(H256::from([1u8; 32]))), format!("{:?}", H256::from([1u8; 32])), ); - assert_eq!( - format!("{:?}", LaneId(InnerLaneId::Array([0, 0, 0, 1]))), - format!("{:?}", [0, 0, 0, 1]), - ); + assert_eq!(format!("{:?}", LegacyLaneId([0, 0, 0, 1])), format!("{:?}", [0, 0, 0, 1]),); } #[test] - fn lane_id_as_ref_works() { + fn hashed_encode_decode_works() { + // simple encode/decode - new format + let lane_id = HashedLaneId(H256::from([1u8; 32])); + let encoded_lane_id = lane_id.encode(); + let decoded_lane_id = HashedLaneId::decode(&mut &encoded_lane_id[..]).expect("decodable"); + assert_eq!(lane_id, decoded_lane_id); assert_eq!( "0101010101010101010101010101010101010101010101010101010101010101", - hex::encode(LaneId(InnerLaneId::Hash(H256::from([1u8; 32]))).as_ref()), + hex::encode(encoded_lane_id) ); - assert_eq!("00000001", hex::encode(LaneId(InnerLaneId::Array([0, 0, 0, 1])).as_ref()),); } #[test] - fn lane_id_encode_decode_works() { - let test_encode_decode = |expected_hex, lane_id: LaneId| { - let enc = lane_id.encode(); - let decoded_lane_id = LaneId::decode(&mut &enc[..]).expect("decodable"); - assert_eq!(lane_id, decoded_lane_id); - - assert_eq!(expected_hex, hex::encode(lane_id.as_ref()),); - assert_eq!(expected_hex, hex::encode(decoded_lane_id.as_ref()),); - - let hex_bytes = hex::decode(expected_hex).expect("valid hex"); - let hex_decoded_lane_id = LaneId::decode(&mut &hex_bytes[..]).expect("decodable"); - assert_eq!(hex_decoded_lane_id, lane_id); - assert_eq!(hex_decoded_lane_id, decoded_lane_id); - }; - - test_encode_decode( - "0101010101010101010101010101010101010101010101010101010101010101", - LaneId(InnerLaneId::Hash(H256::from([1u8; 32]))), - ); - test_encode_decode("00000001", LaneId(InnerLaneId::Array([0, 0, 0, 1]))); + fn legacy_encode_decode_works() { + // simple encode/decode - old format + let lane_id = LegacyLaneId([0, 0, 0, 1]); + let encoded_lane_id = lane_id.encode(); + let decoded_lane_id = LegacyLaneId::decode(&mut &encoded_lane_id[..]).expect("decodable"); + assert_eq!(lane_id, decoded_lane_id); + assert_eq!("00000001", hex::encode(encoded_lane_id)); + + // decode sample + let bytes = vec![0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]; + let (lane, nonce_start, nonce_end): (LegacyLaneId, MessageNonce, MessageNonce) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, LegacyLaneId([0, 0, 0, 2])); + assert_eq!(nonce_start, 1); + assert_eq!(nonce_end, 1); + + // run encode/decode for `LaneId` with different positions + let expected_lane = LegacyLaneId([0, 0, 0, 1]); + let expected_nonce_start = 1088_u64; + let expected_nonce_end = 9185_u64; + + // decode: LaneId,Nonce,Nonce + let bytes = (expected_lane, expected_nonce_start, expected_nonce_end).encode(); + let (lane, nonce_start, nonce_end): (LegacyLaneId, MessageNonce, MessageNonce) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, expected_lane); + assert_eq!(nonce_start, expected_nonce_start); + assert_eq!(nonce_end, expected_nonce_end); + + // decode: Nonce,LaneId,Nonce + let bytes = (expected_nonce_start, expected_lane, expected_nonce_end).encode(); + let (nonce_start, lane, nonce_end): (MessageNonce, LegacyLaneId, MessageNonce) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, expected_lane); + assert_eq!(nonce_start, expected_nonce_start); + assert_eq!(nonce_end, expected_nonce_end); + + // decode: Nonce,Nonce,LaneId + let bytes = (expected_nonce_start, expected_nonce_end, expected_lane).encode(); + let (nonce_start, nonce_end, lane): (MessageNonce, MessageNonce, LegacyLaneId) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, expected_lane); + assert_eq!(nonce_start, expected_nonce_start); + assert_eq!(nonce_end, expected_nonce_end); } #[test] - fn lane_id_is_generated_using_ordered_endpoints() { - assert_eq!(LaneId::new(1, 2), LaneId::new(2, 1)); + fn hashed_lane_id_is_generated_using_ordered_endpoints() { + assert_eq!(HashedLaneId::try_new(1, 2).unwrap(), HashedLaneId::try_new(2, 1).unwrap()); } #[test] - fn lane_id_is_different_for_different_endpoints() { - assert_ne!(LaneId::new(1, 2), LaneId::new(1, 3)); + fn hashed_lane_id_is_different_for_different_endpoints() { + assert_ne!(HashedLaneId::try_new(1, 2).unwrap(), HashedLaneId::try_new(1, 3).unwrap()); } #[test] - fn lane_id_is_different_even_if_arguments_has_partial_matching_encoding() { + fn hashed_lane_id_is_different_even_if_arguments_has_partial_matching_encoding() { /// Some artificial type that generates the same encoding for different values /// concatenations. I.e. the encoding for `(Either::Two(1, 2), Either::Two(3, 4))` /// is the same as encoding of `(Either::Three(1, 2, 3), Either::One(4))`. @@ -274,8 +327,8 @@ mod tests { } assert_ne!( - LaneId::new(Either::Two(1, 2), Either::Two(3, 4)), - LaneId::new(Either::Three(1, 2, 3), Either::One(4)), + HashedLaneId::try_new(Either::Two(1, 2), Either::Two(3, 4)).unwrap(), + HashedLaneId::try_new(Either::Three(1, 2, 3), Either::One(4)).unwrap(), ); } } diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 7eb0c5629395..2776b806cc16 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -35,10 +35,10 @@ use sp_core::RuntimeDebug; use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; pub use call_info::{ - BaseMessagesProofInfo, BridgeMessagesCall, BridgeMessagesCallOf, MessagesCallInfo, - ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, + BaseMessagesProofInfo, BridgeMessagesCall, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, + ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, }; -pub use lane::{LaneId, LaneState}; +pub use lane::{HashedLaneId, LaneIdType, LaneState, LegacyLaneId}; mod call_info; mod lane; @@ -181,7 +181,7 @@ pub type MessagePayload = Vec; /// Message key (unique message identifier) as it is stored in the storage. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct MessageKey { +pub struct MessageKey { /// ID of the message lane. pub lane_id: LaneId, /// Message nonce. @@ -190,9 +190,9 @@ pub struct MessageKey { /// Message as it is stored in the storage. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct Message { +pub struct Message { /// Message key. - pub key: MessageKey, + pub key: MessageKey, /// Message payload. pub payload: MessagePayload, } @@ -200,11 +200,6 @@ pub struct Message { /// Inbound lane data. #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct InboundLaneData { - /// Inbound lane state. - /// - /// If state is `Closed`, then all attempts to deliver messages to this end will fail. - pub state: LaneState, - /// Identifiers of relayers and messages that they have delivered to this lane (ordered by /// message nonce). /// @@ -233,6 +228,11 @@ pub struct InboundLaneData { /// This value is updated indirectly when an `OutboundLane` state of the source /// chain is received alongside with new messages delivery. pub last_confirmed_nonce: MessageNonce, + + /// Inbound lane state. + /// + /// If state is `Closed`, then all attempts to deliver messages to this end will fail. + pub state: LaneState, } impl Default for InboundLaneData { @@ -337,20 +337,20 @@ pub struct UnrewardedRelayer { /// Received messages with their dispatch result. #[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] -pub struct ReceivedMessages { +pub struct ReceivedMessages { /// Id of the lane which is receiving messages. pub lane: LaneId, /// Result of messages which we tried to dispatch pub receive_results: Vec<(MessageNonce, ReceptionResult)>, } -impl ReceivedMessages { +impl ReceivedMessages { /// Creates new `ReceivedMessages` structure from given results. pub fn new( lane: LaneId, receive_results: Vec<(MessageNonce, ReceptionResult)>, ) -> Self { - ReceivedMessages { lane, receive_results } + ReceivedMessages { lane: lane.into(), receive_results } } /// Push `result` of the `message` delivery onto `receive_results` vector. @@ -449,10 +449,6 @@ impl From<&InboundLaneData> for UnrewardedRelayersState { /// Outbound lane data. #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct OutboundLaneData { - /// Lane state. - /// - /// If state is `Closed`, then all attempts to send messages messages at this end will fail. - pub state: LaneState, /// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated /// message if all sent messages are already pruned. pub oldest_unpruned_nonce: MessageNonce, @@ -460,6 +456,10 @@ pub struct OutboundLaneData { pub latest_received_nonce: MessageNonce, /// Nonce of the latest message, generated by us. pub latest_generated_nonce: MessageNonce, + /// Lane state. + /// + /// If state is `Closed`, then all attempts to send messages at this end will fail. + pub state: LaneState, } impl OutboundLaneData { diff --git a/bridges/primitives/messages/src/source_chain.rs b/bridges/primitives/messages/src/source_chain.rs index 64f015bdb822..1d4a513035c7 100644 --- a/bridges/primitives/messages/src/source_chain.rs +++ b/bridges/primitives/messages/src/source_chain.rs @@ -16,7 +16,7 @@ //! Primitives of messages module, that are used on the source chain. -use crate::{LaneId, MessageNonce, UnrewardedRelayer}; +use crate::{MessageNonce, UnrewardedRelayer}; use bp_runtime::{raw_storage_proof_size, RawStorageProof, Size}; use codec::{Decode, Encode}; @@ -39,7 +39,7 @@ use sp_std::{ /// /// - lane id. #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct FromBridgedChainMessagesDeliveryProof { +pub struct FromBridgedChainMessagesDeliveryProof { /// Hash of the bridge header the proof is for. pub bridged_header_hash: BridgedHeaderHash, /// Storage trie proof generated for [`Self::bridged_header_hash`]. @@ -48,7 +48,9 @@ pub struct FromBridgedChainMessagesDeliveryProof { pub lane: LaneId, } -impl Size for FromBridgedChainMessagesDeliveryProof { +impl Size + for FromBridgedChainMessagesDeliveryProof +{ fn size(&self) -> u32 { use frame_support::sp_runtime::SaturatedConversion; raw_storage_proof_size(&self.storage_proof).saturated_into() @@ -60,7 +62,7 @@ pub type RelayersRewards = BTreeMap; /// Manages payments that are happening at the source chain during delivery confirmation /// transaction. -pub trait DeliveryConfirmationPayments { +pub trait DeliveryConfirmationPayments { /// Error type. type Error: Debug + Into<&'static str>; @@ -78,7 +80,7 @@ pub trait DeliveryConfirmationPayments { ) -> MessageNonce; } -impl DeliveryConfirmationPayments for () { +impl DeliveryConfirmationPayments for () { type Error = &'static str; fn pay_reward( @@ -94,14 +96,14 @@ impl DeliveryConfirmationPayments for () { /// Callback that is called at the source chain (bridge hub) when we get delivery confirmation /// for new messages. -pub trait OnMessagesDelivered { +pub trait OnMessagesDelivered { /// New messages delivery has been confirmed. /// /// The only argument of the function is the number of yet undelivered messages fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce); } -impl OnMessagesDelivered for () { +impl OnMessagesDelivered for () { fn on_messages_delivered(_lane: LaneId, _enqueued_messages: MessageNonce) {} } @@ -115,7 +117,7 @@ pub struct SendMessageArtifacts { } /// Messages bridge API to be used from other pallets. -pub trait MessagesBridge { +pub trait MessagesBridge { /// Error type. type Error: Debug; @@ -141,7 +143,7 @@ pub trait MessagesBridge { /// where outbound messages are forbidden. pub struct ForbidOutboundMessages; -impl DeliveryConfirmationPayments for ForbidOutboundMessages { +impl DeliveryConfirmationPayments for ForbidOutboundMessages { type Error = &'static str; fn pay_reward( diff --git a/bridges/primitives/messages/src/storage_keys.rs b/bridges/primitives/messages/src/storage_keys.rs index ff62dab078e7..fb3371cb830c 100644 --- a/bridges/primitives/messages/src/storage_keys.rs +++ b/bridges/primitives/messages/src/storage_keys.rs @@ -25,7 +25,7 @@ pub const OUTBOUND_LANES_MAP_NAME: &str = "OutboundLanes"; /// Name of the `InboundLanes` storage map. pub const INBOUND_LANES_MAP_NAME: &str = "InboundLanes"; -use crate::{LaneId, MessageKey, MessageNonce}; +use crate::{MessageKey, MessageNonce}; use codec::Encode; use frame_support::Blake2_128Concat; @@ -43,16 +43,20 @@ pub fn operating_mode_key(pallet_prefix: &str) -> StorageKey { } /// Storage key of the outbound message in the runtime storage. -pub fn message_key(pallet_prefix: &str, lane: &LaneId, nonce: MessageNonce) -> StorageKey { +pub fn message_key( + pallet_prefix: &str, + lane: LaneId, + nonce: MessageNonce, +) -> StorageKey { bp_runtime::storage_map_final_key::( pallet_prefix, OUTBOUND_MESSAGES_MAP_NAME, - &MessageKey { lane_id: *lane, nonce }.encode(), + &MessageKey { lane_id: lane, nonce }.encode(), ) } /// Storage key of the outbound message lane state in the runtime storage. -pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { +pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { bp_runtime::storage_map_final_key::( pallet_prefix, OUTBOUND_LANES_MAP_NAME, @@ -61,7 +65,7 @@ pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey } /// Storage key of the inbound message lane state in the runtime storage. -pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { +pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { bp_runtime::storage_map_final_key::( pallet_prefix, INBOUND_LANES_MAP_NAME, @@ -72,7 +76,10 @@ pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { #[cfg(test)] mod tests { use super::*; - use frame_support::sp_runtime::Either; + use crate::{ + lane::{HashedLaneId, LegacyLaneId}, + LaneIdType, + }; use hex_literal::hex; #[test] @@ -92,7 +99,8 @@ mod tests { fn storage_message_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted messages proofs. - let storage_key = message_key("BridgeMessages", &LaneId::new(1, 2), 42).0; + let storage_key = + message_key("BridgeMessages", &HashedLaneId::try_new(1, 2).unwrap(), 42).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea70e9bdb8f50c68d12f06eabb57759ee5eb1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea02a00000000000000").to_vec(), @@ -101,8 +109,7 @@ mod tests { ); // check backwards compatibility - let storage_key = - message_key("BridgeMessages", &LaneId::from_inner(Either::Right(*b"test")), 42).0; + let storage_key = message_key("BridgeMessages", &LegacyLaneId(*b"test"), 42).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), @@ -115,7 +122,8 @@ mod tests { fn outbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted outbound lane state proofs. - let storage_key = outbound_lane_data_key("BridgeMessages", &LaneId::new(1, 2)).0; + let storage_key = + outbound_lane_data_key("BridgeMessages", &HashedLaneId::try_new(1, 2).unwrap()).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1fd3bef8b00df8ca7b01813b5e2741950db1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea0").to_vec(), @@ -124,9 +132,7 @@ mod tests { ); // check backwards compatibility - let storage_key = - outbound_lane_data_key("BridgeMessages", &LaneId::from_inner(Either::Right(*b"test"))) - .0; + let storage_key = outbound_lane_data_key("BridgeMessages", &LegacyLaneId(*b"test")).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), @@ -139,7 +145,8 @@ mod tests { fn inbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted inbound lane state proofs. - let storage_key = inbound_lane_data_key("BridgeMessages", &LaneId::new(1, 2)).0; + let storage_key = + inbound_lane_data_key("BridgeMessages", &HashedLaneId::try_new(1, 2).unwrap()).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fabd3bef8b00df8ca7b01813b5e2741950db1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea0").to_vec(), @@ -148,8 +155,7 @@ mod tests { ); // check backwards compatibility - let storage_key = - inbound_lane_data_key("BridgeMessages", &LaneId::from_inner(Either::Right(*b"test"))).0; + let storage_key = inbound_lane_data_key("BridgeMessages", &LegacyLaneId(*b"test")).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs index 67868ff7c7cd..cf07a400933a 100644 --- a/bridges/primitives/messages/src/target_chain.rs +++ b/bridges/primitives/messages/src/target_chain.rs @@ -16,7 +16,7 @@ //! Primitives of messages module, that are used on the target chain. -use crate::{LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData}; +use crate::{Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData}; use bp_runtime::{messages::MessageDispatchResult, raw_storage_proof_size, RawStorageProof, Size}; use codec::{Decode, Encode, Error as CodecError}; @@ -38,20 +38,20 @@ use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; /// /// - nonces (inclusive range) of messages which are included in this proof. #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct FromBridgedChainMessagesProof { +pub struct FromBridgedChainMessagesProof { /// Hash of the finalized bridged header the proof is for. pub bridged_header_hash: BridgedHeaderHash, /// A storage trie proof of messages being delivered. pub storage_proof: RawStorageProof, /// Messages in this proof are sent over this lane. - pub lane: LaneId, + pub lane: Lane, /// Nonce of the first message being delivered. pub nonces_start: MessageNonce, /// Nonce of the last message being delivered. pub nonces_end: MessageNonce, } -impl Size for FromBridgedChainMessagesProof { +impl Size for FromBridgedChainMessagesProof { fn size(&self) -> u32 { use frame_support::sp_runtime::SaturatedConversion; raw_storage_proof_size(&self.storage_proof).saturated_into() @@ -59,7 +59,7 @@ impl Size for FromBridgedChainMessagesProof = (LaneId, ProvedLaneMessages); +pub type ProvedMessages = (LaneId, ProvedLaneMessages); /// Proved messages from single lane of the source chain. #[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] @@ -79,9 +79,9 @@ pub struct DispatchMessageData { /// Message with decoded dispatch payload. #[derive(RuntimeDebug)] -pub struct DispatchMessage { +pub struct DispatchMessage { /// Message key. - pub key: MessageKey, + pub key: MessageKey, /// Message data with decoded dispatch payload. pub data: DispatchMessageData, } @@ -96,6 +96,9 @@ pub trait MessageDispatch { /// Fine-grained result of single message dispatch (for better diagnostic purposes) type DispatchLevelResult: Clone + sp_std::fmt::Debug + Eq; + /// Lane identifier type. + type LaneId: Encode; + /// Returns `true` if dispatcher is ready to accept additional messages. The `false` should /// be treated as a hint by both dispatcher and its consumers - i.e. dispatcher shall not /// simply drop messages if it returns `false`. The consumer may still call the `dispatch` @@ -103,21 +106,23 @@ pub trait MessageDispatch { /// /// We check it in the messages delivery transaction prologue. So if it becomes `false` /// after some portion of messages is already dispatched, it doesn't fail the whole transaction. - fn is_active(lane: LaneId) -> bool; + fn is_active(lane: Self::LaneId) -> bool; /// Estimate dispatch weight. /// /// This function must return correct upper bound of dispatch weight. The return value /// of this function is expected to match return value of the corresponding /// `FromInboundLaneApi::message_details().dispatch_weight` call. - fn dispatch_weight(message: &mut DispatchMessage) -> Weight; + fn dispatch_weight( + message: &mut DispatchMessage, + ) -> Weight; /// Called when inbound message is received. /// /// It is up to the implementers of this trait to determine whether the message /// is invalid (i.e. improperly encoded, has too large weight, ...) or not. fn dispatch( - message: DispatchMessage, + message: DispatchMessage, ) -> MessageDispatchResult; } @@ -146,8 +151,10 @@ impl Default for ProvedLaneMessages { } } -impl From for DispatchMessage { - fn from(message: Message) -> Self { +impl From> + for DispatchMessage +{ + fn from(message: Message) -> Self { DispatchMessage { key: message.key, data: message.payload.into() } } } @@ -173,22 +180,27 @@ impl DeliveryPayments for () { /// Structure that may be used in place of `MessageDispatch` on chains, /// where inbound messages are forbidden. -pub struct ForbidInboundMessages(PhantomData); +pub struct ForbidInboundMessages(PhantomData<(DispatchPayload, LaneId)>); -impl MessageDispatch for ForbidInboundMessages { +impl MessageDispatch + for ForbidInboundMessages +{ type DispatchPayload = DispatchPayload; type DispatchLevelResult = (); + type LaneId = LaneId; fn is_active(_: LaneId) -> bool { false } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::MAX } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } diff --git a/bridges/primitives/relayers/src/extension.rs b/bridges/primitives/relayers/src/extension.rs index 5ab8e6cde96b..a9fa4df27ead 100644 --- a/bridges/primitives/relayers/src/extension.rs +++ b/bridges/primitives/relayers/src/extension.rs @@ -21,6 +21,7 @@ use bp_header_chain::SubmitFinalityProofInfo; use bp_messages::MessagesCallInfo; use bp_parachains::SubmitParachainHeadsInfo; use bp_runtime::StaticStrProvider; +use codec::{Decode, Encode}; use frame_support::{ dispatch::CallableCallFor, traits::IsSubType, weights::Weight, RuntimeDebugNoBound, }; @@ -35,25 +36,28 @@ use sp_std::{fmt::Debug, marker::PhantomData, vec, vec::Vec}; /// Type of the call that the signed extension recognizes. #[derive(PartialEq, RuntimeDebugNoBound)] -pub enum ExtensionCallInfo { +pub enum ExtensionCallInfo { /// Relay chain finality + parachain finality + message delivery/confirmation calls. AllFinalityAndMsgs( SubmitFinalityProofInfo, SubmitParachainHeadsInfo, - MessagesCallInfo, + MessagesCallInfo, ), /// Relay chain finality + message delivery/confirmation calls. - RelayFinalityAndMsgs(SubmitFinalityProofInfo, MessagesCallInfo), + RelayFinalityAndMsgs( + SubmitFinalityProofInfo, + MessagesCallInfo, + ), /// Parachain finality + message delivery/confirmation calls. /// /// This variant is used only when bridging with parachain. - ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), + ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), /// Standalone message delivery/confirmation call. - Msgs(MessagesCallInfo), + Msgs(MessagesCallInfo), } -impl - ExtensionCallInfo +impl + ExtensionCallInfo { /// Returns true if call is a message delivery call (with optional finality calls). pub fn is_receive_messages_proof_call(&self) -> bool { @@ -84,7 +88,7 @@ impl } /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. - pub fn messages_call_info(&self) -> &MessagesCallInfo { + pub fn messages_call_info(&self) -> &MessagesCallInfo { match self { Self::AllFinalityAndMsgs(_, _, info) => info, Self::RelayFinalityAndMsgs(_, info) => info, @@ -119,25 +123,27 @@ pub trait ExtensionConfig { /// Runtime that optionally supports batched calls. We assume that batched call /// succeeds if and only if all of its nested calls succeed. type Runtime: frame_system::Config; + /// Relayers pallet instance. + type BridgeRelayersPalletInstance: 'static; /// Messages pallet instance. type BridgeMessagesPalletInstance: 'static; /// Additional priority that is added to base message delivery transaction priority /// for every additional bundled message. type PriorityBoostPerMessage: Get; - /// Type of reward, that the `pallet-bridge-relayers` is using. - type Reward; /// Block number for the remote **GRANDPA chain**. Mind that this chain is not /// necessarily the chain that we are bridging with. If we are bridging with /// parachain, it must be its parent relay chain. If we are bridging with the /// GRANDPA chain, it must be it. type RemoteGrandpaChainBlockNumber: Clone + Copy + Debug; + /// Lane identifier type. + type LaneId: Clone + Copy + Decode + Encode + Debug; /// Given runtime call, check if it is supported by the signed extension. Additionally, /// check if call (or any of batched calls) are obsolete. fn parse_and_check_for_obsolete_call( call: &::RuntimeCall, ) -> Result< - Option>, + Option>, TransactionValidityError, >; @@ -149,7 +155,7 @@ pub trait ExtensionConfig { /// Given runtime call info, check that this call has been successful and has updated /// runtime storage accordingly. fn check_call_result( - call_info: &ExtensionCallInfo, + call_info: &ExtensionCallInfo, call_data: &mut ExtensionCallData, relayer: &::AccountId, ) -> bool; diff --git a/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs index 1e63c89ecd70..faa4cb177629 100644 --- a/bridges/primitives/relayers/src/lib.rs +++ b/bridges/primitives/relayers/src/lib.rs @@ -25,7 +25,6 @@ pub use extension::{ }; pub use registration::{ExplicitOrAccountParams, Registration, StakeAndSlash}; -use bp_messages::LaneId; use bp_runtime::{ChainId, StorageDoubleMapKeyProvider}; use frame_support::{traits::tokens::Preservation, Blake2_128Concat, Identity}; use scale_info::TypeInfo; @@ -61,7 +60,7 @@ pub enum RewardsAccountOwner { /// of the sovereign accounts will pay rewards for different operations. So we need multiple /// parameters to identify the account that pays a reward to the relayer. #[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] -pub struct RewardsAccountParams { +pub struct RewardsAccountParams { // **IMPORTANT NOTE**: the order of fields here matters - we are using // `into_account_truncating` and lane id is already `32` byte, so if other fields are encoded // after it, they're simply dropped. So lane id shall be the last field. @@ -70,7 +69,7 @@ pub struct RewardsAccountParams { lane_id: LaneId, } -impl RewardsAccountParams { +impl RewardsAccountParams { /// Create a new instance of `RewardsAccountParams`. pub const fn new( lane_id: LaneId, @@ -79,9 +78,14 @@ impl RewardsAccountParams { ) -> Self { Self { lane_id, bridged_chain_id, owner } } + + /// Getter for `lane_id`. + pub const fn lane_id(&self) -> &LaneId { + &self.lane_id + } } -impl TypeId for RewardsAccountParams { +impl TypeId for RewardsAccountParams { const TYPE_ID: [u8; 4] = *b"brap"; } @@ -89,47 +93,58 @@ impl TypeId for RewardsAccountParams { pub trait PaymentProcedure { /// Error that may be returned by the procedure. type Error: Debug; + /// Lane identifier type. + type LaneId: Decode + Encode; /// Pay reward to the relayer from the account with provided params. fn pay_reward( relayer: &Relayer, - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, reward: Reward, ) -> Result<(), Self::Error>; } impl PaymentProcedure for () { type Error = &'static str; + type LaneId = (); - fn pay_reward(_: &Relayer, _: RewardsAccountParams, _: Reward) -> Result<(), Self::Error> { + fn pay_reward( + _: &Relayer, + _: RewardsAccountParams, + _: Reward, + ) -> Result<(), Self::Error> { Ok(()) } } /// Reward payment procedure that does `balances::transfer` call from the account, derived from /// given params. -pub struct PayRewardFromAccount(PhantomData<(T, Relayer)>); +pub struct PayRewardFromAccount(PhantomData<(T, Relayer, LaneId)>); -impl PayRewardFromAccount +impl PayRewardFromAccount where Relayer: Decode + Encode, + LaneId: Decode + Encode, { /// Return account that pays rewards based on the provided parameters. - pub fn rewards_account(params: RewardsAccountParams) -> Relayer { + pub fn rewards_account(params: RewardsAccountParams) -> Relayer { params.into_sub_account_truncating(b"rewards-account") } } -impl PaymentProcedure for PayRewardFromAccount +impl PaymentProcedure + for PayRewardFromAccount where T: frame_support::traits::fungible::Mutate, Relayer: Decode + Encode + Eq, + LaneId: Decode + Encode, { type Error = sp_runtime::DispatchError; + type LaneId = LaneId; fn pay_reward( relayer: &Relayer, - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, reward: T::Balance, ) -> Result<(), Self::Error> { T::transfer( @@ -142,48 +157,56 @@ where } } -/// Can be use to access the runtime storage key within the `RelayerRewards` map of the relayers +/// Can be used to access the runtime storage key within the `RelayerRewards` map of the relayers /// pallet. -pub struct RelayerRewardsKeyProvider(PhantomData<(AccountId, Reward)>); +pub struct RelayerRewardsKeyProvider( + PhantomData<(AccountId, Reward, LaneId)>, +); -impl StorageDoubleMapKeyProvider for RelayerRewardsKeyProvider +impl StorageDoubleMapKeyProvider + for RelayerRewardsKeyProvider where AccountId: 'static + Codec + EncodeLike + Send + Sync, Reward: 'static + Codec + EncodeLike + Send + Sync, + LaneId: Codec + EncodeLike + Send + Sync, { const MAP_NAME: &'static str = "RelayerRewards"; type Hasher1 = Blake2_128Concat; type Key1 = AccountId; type Hasher2 = Identity; - type Key2 = RewardsAccountParams; + type Key2 = RewardsAccountParams; type Value = Reward; } #[cfg(test)] mod tests { use super::*; - use bp_messages::LaneId; - use sp_runtime::testing::H256; + use bp_messages::{HashedLaneId, LaneIdType, LegacyLaneId}; + use sp_runtime::{app_crypto::Ss58Codec, testing::H256}; #[test] fn different_lanes_are_using_different_accounts() { assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId::new(1, 2), - *b"test", - RewardsAccountOwner::ThisChain - )), + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain + ) + ), hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId::new(1, 3), - *b"test", - RewardsAccountOwner::ThisChain - )), + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 3).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain + ) + ), hex_literal::hex!("627261700074657374a43e8951aa302c133beb5f85821a21645f07b487270ef3") .into(), ); @@ -192,23 +215,101 @@ mod tests { #[test] fn different_directions_are_using_different_accounts() { assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId::new(1, 2), - *b"test", - RewardsAccountOwner::ThisChain - )), + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain + ) + ), hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId::new(1, 2), - *b"test", - RewardsAccountOwner::BridgedChain - )), + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::BridgedChain + ) + ), hex_literal::hex!("627261700174657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); } + + #[test] + fn pay_reward_from_account_for_legacy_lane_id_works() { + let test_data = vec![ + // Note: these accounts are used for integration tests within + // `bridges_rococo_westend.sh` + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhks", + RewardsAccountOwner::ThisChain, + (0_u16, "13E5fui97x6KTwNnSjaEKZ8s7kJNot5F3aUsy3jUtuoMyUec"), + ), + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhks", + RewardsAccountOwner::BridgedChain, + (0_u16, "13E5fui9Ka9Vz4JbGN3xWjmwDNxnxF1N9Hhhbeu3VCqLChuj"), + ), + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhpd", + RewardsAccountOwner::ThisChain, + (2_u16, "EoQBtnwtXqnSnr9cgBEJpKU7NjeC9EnR4D1VjgcvHz9ZYmS"), + ), + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhpd", + RewardsAccountOwner::BridgedChain, + (2_u16, "EoQBtnx69txxumxSJexVzxYD1Q4LWAuWmRq8LrBWb27nhYN"), + ), + // Note: these accounts are used for integration tests within + // `bridges_polkadot_kusama.sh` from fellows. + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhwd", + RewardsAccountOwner::ThisChain, + (4_u16, "SNihsskf7bFhnHH9HJFMjWD3FJ96ESdAQTFZUAtXudRQbaH"), + ), + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhwd", + RewardsAccountOwner::BridgedChain, + (4_u16, "SNihsskrjeSDuD5xumyYv9H8sxZEbNkG7g5C5LT8CfPdaSE"), + ), + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhro", + RewardsAccountOwner::ThisChain, + (4_u16, "SNihsskf7bF2vWogkC6uFoiqPhd3dUX6TGzYZ1ocJdo3xHp"), + ), + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhro", + RewardsAccountOwner::BridgedChain, + (4_u16, "SNihsskrjeRZ3ScWNfq6SSnw2N3BzQeCAVpBABNCbfmHENB"), + ), + ]; + + for (lane_id, bridged_chain_id, owner, (expected_ss58, expected_account)) in test_data { + assert_eq!( + expected_account, + sp_runtime::AccountId32::new(PayRewardFromAccount::< + [u8; 32], + [u8; 32], + LegacyLaneId, + >::rewards_account(RewardsAccountParams::new( + lane_id, + *bridged_chain_id, + owner + ))) + .to_ss58check_with_version(expected_ss58.into()) + ); + } + } } diff --git a/bridges/primitives/relayers/src/registration.rs b/bridges/primitives/relayers/src/registration.rs index 9d9b7e481220..d74ef18cf706 100644 --- a/bridges/primitives/relayers/src/registration.rs +++ b/bridges/primitives/relayers/src/registration.rs @@ -48,15 +48,17 @@ use sp_runtime::{ /// Either explicit account reference or `RewardsAccountParams`. #[derive(Clone, Debug)] -pub enum ExplicitOrAccountParams { +pub enum ExplicitOrAccountParams { /// Explicit account reference. Explicit(AccountId), /// Account, referenced using `RewardsAccountParams`. - Params(RewardsAccountParams), + Params(RewardsAccountParams), } -impl From for ExplicitOrAccountParams { - fn from(params: RewardsAccountParams) -> Self { +impl From> + for ExplicitOrAccountParams +{ + fn from(params: RewardsAccountParams) -> Self { ExplicitOrAccountParams::Params(params) } } @@ -103,9 +105,9 @@ pub trait StakeAndSlash { /// `beneficiary`. /// /// Returns `Ok(_)` with non-zero balance if we have failed to repatriate some portion of stake. - fn repatriate_reserved( + fn repatriate_reserved( relayer: &AccountId, - beneficiary: ExplicitOrAccountParams, + beneficiary: ExplicitOrAccountParams, amount: Balance, ) -> Result; } @@ -126,9 +128,9 @@ where Zero::zero() } - fn repatriate_reserved( + fn repatriate_reserved( _relayer: &AccountId, - _beneficiary: ExplicitOrAccountParams, + _beneficiary: ExplicitOrAccountParams, _amount: Balance, ) -> Result { Ok(Zero::zero()) diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 0db4eac79a75..eba3bcadfead 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -365,17 +365,23 @@ macro_rules! decl_bridge_finality_runtime_apis { }; } +// Re-export to avoid include tuplex dependency everywhere. +#[doc(hidden)] +pub mod __private { + pub use codec; +} + /// Convenience macro that declares bridge messages runtime apis and related constants for a chain. /// This includes: /// - chain-specific bridge runtime APIs: -/// - `ToOutboundLaneApi` -/// - `FromInboundLaneApi` +/// - `ToOutboundLaneApi` +/// - `FromInboundLaneApi` /// - constants that are stringified names of runtime API methods: /// - `FROM__MESSAGE_DETAILS_METHOD`, /// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_messages_runtime_apis { - ($chain: ident) => { + ($chain: ident, $lane_id_type:ty) => { bp_runtime::paste::item! { mod [<$chain _messages_api>] { use super::*; @@ -400,7 +406,7 @@ macro_rules! decl_bridge_messages_runtime_apis { /// If some (or all) messages are missing from the storage, they'll also will /// be missing from the resulting vector. The vector is ordered by the nonce. fn message_details( - lane: bp_messages::LaneId, + lane: $lane_id_type, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> sp_std::vec::Vec; @@ -416,7 +422,7 @@ macro_rules! decl_bridge_messages_runtime_apis { pub trait [] { /// Return details of given inbound messages. fn message_details( - lane: bp_messages::LaneId, + lane: $lane_id_type, messages: sp_std::vec::Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> sp_std::vec::Vec; } @@ -433,8 +439,8 @@ macro_rules! decl_bridge_messages_runtime_apis { /// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_runtime_apis { - ($chain: ident $(, $consensus: ident)?) => { + ($chain: ident $(, $consensus: ident, $lane_id_type:ident)?) => { bp_runtime::decl_bridge_finality_runtime_apis!($chain $(, $consensus)?); - bp_runtime::decl_bridge_messages_runtime_apis!($chain); + bp_runtime::decl_bridge_messages_runtime_apis!($chain, $lane_id_type); }; } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 8f5040ad9a1b..90eb72922bea 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -36,7 +36,7 @@ use sp_std::{fmt::Debug, ops::RangeInclusive, vec, vec::Vec}; pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf, HasherOf, HeaderOf, NonceOf, Parachain, ParachainIdOf, SignatureOf, TransactionEraOf, - UnderlyingChainOf, UnderlyingChainProvider, + UnderlyingChainOf, UnderlyingChainProvider, __private, }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; @@ -272,7 +272,7 @@ pub trait StorageMapKeyProvider { } } -/// Can be use to access the runtime storage key of a `StorageDoubleMap`. +/// Can be used to access the runtime storage key of a `StorageDoubleMap`. pub trait StorageDoubleMapKeyProvider { /// The name of the variable that holds the `StorageDoubleMap`. const MAP_NAME: &'static str; diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 44a90a57d4fb..061e7a275063 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -19,7 +19,7 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use bp_messages::LaneId; +use bp_messages::LaneIdType; use bp_runtime::{AccountIdOf, BalanceOf, Chain}; pub use call_info::XcmBridgeHubCall; use codec::{Decode, Encode, MaxEncodedLen}; @@ -63,7 +63,6 @@ pub type XcmAsPlainPayload = sp_std::vec::Vec; Ord, PartialOrd, PartialEq, - RuntimeDebug, TypeInfo, MaxEncodedLen, Serialize, @@ -90,6 +89,12 @@ impl BridgeId { } } +impl core::fmt::Debug for BridgeId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.0, f) + } +} + /// Local XCM channel manager. pub trait LocalXcmChannelManager { /// Error that may be returned when suspending/resuming the bridge. @@ -149,8 +154,8 @@ pub enum BridgeState { #[derive( CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound, )] -#[scale_info(skip_type_params(ThisChain))] -pub struct Bridge { +#[scale_info(skip_type_params(ThisChain, LaneId))] +pub struct Bridge { /// Relative location of the bridge origin chain. This is expected to be **convertible** to the /// `latest` XCM, so the check and migration needs to be ensured. pub bridge_origin_relative_location: Box, @@ -204,6 +209,8 @@ pub enum BridgeLocationsError { UnsupportedDestinationLocation, /// The version of XCM location argument is unsupported. UnsupportedXcmVersion, + /// The `LaneIdType` generator is not supported. + UnsupportedLaneIdType, } impl BridgeLocations { @@ -318,7 +325,7 @@ impl BridgeLocations { /// Generates the exact same `LaneId` on the both bridge hubs. /// /// Note: Use this **only** when opening a new bridge. - pub fn calculate_lane_id( + pub fn calculate_lane_id( &self, xcm_version: XcmVersion, ) -> Result { @@ -341,10 +348,11 @@ impl BridgeLocations { .into_version(xcm_version) .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); - Ok(LaneId::new( + LaneId::try_new( EncodedVersionedInteriorLocation(universal_location1.encode()), EncodedVersionedInteriorLocation(universal_location2.encode()), - )) + ) + .map_err(|_| BridgeLocationsError::UnsupportedLaneIdType) } } @@ -590,6 +598,8 @@ mod tests { #[test] fn calculate_lane_id_works() { + type TestLaneId = bp_messages::HashedLaneId; + let from_local_to_remote = run_successful_test(SuccessfulTest { here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] .into(), @@ -631,12 +641,12 @@ mod tests { }); assert_ne!( - from_local_to_remote.calculate_lane_id(xcm::latest::VERSION), - from_remote_to_local.calculate_lane_id(xcm::latest::VERSION - 1), + from_local_to_remote.calculate_lane_id::(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id::(xcm::latest::VERSION - 1), ); assert_eq!( - from_local_to_remote.calculate_lane_id(xcm::latest::VERSION), - from_remote_to_local.calculate_lane_id(xcm::latest::VERSION), + from_local_to_remote.calculate_lane_id::(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id::(xcm::latest::VERSION), ); } diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index 227e9c31c5bf..9856f0d0237e 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -113,9 +113,6 @@ impl Parachain for T where T: UnderlyingChainProvider + Chain + ParachainBase /// Substrate-based chain with messaging support from minimal relay-client point of view. pub trait ChainWithMessages: Chain + ChainWithMessagesBase { - // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): check all the names - // after the issue is fixed - all names must be changed - /// Name of the bridge relayers pallet (used in `construct_runtime` macro call) that is deployed /// at some other chain to bridge with this `ChainWithMessages`. /// diff --git a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs index 28b0eb0ad526..2e15562f6c2e 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs @@ -23,9 +23,12 @@ use crate::{ parachains::SubstrateParachainsPipeline, }; use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use codec::{Codec, EncodeLike}; +use messages_relay::Labeled; use relay_substrate_client::{ Chain, ChainWithRuntimeVersion, ChainWithTransactions, Parachain, RelayChain, }; +use std::fmt::Debug; /// Minimal bridge representation that can be used from the CLI. /// It connects a source chain to a target chain. @@ -99,7 +102,22 @@ where /// Bridge representation that can be used from the CLI for relaying messages. pub trait MessagesCliBridge: CliBridgeBase { /// The Source -> Destination messages synchronization pipeline. - type MessagesLane: SubstrateMessageLane; + type MessagesLane: SubstrateMessageLane< + SourceChain = Self::Source, + TargetChain = Self::Target, + LaneId = Self::LaneId, + >; + /// Lane identifier type. + type LaneId: Clone + + Copy + + Debug + + Codec + + EncodeLike + + Send + + Sync + + Labeled + + TryFrom> + + Default; /// Optional messages delivery transaction limits that the messages relay is going /// to use. If it returns `None`, limits are estimated using `TransactionPayment` API @@ -108,3 +126,6 @@ pub trait MessagesCliBridge: CliBridgeBase { None } } + +/// An alias for lane identifier type. +pub type MessagesLaneIdOf = ::LaneId; diff --git a/bridges/relays/lib-substrate-relay/src/cli/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/mod.rs index ef8403ff68ee..be64866fc14b 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/mod.rs @@ -16,10 +16,8 @@ //! Deal with CLI args of substrate-to-substrate relay. -use bp_messages::LaneId; use rbtag::BuildInfo; -use sp_core::H256; -use sp_runtime::Either; +use sp_runtime::traits::TryConvert; use std::str::FromStr; use structopt::StructOpt; use strum::{EnumString, VariantNames}; @@ -43,36 +41,19 @@ pub type DefaultClient = relay_substrate_client::RpcWithCachingClient; /// Lane id. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HexLaneId(Either); +pub struct HexLaneId(Vec); -impl From for LaneId { - fn from(lane_id: HexLaneId) -> LaneId { - LaneId::from_inner(lane_id.0) +impl>> TryConvert for HexLaneId { + fn try_convert(lane_id: HexLaneId) -> Result { + T::try_from(lane_id.0.clone()).map_err(|_| lane_id) } } impl FromStr for HexLaneId { - type Err = rustc_hex::FromHexError; + type Err = hex::FromHexError; fn from_str(s: &str) -> Result { - // check `H256` variant at first - match H256::from_str(s) { - Ok(hash) => Ok(HexLaneId(Either::Left(hash))), - Err(hash_error) => { - // check backwards compatible - let mut lane_id = [0u8; 4]; - match hex::decode_to_slice(s, &mut lane_id) { - Ok(_) => Ok(HexLaneId(Either::Right(lane_id))), - Err(array_error) => { - log::error!( - target: "bridge", - "Failed to parse `HexLaneId` as hex string: {s:?} - hash_error: {hash_error:?}, array_error: {array_error:?}", - ); - Err(hash_error) - }, - } - }, - } + hex::decode(s).map(Self) } } @@ -172,6 +153,8 @@ pub enum RuntimeVersionType { #[cfg(test)] mod tests { use super::*; + use bp_messages::{HashedLaneId, LegacyLaneId}; + use sp_core::H256; #[test] fn hex_lane_id_from_str_works() { @@ -185,21 +168,21 @@ mod tests { ) .is_err()); assert_eq!( - LaneId::from( + HexLaneId::try_convert( HexLaneId::from_str( "0101010101010101010101010101010101010101010101010101010101010101" ) .unwrap() ), - LaneId::from_inner(Either::Left(H256::from([1u8; 32]))) + Ok(HashedLaneId::from_inner(H256::from([1u8; 32]))) ); // array variant assert!(HexLaneId::from_str("0000001").is_err()); assert!(HexLaneId::from_str("000000001").is_err()); assert_eq!( - LaneId::from(HexLaneId::from_str("00000001").unwrap()), - LaneId::from_inner(Either::Right([0, 0, 0, 1])) + HexLaneId::try_convert(HexLaneId::from_str("00000001").unwrap()), + Ok(LegacyLaneId([0, 0, 0, 1])) ); } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs index 3786976bed9b..e875c53a2e7e 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs @@ -31,25 +31,30 @@ pub mod relay_to_relay; pub mod relay_to_parachain; use async_trait::async_trait; -use std::{marker::PhantomData, sync::Arc}; +use codec::{Codec, EncodeLike}; +use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use structopt::StructOpt; use futures::{FutureExt, TryFutureExt}; use crate::{ - cli::{bridge::MessagesCliBridge, DefaultClient, HexLaneId, PrometheusParams}, + cli::{ + bridge::{MessagesCliBridge, MessagesLaneIdOf}, + DefaultClient, HexLaneId, PrometheusParams, + }, messages::{MessagesRelayLimits, MessagesRelayParams}, on_demand::OnDemandRelay, HeadersToRelay, TaggedAccount, TransactionParams, }; -use bp_messages::LaneId; use bp_runtime::BalanceOf; +use messages_relay::Labeled; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithMessages, ChainWithRuntimeVersion, ChainWithTransactions, }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; +use sp_runtime::traits::TryConvert; /// Parameters that have the same names across all bridges. #[derive(Debug, PartialEq, StructOpt)] @@ -163,7 +168,7 @@ where &self, source_to_target_headers_relay: Arc>, target_to_source_headers_relay: Arc>, - lane_id: LaneId, + lane_id: MessagesLaneIdOf, maybe_limits: Option, ) -> MessagesRelayParams, DefaultClient> { MessagesRelayParams { @@ -234,9 +239,20 @@ where + ChainWithRuntimeVersion; /// Left to Right bridge. - type L2R: MessagesCliBridge; + type L2R: MessagesCliBridge; /// Right to Left bridge - type R2L: MessagesCliBridge; + type R2L: MessagesCliBridge; + /// Lane identifier type. + type LaneId: Clone + + Copy + + Debug + + Codec + + EncodeLike + + Send + + Sync + + Labeled + + TryFrom> + + Default; /// Construct new bridge. fn new(params: ::Params) -> anyhow::Result; @@ -287,29 +303,30 @@ where self.mut_base().start_on_demand_headers_relayers().await?; // add balance-related metrics - let lanes = self + let lanes: Vec = self .base() .common() .shared .lane .iter() .cloned() - .map(Into::into) - .collect::>(); + .map(HexLaneId::try_convert) + .collect::, HexLaneId>>() + .expect(""); { let common = self.mut_base().mut_common(); - crate::messages::metrics::add_relay_balances_metrics::<_, Self::Right>( - common.left.client.clone(), - &common.metrics_params, - &common.left.accounts, - &lanes, - ) + crate::messages::metrics::add_relay_balances_metrics::< + _, + Self::Right, + MessagesLaneIdOf, + >(common.left.client.clone(), &common.metrics_params, &common.left.accounts, &lanes) .await?; - crate::messages::metrics::add_relay_balances_metrics::<_, Self::Left>( - common.right.client.clone(), - &common.metrics_params, - &common.right.accounts, - &lanes, + crate::messages::metrics::add_relay_balances_metrics::< + _, + Self::Left, + MessagesLaneIdOf, + >( + common.right.client.clone(), &common.metrics_params, &common.right.accounts, &lanes ) .await?; } @@ -359,8 +376,6 @@ mod tests { use crate::{cli::chain_schema::RuntimeVersionType, declare_chain_cli_schema}; use relay_substrate_client::{ChainRuntimeVersion, Parachain, SimpleRuntimeVersion}; - use sp_core::H256; - use sp_runtime::Either; #[test] // We need `#[allow(dead_code)]` because some of the methods generated by the macros @@ -434,7 +449,7 @@ mod tests { res, BridgeHubKusamaBridgeHubPolkadotHeadersAndMessages { shared: HeadersAndMessagesSharedParams { - lane: vec![HexLaneId(Either::Left(H256::from([0x00u8; 32])))], + lane: vec![HexLaneId(vec![0x00u8; 32])], only_mandatory_headers: false, only_free_headers: false, prometheus_params: PrometheusParams { diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index 34d5226e90c5..3878b081d6c3 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -33,6 +33,7 @@ use relay_substrate_client::{ ChainWithTransactions, Client, }; use relay_utils::UniqueSaturatedInto; +use sp_runtime::traits::TryConvert; /// Messages relaying params. #[derive(StructOpt)] @@ -116,6 +117,9 @@ where let target_client = data.target.into_client::().await?; let target_sign = data.target_sign.to_keypair::()?; let target_transactions_mortality = data.target_sign.transactions_mortality()?; + let lane_id = HexLaneId::try_convert(data.lane).map_err(|invalid_lane_id| { + anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) + })?; crate::messages::run::(MessagesRelayParams { source_client, @@ -130,7 +134,7 @@ where }, source_to_target_headers_relay: None, target_to_source_headers_relay: None, - lane_id: data.lane.into(), + lane_id, limits: Self::maybe_messages_limits(), metrics_params: data.prometheus_params.into_metrics_params()?, }) @@ -146,6 +150,9 @@ where let source_transactions_mortality = data.source_sign.transactions_mortality()?; let target_sign = data.target_sign.to_keypair::()?; let target_transactions_mortality = data.target_sign.transactions_mortality()?; + let lane_id = HexLaneId::try_convert(data.lane).map_err(|invalid_lane_id| { + anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) + })?; let at_source_block = source_client .header_by_number(data.at_source_block.unique_saturated_into()) @@ -167,7 +174,7 @@ where TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, TransactionParams { signer: target_sign, mortality: target_transactions_mortality }, at_source_block, - data.lane.into(), + lane_id, data.messages_start..=data.messages_end, data.outbound_state_proof_required, ) @@ -182,6 +189,9 @@ where let target_client = data.target.into_client::().await?; let source_sign = data.source_sign.to_keypair::()?; let source_transactions_mortality = data.source_sign.transactions_mortality()?; + let lane_id = HexLaneId::try_convert(data.lane).map_err(|invalid_lane_id| { + anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) + })?; let at_target_block = target_client .header_by_number(data.at_target_block.unique_saturated_into()) @@ -202,7 +212,7 @@ where target_client, TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, at_target_block, - data.lane.into(), + lane_id, ) .await } diff --git a/bridges/relays/lib-substrate-relay/src/messages/metrics.rs b/bridges/relays/lib-substrate-relay/src/messages/metrics.rs index 8845f43dcb62..efe429701c41 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/metrics.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/metrics.rs @@ -18,11 +18,11 @@ use crate::TaggedAccount; -use bp_messages::LaneId; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::StorageDoubleMapKeyProvider; -use codec::Decode; +use codec::{Decode, EncodeLike}; use frame_system::AccountInfo; +use messages_relay::Labeled; use pallet_balances::AccountData; use relay_substrate_client::{ metrics::{FloatStorageValue, FloatStorageValueMetric}, @@ -35,7 +35,7 @@ use sp_runtime::{FixedPointNumber, FixedU128}; use std::{fmt::Debug, marker::PhantomData}; /// Add relay accounts balance metrics. -pub async fn add_relay_balances_metrics( +pub async fn add_relay_balances_metrics( client: impl Client, metrics: &MetricsParams, relay_accounts: &Vec>>, @@ -43,6 +43,7 @@ pub async fn add_relay_balances_metrics anyhow::Result<()> where BalanceOf: Into + std::fmt::Debug, + LaneId: Clone + Copy + Decode + EncodeLike + Send + Sync + Labeled, { if relay_accounts.is_empty() { return Ok(()) @@ -52,9 +53,8 @@ where let token_decimals = client .token_decimals() .await? - .map(|token_decimals| { + .inspect(|token_decimals| { log::info!(target: "bridge", "Read `tokenDecimals` for {}: {}", C::NAME, token_decimals); - token_decimals }) .unwrap_or_else(|| { // turns out it is normal not to have this property - e.g. when polkadot binary is @@ -86,25 +86,25 @@ where FloatStorageValueMetric::new( AccountBalance:: { token_decimals, _phantom: Default::default() }, client.clone(), - bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf, LaneId>::final_key( relayers_pallet_name, account.id(), &RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::ThisChain), ), - format!("at_{}_relay_{}_reward_for_msgs_from_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, hex::encode(lane.as_ref())), - format!("Reward of the {} relay account at {} for delivering messages from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane), + format!("at_{}_relay_{}_reward_for_msgs_from_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, lane.label()), + format!("Reward of the {} relay account at {} for delivering messages from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane.label()), )?.register_and_spawn(&metrics.registry)?; FloatStorageValueMetric::new( AccountBalance:: { token_decimals, _phantom: Default::default() }, client.clone(), - bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf, LaneId>::final_key( relayers_pallet_name, account.id(), &RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::BridgedChain), ), - format!("at_{}_relay_{}_reward_for_msgs_to_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, hex::encode(lane.as_ref())), - format!("Reward of the {} relay account at {} for delivering messages confirmations from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane), + format!("at_{}_relay_{}_reward_for_msgs_to_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, lane.label()), + format!("Reward of the {} relay account at {} for delivering messages confirmations from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane.label()), )?.register_and_spawn(&metrics.registry)?; } } diff --git a/bridges/relays/lib-substrate-relay/src/messages/mod.rs b/bridges/relays/lib-substrate-relay/src/messages/mod.rs index 28bc5c7f5e8e..f7031648bc35 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/mod.rs @@ -27,19 +27,17 @@ use crate::{ use async_std::sync::Arc; use bp_messages::{ - target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, LaneId, MessageNonce, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, MessageNonce, }; -use bp_runtime::{ - AccountIdOf, Chain as _, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps, -}; -use codec::Encode; +use bp_runtime::{AccountIdOf, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps}; +use codec::{Codec, Encode, EncodeLike}; use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; -use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction}; +use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction, Labeled}; use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; use relay_substrate_client::{ transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, - ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf, SignParam, - UnsignedTransaction, + ChainBase, ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf, + SignParam, UnsignedTransaction, }; use relay_utils::{ metrics::{GlobalMetrics, MetricsParams, StandaloneMetric}, @@ -60,6 +58,18 @@ pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync { /// Messages from the `SourceChain` are dispatched on this chain. type TargetChain: ChainWithMessages + ChainWithTransactions; + /// Lane identifier type. + type LaneId: Clone + + Copy + + Debug + + Codec + + EncodeLike + + Send + + Sync + + Labeled + + TryFrom> + + Default; + /// How receive messages proof call is built? type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder; /// How receive messages delivery proof call is built? @@ -81,8 +91,10 @@ impl MessageLane for MessageLaneAdapter

{ const SOURCE_NAME: &'static str = P::SourceChain::NAME; const TARGET_NAME: &'static str = P::TargetChain::NAME; - type MessagesProof = SubstrateMessagesProof; - type MessagesReceivingProof = SubstrateMessagesDeliveryProof; + type LaneId = P::LaneId; + + type MessagesProof = SubstrateMessagesProof; + type MessagesReceivingProof = SubstrateMessagesDeliveryProof; type SourceChainBalance = BalanceOf; type SourceHeaderNumber = BlockNumberOf; @@ -109,7 +121,7 @@ pub struct MessagesRelayParams pub target_to_source_headers_relay: Option>>, /// Identifier of lane that needs to be served. - pub lane_id: LaneId, + pub lane_id: P::LaneId, /// Messages relay limits. If not provided, the relay tries to determine it automatically, /// using `TransactionPayment` pallet runtime API. pub limits: Option, @@ -293,7 +305,7 @@ pub async fn relay_messages_range( source_transaction_params: TransactionParams>, target_transaction_params: TransactionParams>, at_source_block: HeaderIdOf, - lane_id: LaneId, + lane_id: P::LaneId, range: RangeInclusive, outbound_state_proof_required: bool, ) -> anyhow::Result<()> @@ -335,7 +347,7 @@ pub async fn relay_messages_delivery_confirmation( target_client: impl Client, source_transaction_params: TransactionParams>, at_target_block: HeaderIdOf, - lane_id: LaneId, + lane_id: P::LaneId, ) -> anyhow::Result<()> where AccountIdOf: From< as Pair>::Public>, @@ -372,7 +384,7 @@ pub trait ReceiveMessagesProofCallBuilder { /// messages module at the target chain. fn build_receive_messages_proof_call( relayer_id_at_source: AccountIdOf, - proof: SubstrateMessagesProof, + proof: SubstrateMessagesProof, messages_count: u32, dispatch_weight: Weight, trace_call: bool, @@ -388,7 +400,7 @@ pub struct DirectReceiveMessagesProofCallBuilder { impl ReceiveMessagesProofCallBuilder

for DirectReceiveMessagesProofCallBuilder where P: SubstrateMessageLane, - R: BridgeMessagesConfig, + R: BridgeMessagesConfig, I: 'static, R::BridgedChain: bp_runtime::Chain, Hash = HashOf>, @@ -396,7 +408,7 @@ where { fn build_receive_messages_proof_call( relayer_id_at_source: AccountIdOf, - proof: SubstrateMessagesProof, + proof: SubstrateMessagesProof, messages_count: u32, dispatch_weight: Weight, trace_call: bool, @@ -444,7 +456,8 @@ macro_rules! generate_receive_message_proof_call_builder { <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain >, proof: $crate::messages::source::SubstrateMessagesProof< - <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain + <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain, + <$pipeline as $crate::messages::SubstrateMessageLane>::LaneId >, messages_count: u32, dispatch_weight: bp_messages::Weight, @@ -470,7 +483,7 @@ pub trait ReceiveMessagesDeliveryProofCallBuilder { /// Given messages delivery proof, build call of `receive_messages_delivery_proof` function of /// bridge messages module at the source chain. fn build_receive_messages_delivery_proof_call( - proof: SubstrateMessagesDeliveryProof, + proof: SubstrateMessagesDeliveryProof, trace_call: bool, ) -> CallOf; } @@ -485,13 +498,13 @@ impl ReceiveMessagesDeliveryProofCallBuilder

for DirectReceiveMessagesDeliveryProofCallBuilder where P: SubstrateMessageLane, - R: BridgeMessagesConfig, + R: BridgeMessagesConfig, I: 'static, R::BridgedChain: bp_runtime::Chain>, CallOf: From> + GetDispatchInfo, { fn build_receive_messages_delivery_proof_call( - proof: SubstrateMessagesDeliveryProof, + proof: SubstrateMessagesDeliveryProof, trace_call: bool, ) -> CallOf { let call: CallOf = @@ -533,7 +546,8 @@ macro_rules! generate_receive_message_delivery_proof_call_builder { { fn build_receive_messages_delivery_proof_call( proof: $crate::messages::target::SubstrateMessagesDeliveryProof< - <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain + <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain, + <$pipeline as $crate::messages::SubstrateMessageLane>::LaneId >, _trace_call: bool, ) -> relay_substrate_client::CallOf< @@ -644,7 +658,7 @@ where FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId::new(1, 2), + lane: P::LaneId::default(), nonces_start: 1, nonces_end: messages as u64, }, @@ -674,7 +688,7 @@ where mod tests { use super::*; use bp_messages::{ - source_chain::FromBridgedChainMessagesDeliveryProof, UnrewardedRelayersState, + source_chain::FromBridgedChainMessagesDeliveryProof, LaneIdType, UnrewardedRelayersState, }; use relay_substrate_client::calls::{UtilityCall as MockUtilityCall, UtilityCall}; @@ -687,8 +701,8 @@ mod tests { } pub type CodegenBridgeMessagesCall = bp_messages::BridgeMessagesCall< u64, - Box>, - FromBridgedChainMessagesDeliveryProof, + Box>, + FromBridgedChainMessagesDeliveryProof, >; impl From> for RuntimeCall { @@ -706,7 +720,7 @@ mod tests { let receive_messages_proof = FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId::new(1, 2), + lane: mock::TestLaneIdType::try_new(1, 2).unwrap(), nonces_start: 0, nonces_end: 0, }; @@ -761,7 +775,7 @@ mod tests { let receive_messages_delivery_proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId::new(1, 2), + lane: mock::TestLaneIdType::try_new(1, 2).unwrap(), }; let relayers_state = UnrewardedRelayersState { unrewarded_relayer_entries: 0, @@ -808,7 +822,7 @@ mod tests { // mock runtime with `pallet_bridge_messages` mod mock { use super::super::*; - use bp_messages::target_chain::ForbidInboundMessages; + use bp_messages::{target_chain::ForbidInboundMessages, HashedLaneId}; use bp_runtime::ChainId; use frame_support::derive_impl; use sp_core::H256; @@ -819,6 +833,9 @@ mod tests { type Block = frame_system::mocking::MockBlock; pub type SignedBlock = generic::SignedBlock; + /// Lane identifier type used for tests. + pub type TestLaneIdType = HashedLaneId; + frame_support::construct_runtime! { pub enum TestRuntime { @@ -840,10 +857,11 @@ mod tests { type BridgedHeaderChain = BridgedHeaderChain; type OutboundPayload = Vec; type InboundPayload = Vec; + type LaneId = TestLaneIdType; type DeliveryPayments = (); type DeliveryConfirmationPayments = (); type OnMessagesDelivered = (); - type MessageDispatch = ForbidInboundMessages>; + type MessageDispatch = ForbidInboundMessages, Self::LaneId>; } pub struct ThisUnderlyingChain; @@ -1005,6 +1023,7 @@ mod tests { impl SubstrateMessageLane for ThisChainToBridgedChainMessageLane { type SourceChain = ThisChain; type TargetChain = BridgedChain; + type LaneId = mock::TestLaneIdType; type ReceiveMessagesProofCallBuilder = ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder; type ReceiveMessagesDeliveryProofCallBuilder = diff --git a/bridges/relays/lib-substrate-relay/src/messages/source.rs b/bridges/relays/lib-substrate-relay/src/messages/source.rs index 2c49df3452ab..b560867a235b 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/source.rs @@ -34,7 +34,7 @@ use async_trait::async_trait; use bp_messages::{ storage_keys::{operating_mode_key, outbound_lane_data_key}, target_chain::FromBridgedChainMessagesProof, - ChainWithMessages as _, InboundMessageDetails, LaneId, MessageNonce, MessagePayload, + ChainWithMessages as _, InboundMessageDetails, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, }; use bp_runtime::{BasicOperatingMode, HeaderIdProvider, RangeInclusiveExt}; @@ -60,14 +60,14 @@ use std::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 /// the proof itself. -pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof>); +pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof, L>); type MessagesToRefine<'a> = Vec<(MessagePayload, &'a mut OutboundMessageDetails)>; /// Substrate client as Substrate messages source. pub struct SubstrateMessagesSource { source_client: SourceClnt, target_client: TargetClnt, - lane_id: LaneId, + lane_id: P::LaneId, transaction_params: TransactionParams>, target_to_source_headers_relay: Option>>, } @@ -79,7 +79,7 @@ impl, TargetClnt> pub fn new( source_client: SourceClnt, target_client: TargetClnt, - lane_id: LaneId, + lane_id: P::LaneId, transaction_params: TransactionParams>, target_to_source_headers_relay: Option< Arc>, @@ -256,8 +256,11 @@ where } let best_target_header_hash = self.target_client.best_header_hash().await?; - for mut msgs_to_refine_batch in - split_msgs_to_refine::(self.lane_id, msgs_to_refine)? + for mut msgs_to_refine_batch in split_msgs_to_refine::< + P::SourceChain, + P::TargetChain, + P::LaneId, + >(self.lane_id, msgs_to_refine)? { let in_msgs_details = self .target_client @@ -542,7 +545,7 @@ fn validate_out_msgs_details( Ok(()) } -fn split_msgs_to_refine( +fn split_msgs_to_refine( lane_id: LaneId, msgs_to_refine: MessagesToRefine, ) -> Result, SubstrateError> { @@ -578,8 +581,12 @@ fn split_msgs_to_refine( #[cfg(test)] mod tests { use super::*; + use bp_messages::{HashedLaneId, LaneIdType}; use relay_substrate_client::test_chain::TestChain; + /// Lane identifier type used for tests. + type TestLaneIdType = HashedLaneId; + fn message_details_from_rpc( nonces: RangeInclusive, ) -> Vec { @@ -660,8 +667,10 @@ mod tests { msgs_to_refine.push((payload, out_msg_details)); } - let maybe_batches = - split_msgs_to_refine::(LaneId::new(1, 2), msgs_to_refine); + let maybe_batches = split_msgs_to_refine::( + TestLaneIdType::try_new(1, 2).unwrap(), + msgs_to_refine, + ); match expected_batches { Ok(expected_batches) => { let batches = maybe_batches.unwrap(); diff --git a/bridges/relays/lib-substrate-relay/src/messages/target.rs b/bridges/relays/lib-substrate-relay/src/messages/target.rs index a6bf169cffb6..0d1aac88a32a 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/target.rs @@ -36,7 +36,7 @@ use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, storage_keys::inbound_lane_data_key, - ChainWithMessages as _, InboundLaneData, LaneId, MessageNonce, UnrewardedRelayersState, + ChainWithMessages as _, InboundLaneData, MessageNonce, UnrewardedRelayersState, }; use messages_relay::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, @@ -51,14 +51,14 @@ use sp_core::Pair; use std::{convert::TryFrom, ops::RangeInclusive}; /// Message receiving proof returned by the target Substrate node. -pub type SubstrateMessagesDeliveryProof = - (UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof>); +pub type SubstrateMessagesDeliveryProof = + (UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof, L>); /// Substrate client as Substrate messages target. pub struct SubstrateMessagesTarget { target_client: TargetClnt, source_client: SourceClnt, - lane_id: LaneId, + lane_id: P::LaneId, relayer_id_at_source: AccountIdOf, transaction_params: Option>>, source_to_target_headers_relay: Option>>, @@ -73,7 +73,7 @@ where pub fn new( target_client: TargetClnt, source_client: SourceClnt, - lane_id: LaneId, + lane_id: P::LaneId, relayer_id_at_source: AccountIdOf, transaction_params: Option>>, source_to_target_headers_relay: Option< @@ -308,7 +308,7 @@ where fn make_messages_delivery_call( relayer_id_at_source: AccountIdOf, nonces: RangeInclusive, - proof: SubstrateMessagesProof, + proof: SubstrateMessagesProof, trace_call: bool, ) -> CallOf { let messages_count = nonces.end() - nonces.start() + 1; diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs index 2ef86f48ecbe..96eba0af988c 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -664,7 +664,8 @@ impl<'a, P: SubstrateParachainsPipeline, SourceRelayClnt, TargetClnt> for ( &'a OnDemandParachainsRelay, &'a ParachainsSource, - ) where + ) +where SourceRelayClnt: Client, TargetClnt: Client, { diff --git a/bridges/relays/messages/Cargo.toml b/bridges/relays/messages/Cargo.toml index c7a132bb3bae..f9df73507c75 100644 --- a/bridges/relays/messages/Cargo.toml +++ b/bridges/relays/messages/Cargo.toml @@ -26,3 +26,6 @@ finality-relay = { workspace = true } relay-utils = { workspace = true } sp-arithmetic = { workspace = true, default-features = true } + +[dev-dependencies] +sp-core = { workspace = true } diff --git a/bridges/relays/messages/src/lib.rs b/bridges/relays/messages/src/lib.rs index 78a3237ba4fe..f5e09f4d4684 100644 --- a/bridges/relays/messages/src/lib.rs +++ b/bridges/relays/messages/src/lib.rs @@ -38,3 +38,4 @@ mod message_race_strategy; pub use message_race_delivery::relay_messages_range; pub use message_race_receiving::relay_messages_delivery_confirmation; +pub use metrics::Labeled; diff --git a/bridges/relays/messages/src/message_lane.rs b/bridges/relays/messages/src/message_lane.rs index 5c9728ad93ab..84c1e57ba4eb 100644 --- a/bridges/relays/messages/src/message_lane.rs +++ b/bridges/relays/messages/src/message_lane.rs @@ -19,6 +19,7 @@ //! 1) relay new messages from source to target node; //! 2) relay proof-of-delivery from target to source node. +use crate::metrics::Labeled; use num_traits::{SaturatingAdd, Zero}; use relay_utils::{BlockNumberBase, HeaderId}; use sp_arithmetic::traits::AtLeast32BitUnsigned; @@ -31,6 +32,9 @@ pub trait MessageLane: 'static + Clone + Send + Sync { /// Name of the messages target. const TARGET_NAME: &'static str; + /// Lane identifier type. + type LaneId: Clone + Send + Sync + Labeled; + /// Messages proof. type MessagesProof: Clone + Debug + Send + Sync; /// Messages receiving proof. diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index 995499092c3e..36de637f04c4 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -29,7 +29,7 @@ use std::{collections::BTreeMap, fmt::Debug, future::Future, ops::RangeInclusive use async_trait::async_trait; use futures::{channel::mpsc::unbounded, future::FutureExt, stream::StreamExt}; -use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight}; +use bp_messages::{MessageNonce, UnrewardedRelayersState, Weight}; use relay_utils::{ interval, metrics::MetricsParams, process_future_result, relay_loop::Client as RelayClient, retry_backoff, FailedClient, TransactionTracker, @@ -39,12 +39,12 @@ use crate::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, message_race_delivery::run as run_message_delivery_race, message_race_receiving::run as run_message_receiving_race, - metrics::MessageLaneLoopMetrics, + metrics::{Labeled, MessageLaneLoopMetrics}, }; /// Message lane loop configuration params. #[derive(Debug, Clone)] -pub struct Params { +pub struct Params { /// Id of lane this loop is servicing. pub lane: LaneId, /// Interval at which we ask target node about its updates. @@ -275,13 +275,13 @@ pub struct ClientsState { /// Return prefix that will be used by default to expose Prometheus metrics of the finality proofs /// sync loop. -pub fn metrics_prefix(lane: &LaneId) -> String { - format!("{}_to_{}_MessageLane_{:?}", P::SOURCE_NAME, P::TARGET_NAME, lane) +pub fn metrics_prefix(lane: &P::LaneId) -> String { + format!("{}_to_{}_MessageLane_{}", P::SOURCE_NAME, P::TARGET_NAME, lane.label()) } /// Run message lane service loop. pub async fn run( - params: Params, + params: Params, source_client: impl SourceClient

, target_client: impl TargetClient

, metrics_params: MetricsParams, @@ -309,7 +309,7 @@ pub async fn run( /// Run one-way message delivery loop until connection with target or source node is lost, or exit /// signal is received. async fn run_until_connection_lost, TC: TargetClient

>( - params: Params, + params: Params, source_client: SC, target_client: TC, metrics_msg: Option, @@ -471,9 +471,9 @@ async fn run_until_connection_lost, TC: Targ pub(crate) mod tests { use std::sync::Arc; + use bp_messages::{HashedLaneId, LaneIdType, LegacyLaneId}; use futures::stream::StreamExt; use parking_lot::Mutex; - use relay_utils::{HeaderId, MaybeConnectionError, TrackedTransactionStatus}; use super::*; @@ -504,6 +504,9 @@ pub(crate) mod tests { } } + /// Lane identifier type used for tests. + pub type TestLaneIdType = HashedLaneId; + #[derive(Clone)] pub struct TestMessageLane; @@ -520,6 +523,8 @@ pub(crate) mod tests { type TargetHeaderNumber = TestTargetHeaderNumber; type TargetHeaderHash = TestTargetHeaderHash; + + type LaneId = TestLaneIdType; } #[derive(Clone, Debug)] @@ -957,7 +962,7 @@ pub(crate) mod tests { }; let _ = run( Params { - lane: LaneId::new(1, 2), + lane: TestLaneIdType::try_new(1, 2).unwrap(), source_tick: Duration::from_millis(100), target_tick: Duration::from_millis(100), reconnect_delay: Duration::from_millis(0), @@ -1278,7 +1283,31 @@ pub(crate) mod tests { #[test] fn metrics_prefix_is_valid() { assert!(MessageLaneLoopMetrics::new(Some(&metrics_prefix::( - &LaneId::new(1, 2) + &HashedLaneId::try_new(1, 2).unwrap() + ))) + .is_ok()); + + // with LegacyLaneId + #[derive(Clone)] + pub struct LegacyTestMessageLane; + impl MessageLane for LegacyTestMessageLane { + const SOURCE_NAME: &'static str = "LegacyTestSource"; + const TARGET_NAME: &'static str = "LegacyTestTarget"; + + type MessagesProof = TestMessagesProof; + type MessagesReceivingProof = TestMessagesReceivingProof; + + type SourceChainBalance = TestSourceChainBalance; + type SourceHeaderNumber = TestSourceHeaderNumber; + type SourceHeaderHash = TestSourceHeaderHash; + + type TargetHeaderNumber = TestTargetHeaderNumber; + type TargetHeaderHash = TestTargetHeaderHash; + + type LaneId = LegacyLaneId; + } + assert!(MessageLaneLoopMetrics::new(Some(&metrics_prefix::( + &LegacyLaneId([0, 0, 0, 1]) ))) .is_ok()); } diff --git a/bridges/relays/messages/src/message_race_delivery.rs b/bridges/relays/messages/src/message_race_delivery.rs index cbb89baabcc5..b09533a4ddc1 100644 --- a/bridges/relays/messages/src/message_race_delivery.rs +++ b/bridges/relays/messages/src/message_race_delivery.rs @@ -59,9 +59,7 @@ pub async fn run( _phantom: Default::default(), }, target_state_updates, - MessageDeliveryStrategy:: { - lane_source_client: source_client, - lane_target_client: target_client, + MessageDeliveryStrategy::

{ max_unrewarded_relayer_entries_at_target: params .max_unrewarded_relayer_entries_at_target, max_unconfirmed_nonces_at_target: params.max_unconfirmed_nonces_at_target, @@ -71,7 +69,6 @@ pub async fn run( latest_confirmed_nonces_at_source: VecDeque::new(), target_nonces: None, strategy: BasicStrategy::new(), - metrics_msg, }, ) .await @@ -300,11 +297,7 @@ struct DeliveryRaceTargetNoncesData { } /// Messages delivery strategy. -struct MessageDeliveryStrategy { - /// The client that is connected to the message lane source node. - lane_source_client: SC, - /// The client that is connected to the message lane target node. - lane_target_client: TC, +struct MessageDeliveryStrategy { /// Maximal unrewarded relayer entries at target client. max_unrewarded_relayer_entries_at_target: MessageNonce, /// Maximal unconfirmed nonces at target client. @@ -322,8 +315,6 @@ struct MessageDeliveryStrategy { target_nonces: Option>, /// Basic delivery strategy. strategy: MessageDeliveryStrategyBase

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

= BasicStrategy< @@ -335,7 +326,7 @@ type MessageDeliveryStrategyBase

= BasicStrategy<

::MessagesProof, >; -impl std::fmt::Debug for MessageDeliveryStrategy { +impl std::fmt::Debug for MessageDeliveryStrategy

{ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { fmt.debug_struct("MessageDeliveryStrategy") .field( @@ -353,11 +344,9 @@ impl std::fmt::Debug for MessageDeliveryStrategy MessageDeliveryStrategy +impl MessageDeliveryStrategy

where P: MessageLane, - SC: MessageLaneSourceClient

, - TC: MessageLaneTargetClient

, { /// Returns true if some race action can be selected (with `select_race_action`) at given /// `best_finalized_source_header_id_at_best_target` source header at target. @@ -465,23 +454,18 @@ where let max_nonces = std::cmp::min(max_nonces, self.max_messages_in_single_batch); let max_messages_weight_in_single_batch = self.max_messages_weight_in_single_batch; let max_messages_size_in_single_batch = self.max_messages_size_in_single_batch; - let lane_source_client = self.lane_source_client.clone(); - let lane_target_client = self.lane_target_client.clone(); // select nonces from nonces, available for delivery let selected_nonces = match self.strategy.available_source_queue_indices(race_state) { Some(available_source_queue_indices) => { let source_queue = self.strategy.source_queue(); - let reference = RelayMessagesBatchReference { + let reference = RelayMessagesBatchReference::

{ max_messages_in_this_batch: max_nonces, max_messages_weight_in_single_batch, max_messages_size_in_single_batch, - lane_source_client: lane_source_client.clone(), - lane_target_client: lane_target_client.clone(), best_target_nonce, nonces_queue: source_queue.clone(), nonces_queue_range: available_source_queue_indices, - metrics: self.metrics_msg.clone(), }; MessageRaceLimits::decide(reference).await @@ -534,12 +518,10 @@ where } #[async_trait] -impl RaceStrategy, TargetHeaderIdOf

, P::MessagesProof> - for MessageDeliveryStrategy +impl

RaceStrategy, TargetHeaderIdOf

, P::MessagesProof> + for MessageDeliveryStrategy

where P: MessageLane, - SC: MessageLaneSourceClient

, - TC: MessageLaneTargetClient

, { type SourceNoncesRange = MessageDetailsMap; type ProofParameters = MessageProofParameters; @@ -707,8 +689,7 @@ mod tests { message_lane_loop::{ tests::{ header_id, TestMessageLane, TestMessagesBatchTransaction, TestMessagesProof, - TestSourceChainBalance, TestSourceClient, TestSourceHeaderId, TestTargetClient, - TestTargetHeaderId, + TestSourceChainBalance, TestSourceHeaderId, TestTargetHeaderId, }, MessageDetails, }, @@ -726,8 +707,7 @@ mod tests { TestMessagesProof, TestMessagesBatchTransaction, >; - type TestStrategy = - MessageDeliveryStrategy; + type TestStrategy = MessageDeliveryStrategy; fn source_nonces( new_nonces: RangeInclusive, @@ -770,9 +750,6 @@ mod tests { max_messages_weight_in_single_batch: Weight::from_parts(4, 0), max_messages_size_in_single_batch: 4, latest_confirmed_nonces_at_source: vec![(header_id(1), 19)].into_iter().collect(), - lane_source_client: TestSourceClient::default(), - lane_target_client: TestTargetClient::default(), - metrics_msg: None, target_nonces: Some(TargetClientNonces { latest_nonce: 19, nonces_data: DeliveryRaceTargetNoncesData { @@ -1167,9 +1144,6 @@ mod tests { max_messages_weight_in_single_batch: Weight::from_parts(4, 0), max_messages_size_in_single_batch: 4, latest_confirmed_nonces_at_source: VecDeque::new(), - lane_source_client: TestSourceClient::default(), - lane_target_client: TestTargetClient::default(), - metrics_msg: None, target_nonces: None, strategy: BasicStrategy::new(), }; diff --git a/bridges/relays/messages/src/message_race_limits.rs b/bridges/relays/messages/src/message_race_limits.rs index 873bb6aad042..8fcd1f911f68 100644 --- a/bridges/relays/messages/src/message_race_limits.rs +++ b/bridges/relays/messages/src/message_race_limits.rs @@ -23,33 +23,16 @@ use bp_messages::{MessageNonce, Weight}; use crate::{ message_lane::MessageLane, - message_lane_loop::{ - MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient, - TargetClient as MessageLaneTargetClient, - }, + message_lane_loop::{MessageDetails, MessageDetailsMap}, message_race_loop::NoncesRange, message_race_strategy::SourceRangesQueue, - metrics::MessageLaneLoopMetrics, }; /// Reference data for participating in relay -pub struct RelayReference< - P: MessageLane, - SourceClient: MessageLaneSourceClient

, - TargetClient: MessageLaneTargetClient

, -> { - /// The client that is connected to the message lane source node. - pub lane_source_client: SourceClient, - /// The client that is connected to the message lane target node. - pub lane_target_client: TargetClient, - /// Metrics reference. - pub metrics: Option, +pub struct RelayReference { /// Messages size summary pub selected_size: u32, - /// Hard check begin nonce - pub hard_selected_begin_nonce: MessageNonce, - /// Index by all ready nonces pub index: usize, /// Current nonce @@ -59,23 +42,13 @@ pub struct RelayReference< } /// Relay reference data -pub struct RelayMessagesBatchReference< - P: MessageLane, - SourceClient: MessageLaneSourceClient

, - TargetClient: MessageLaneTargetClient

, -> { +pub struct RelayMessagesBatchReference { /// Maximal number of relayed messages in single delivery transaction. pub max_messages_in_this_batch: MessageNonce, /// Maximal cumulative dispatch weight of relayed messages in single delivery transaction. pub max_messages_weight_in_single_batch: Weight, /// Maximal cumulative size of relayed messages in single delivery transaction. pub max_messages_size_in_single_batch: u32, - /// The client that is connected to the message lane source node. - pub lane_source_client: SourceClient, - /// The client that is connected to the message lane target node. - pub lane_target_client: TargetClient, - /// Metrics reference. - pub metrics: Option, /// Best available nonce at the **best** target block. We do not want to deliver nonces /// less than this nonce, even though the block may be retracted. pub best_target_nonce: MessageNonce, @@ -94,12 +67,8 @@ pub struct RelayMessagesBatchReference< pub struct MessageRaceLimits; impl MessageRaceLimits { - pub async fn decide< - P: MessageLane, - SourceClient: MessageLaneSourceClient

, - TargetClient: MessageLaneTargetClient

, - >( - reference: RelayMessagesBatchReference, + pub async fn decide( + reference: RelayMessagesBatchReference

, ) -> Option> { let mut hard_selected_count = 0; @@ -112,15 +81,9 @@ impl MessageRaceLimits { ); // relay reference - let mut relay_reference = RelayReference { - lane_source_client: reference.lane_source_client.clone(), - lane_target_client: reference.lane_target_client.clone(), - metrics: reference.metrics.clone(), - + let mut relay_reference = RelayReference::

{ selected_size: 0, - hard_selected_begin_nonce, - index: 0, nonce: 0, details: MessageDetails { diff --git a/bridges/relays/messages/src/message_race_loop.rs b/bridges/relays/messages/src/message_race_loop.rs index 31341a9a0c0c..ea6a2371dc90 100644 --- a/bridges/relays/messages/src/message_race_loop.rs +++ b/bridges/relays/messages/src/message_race_loop.rs @@ -225,15 +225,9 @@ pub trait RaceState: Clone + Send + Sync { /// client (at the `best_finalized_source_header_id_at_best_target`). fn set_best_finalized_source_header_id_at_best_target(&mut self, id: SourceHeaderId); - /// Best finalized source header id at the source client. - fn best_finalized_source_header_id_at_source(&self) -> Option; /// Best finalized source header id at the best block on the target /// client (at the `best_finalized_source_header_id_at_best_target`). fn best_finalized_source_header_id_at_best_target(&self) -> Option; - /// The best header id at the target client. - fn best_target_header_id(&self) -> Option; - /// Best finalized header id at the target client. - fn best_finalized_target_header_id(&self) -> Option; /// Returns `true` if we have selected nonces to submit to the target node. fn nonces_to_submit(&self) -> Option>; @@ -296,22 +290,10 @@ where self.best_finalized_source_header_id_at_best_target = Some(id); } - fn best_finalized_source_header_id_at_source(&self) -> Option { - self.best_finalized_source_header_id_at_source.clone() - } - fn best_finalized_source_header_id_at_best_target(&self) -> Option { self.best_finalized_source_header_id_at_best_target.clone() } - fn best_target_header_id(&self) -> Option { - self.best_target_header_id.clone() - } - - fn best_finalized_target_header_id(&self) -> Option { - self.best_finalized_target_header_id.clone() - } - fn nonces_to_submit(&self) -> Option> { self.nonces_to_submit.clone().map(|(_, nonces, _)| nonces) } diff --git a/bridges/relays/messages/src/message_race_strategy.rs b/bridges/relays/messages/src/message_race_strategy.rs index 3a532331d79d..1303fcfedebd 100644 --- a/bridges/relays/messages/src/message_race_strategy.rs +++ b/bridges/relays/messages/src/message_race_strategy.rs @@ -67,7 +67,8 @@ impl< TargetHeaderHash, SourceNoncesRange, Proof, - > where + > +where SourceHeaderHash: Clone, SourceHeaderNumber: Clone + Ord, SourceNoncesRange: NoncesRange, @@ -189,7 +190,8 @@ impl< TargetHeaderHash, SourceNoncesRange, Proof, - > where + > +where SourceHeaderHash: Clone + Debug + Send + Sync, SourceHeaderNumber: Clone + Ord + Debug + Send + Sync, SourceNoncesRange: NoncesRange + Debug + Send + Sync, diff --git a/bridges/relays/messages/src/metrics.rs b/bridges/relays/messages/src/metrics.rs index 69d80d178de8..2ca10e56d74a 100644 --- a/bridges/relays/messages/src/metrics.rs +++ b/bridges/relays/messages/src/metrics.rs @@ -21,7 +21,7 @@ use crate::{ message_lane_loop::{SourceClientState, TargetClientState}, }; -use bp_messages::MessageNonce; +use bp_messages::{HashedLaneId, LegacyLaneId, MessageNonce}; use finality_relay::SyncLoopMetrics; use relay_utils::metrics::{ metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, @@ -146,3 +146,32 @@ impl Metric for MessageLaneLoopMetrics { Ok(()) } } + +/// Provides a label for metrics. +pub trait Labeled { + /// Returns a label. + fn label(&self) -> String; +} + +/// `Labeled` implementation for `LegacyLaneId`. +impl Labeled for LegacyLaneId { + fn label(&self) -> String { + hex::encode(self.0) + } +} + +/// `Labeled` implementation for `HashedLaneId`. +impl Labeled for HashedLaneId { + fn label(&self) -> String { + format!("{:?}", self.inner()) + } +} + +#[test] +fn lane_to_label_works() { + assert_eq!( + "0x0101010101010101010101010101010101010101010101010101010101010101", + HashedLaneId::from_inner(sp_core::H256::from([1u8; 32])).label(), + ); + assert_eq!("00000001", LegacyLaneId([0, 0, 0, 1]).label()); +} diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs index d5c89b9c0987..eeeaa6e68cf9 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs @@ -182,12 +182,6 @@ where let root = merkelize::(hashes.into_iter(), &mut collect_proof); let leaf = leaf.expect("Requested `leaf_index` is greater than number of leaves."); - #[cfg(feature = "debug")] - log::debug!( - "[merkle_proof] Proof: {:?}", - collect_proof.proof.iter().map(hex::encode).collect::>() - ); - MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf } } @@ -274,8 +268,6 @@ where V: Visitor, I: Iterator, { - #[cfg(feature = "debug")] - log::debug!("[merkelize_row]"); next.clear(); let hash_len = ::LENGTH; @@ -286,9 +278,6 @@ where let b = iter.next(); visitor.visit(index, &a, &b); - #[cfg(feature = "debug")] - log::debug!(" {:?}\n {:?}", a.as_ref().map(hex::encode), b.as_ref().map(hex::encode)); - index += 2; match (a, b) { (Some(a), Some(b)) => { @@ -309,14 +298,7 @@ where // Last item = root. (Some(a), None) => return Ok(a), // Finish up, no more items. - _ => { - #[cfg(feature = "debug")] - log::debug!( - "[merkelize_row] Next: {:?}", - next.iter().map(hex::encode).collect::>() - ); - return Err(next) - }, + _ => return Err(next), } } } diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index a10884b45531..fbfc52d01c83 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs @@ -168,7 +168,8 @@ impl< ConvertAssetId, EthereumUniversalLocation, GlobalAssetHubLocation, - > where + > +where CreateAssetCall: Get, CreateAssetDeposit: Get, InboundQueuePalletInstance: Get, @@ -226,7 +227,8 @@ impl< ConvertAssetId, EthereumUniversalLocation, GlobalAssetHubLocation, - > where + > +where CreateAssetCall: Get, CreateAssetDeposit: Get, InboundQueuePalletInstance: Get, diff --git a/bridges/snowbridge/primitives/router/src/outbound/mod.rs b/bridges/snowbridge/primitives/router/src/outbound/mod.rs index d3b6c116dd7a..b23bce0e2185 100644 --- a/bridges/snowbridge/primitives/router/src/outbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/outbound/mod.rs @@ -44,7 +44,8 @@ impl where + > +where UniversalLocation: Get, EthereumNetwork: Get, OutboundQueue: SendMessage, diff --git a/bridges/snowbridge/runtime/runtime-common/src/lib.rs b/bridges/snowbridge/runtime/runtime-common/src/lib.rs index aae45520ff4b..0b1a74b232a0 100644 --- a/bridges/snowbridge/runtime/runtime-common/src/lib.rs +++ b/bridges/snowbridge/runtime/runtime-common/src/lib.rs @@ -50,7 +50,8 @@ impl where + > +where Balance: BaseArithmetic + Unsigned + Copy + From + Into + Debug, AccountId: Clone + FullCodec, FeeAssetLocation: Get, diff --git a/bridges/testing/README.md b/bridges/testing/README.md index 158dfd73b1ad..89a07c421e3e 100644 --- a/bridges/testing/README.md +++ b/bridges/testing/README.md @@ -22,7 +22,7 @@ Prerequisites for running the tests locally: - copy the `substrate-relay` binary, built in the previous step, to `~/local_bridge_testing/bin/substrate-relay`; After that, any test can be run using the `run-test.sh` command. -Example: `./run-new-test.sh 0001-asset-transfer` +Example: `./run-test.sh 0001-asset-transfer` Hopefully, it'll show the "All tests have completed successfully" message in the end. Otherwise, it'll print paths to zombienet diff --git a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh index 54633449134b..e7848fe7163c 100755 --- a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -53,66 +53,66 @@ ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZ # Expected sovereign accounts for rewards on BridgeHubs. # # Generated by: -# #[test] -# fn generate_sovereign_accounts_for_rewards() { -# use bp_messages::LaneId; -# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; -# use sp_core::crypto::Ss58Codec; +##[test] +#fn generate_sovereign_accounts_for_rewards() { +# use bp_messages::LegacyLaneId; +# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; +# use sp_core::crypto::Ss58Codec; # -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhwd", -# RewardsAccountOwner::ThisChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhwd", -# RewardsAccountOwner::BridgedChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); # -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhro", -# RewardsAccountOwner::ThisChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhro", -# RewardsAccountOwner::BridgedChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); -# } -ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain="5EHnXaT5BhiSGP5hbdsoVGtzi2sQVgpDNToTxLYeQvKoMPEm" -ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain="5EHnXaT5BhiSGP5hbdt5EJSapXYbxEv678jyWHEUskCXcjqo" -ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXaT5BhiSGP5h9Rg8sgUJqoLym3iEaWUiboT8S9AT5xFh" -ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5BhiSGP5h9RgQci1txJ2BDbp7KBRE9k8xty3BMUSi" +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +#} +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain="5EHnXaT5GApse1euZWj9hycMbgjKBCNQL9WEwScL8QDx6mhK" +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain="5EHnXaT5Tnt4A8aiP9CsuAFRhKPjKZJXRrj4a3mtihFvKpTi" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXaT5GApry9tS6yd1FVusPq8o8bQJGCKyvXTFCoEKk5Z9" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5Tnt3VGpEvc6jSgYwVToDGxLRMuYoZ8coo6GHyWbR" LANE_ID="00000002" XCM_VERSION=3 diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 4fea055203d8..f0a082dce534 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -379,6 +379,7 @@ fn build_polkadot_full_node( execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, )?; diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 30a232f01b3e..66429625d5bf 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -49,7 +49,6 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } hex-literal = { workspace = true, default-features = true } -lazy_static = { workspace = true } trie-standardmap = { workspace = true } rand = { workspace = true, default-features = true } futures = { workspace = true } diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 9dc41aa03d9b..21af35fe3de3 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -390,7 +390,8 @@ pub mod pallet { let maximum_channels = host_config .hrmp_max_message_num_per_candidate - .min(>::take()) as usize; + .min(>::take()) + as usize; // Note: this internally calls the `GetChannelInfo` implementation for this // pallet, which draws on the `RelevantMessagingState`. That in turn has diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 548231966e42..23223627ebca 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -754,12 +754,8 @@ fn message_queue_chain() { #[test] #[cfg(not(feature = "runtime-benchmarks"))] fn receive_dmp() { - lazy_static::lazy_static! { - static ref MSG: InboundDownwardMessage = InboundDownwardMessage { - sent_at: 1, - msg: b"down".to_vec(), - }; - } + static MSG: std::sync::LazyLock = + std::sync::LazyLock::new(|| InboundDownwardMessage { sent_at: 1, msg: b"down".to_vec() }); BlockTests::new() .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num { @@ -771,14 +767,14 @@ fn receive_dmp() { }) .with_inherent_data(|_, relay_block_num, data| match relay_block_num { 1 => { - data.downward_messages.push(MSG.clone()); + data.downward_messages.push((*MSG).clone()); }, _ => unreachable!(), }) .add(1, || { HANDLED_DMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(MSG.msg.clone())]); + assert_eq!(&*m, &[MSG.msg.clone()]); m.clear(); }); }); diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 470e00fe94e1..3964ecf28cac 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -20,7 +20,7 @@ use cumulus_pallet_parachain_system::AnyRelayNumber; use cumulus_primitives_core::{ChannelInfo, IsSystem, ParaId}; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, Everything, Nothing, OriginTrait}, + traits::{ConstU32, Everything, OriginTrait}, BoundedSlice, }; use frame_system::EnsureRoot; @@ -30,10 +30,6 @@ use sp_runtime::{ BuildStorage, }; use xcm::prelude::*; -use xcm_builder::{ - FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, - ParentIsPreset, -}; use xcm_executor::traits::ConvertOrigin; type Block = frame_system::mocking::MockBlock; @@ -119,61 +115,6 @@ parameter_types! { pub const MaxAssetsIntoHolding: u32 = 64; } -/// Means for transacting assets on this chain. -pub type LocalAssetTransactor = FungibleAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Do a simple punn to convert an AccountId32 Location into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; - -pub type LocationToAccountId = (ParentIsPreset,); - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - // How to withdraw and deposit an asset. - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = (); - type IsReserve = NativeAsset; - type IsTeleporter = NativeAsset; - type UniversalLocation = UniversalLocation; - type Barrier = (); - type Weigher = FixedWeightBounds; - type Trader = (); - type ResponseHandler = (); - type AssetTrap = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; - type TransactionalProcessor = FrameTransactionalProcessor; - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); - type XcmRecorder = (); -} - -pub type XcmRouter = ( - // XCMP to communicate with the sibling chains. - XcmpQueue, -); - pub struct SystemParachainAsSuperuser(PhantomData); impl ConvertOrigin for SystemParachainAsSuperuser diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml index f3c0799ad0f6..266d743ca0c2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml @@ -16,6 +16,12 @@ workspace = true sp-core = { workspace = true } frame-support = { workspace = true } +# Polkadot Dependencies +xcm = { workspace = true } + +# Bridge dependencies +bp-messages = { workspace = true } + # Cumulus parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs index 3786d529ea65..b9c0c01101c6 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/genesis.rs @@ -21,6 +21,7 @@ use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; use parachains_common::Balance; +use xcm::latest::prelude::*; pub const ASSETHUB_PARA_ID: u32 = 1000; pub const PARA_ID: u32 = 1013; @@ -66,6 +67,17 @@ pub fn genesis() -> Storage { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, + xcm_over_bridge_hub_westend: bridge_hub_rococo_runtime::XcmOverBridgeHubWestendConfig { + opened_bridges: vec![ + // open AHR -> AHW bridge + ( + Location::new(1, [Parachain(1000)]), + Junctions::from([Westend.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + ), + ], + ..Default::default() + }, ethereum_system: bridge_hub_rococo_runtime::EthereumSystemConfig { para_id: PARA_ID.into(), asset_hub_para_id: ASSETHUB_PARA_ID.into(), diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml index ebcec9641e7d..88d7348f50f2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml @@ -16,6 +16,12 @@ workspace = true sp-core = { workspace = true } frame-support = { workspace = true } +# Polkadot Dependencies +xcm = { workspace = true } + +# Bridge dependencies +bp-messages = { workspace = true } + # Cumulus parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs index f38f385db650..3ffe3d86b2ac 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/genesis.rs @@ -21,6 +21,7 @@ use emulated_integration_tests_common::{ accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, }; use parachains_common::Balance; +use xcm::latest::prelude::*; pub const PARA_ID: u32 = 1002; pub const ASSETHUB_PARA_ID: u32 = 1000; @@ -66,6 +67,17 @@ pub fn genesis() -> Storage { owner: Some(get_account_id_from_seed::(accounts::BOB)), ..Default::default() }, + xcm_over_bridge_hub_rococo: bridge_hub_westend_runtime::XcmOverBridgeHubRococoConfig { + opened_bridges: vec![ + // open AHW -> AHR bridge + ( + Location::new(1, [Parachain(1000)]), + Junctions::from([Rococo.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + ), + ], + ..Default::default() + }, ethereum_system: bridge_hub_westend_runtime::EthereumSystemConfig { para_id: PARA_ID.into(), asset_hub_para_id: ASSETHUB_PARA_ID.into(), diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 559a16379bb4..c0d42cf2758e 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -61,10 +61,10 @@ pub use xcm_emulator::{ // Bridges use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - LaneId, MessageKey, OutboundLaneData, + MessageKey, OutboundLaneData, }; pub use bp_xcm_bridge_hub::XcmBridgeHubCall; -use pallet_bridge_messages::{Config as BridgeMessagesConfig, OutboundLanes, Pallet}; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, LaneIdOf, OutboundLanes, Pallet}; pub use pallet_bridge_messages::{ Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2, Instance3 as BridgeMessagesInstance3, @@ -75,14 +75,14 @@ pub struct BridgeHubMessageHandler { _marker: std::marker::PhantomData<(S, SI, T, TI)>, } -struct LaneIdWrapper(LaneId); -impl From for BridgeLaneId { - fn from(lane_id: LaneIdWrapper) -> BridgeLaneId { +struct LaneIdWrapper(LaneId); +impl From> for BridgeLaneId { + fn from(lane_id: LaneIdWrapper) -> BridgeLaneId { lane_id.0.encode() } } -impl From for LaneIdWrapper { - fn from(id: BridgeLaneId) -> LaneIdWrapper { +impl From for LaneIdWrapper { + fn from(id: BridgeLaneId) -> LaneIdWrapper { LaneIdWrapper(LaneId::decode(&mut &id[..]).expect("decodable")) } } @@ -154,7 +154,7 @@ where } fn notify_source_message_delivery(lane_id: BridgeLaneId) { - let lane_id = LaneIdWrapper::from(lane_id).0; + let lane_id: LaneIdOf = LaneIdWrapper::from(lane_id).0; let data = OutboundLanes::::get(lane_id).unwrap(); let new_data = OutboundLaneData { oldest_unpruned_nonce: data.oldest_unpruned_nonce + 1, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index f4fe1478f3ed..0e43108a417b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -51,6 +51,7 @@ mod imports { pub use rococo_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ asset_hub_rococo_runtime::{ + self, xcm_config::{ self as ahr_xcm_config, TokenLocation as RelayLocation, XcmConfig as AssetHubRococoXcmConfig, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs index 7ff6d6c193c9..7bb25d7cec62 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs @@ -449,7 +449,16 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { let sov_of_receiver_on_ah = AssetHubRococo::sovereign_account_id_of(receiver_as_seen_by_ah); let wnd_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000; - // Configure destination chain to trust AH as reserve of WND + // Configure source and destination chains to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); PenpalB::execute_with(|| { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index faff5f7660c2..8aad4b392b2c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -1548,3 +1548,58 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } + +/// Reserve Withdraw Native Asset from AssetHub to Parachain fails. +#[test] +fn reserve_withdraw_from_untrusted_reserve_fails() { + // Init values for Parachain Origin + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + let roc_to_send: Balance = ROCOCO_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubRococo::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::DestinationReserve), + bx!(fee_id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + }) + ); + }); + + // this should also fail + AssetHubRococo::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(All), + reserve: destination, + xcm: Xcm::<()>::new(), + }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index c8da801a14bf..470b4d0f389e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -265,7 +265,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let delivery_fees = AssetHubRococo::execute_with(|| { xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >( + test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced @@ -527,3 +529,54 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { system_para_to_para_transfer_assets, ); } + +/// Teleport Native Asset from AssetHub to Parachain fails. +#[test] +fn teleport_to_untrusted_chain_fails() { + // Init values for Parachain Origin + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + let roc_to_send: Balance = ROCOCO_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubRococo::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::Teleport), + bx!(fee_id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); + + // this should also fail + AssetHubRococo::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateTeleport { assets: Wild(All), dest: destination, xcm: Xcm::<()>::new() }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index f568fb4101db..d0016b5a1b15 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -48,6 +48,7 @@ mod imports { pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ asset_hub_westend_runtime::{ + self, xcm_config::{ self as ahw_xcm_config, WestendLocation as RelayLocation, XcmConfig as AssetHubWestendXcmConfig, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs index 975bacea7b4f..4d6cdd9a94d6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs @@ -450,7 +450,16 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { let sov_of_receiver_on_ah = AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_ah); let roc_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; - // Configure destination chain to trust AH as reserve of ROC + // Configure source and destination chains to trust AH as reserve of ROC + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Rococo)]).encode(), + )], + )); + }); PenpalB::execute_with(|| { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 53b6939298da..0100e8e34ef3 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -1552,3 +1552,58 @@ fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } + +/// Reserve Withdraw Native Asset from AssetHub to Parachain fails. +#[test] +fn reserve_withdraw_from_untrusted_reserve_fails() { + // Init values for Parachain Origin + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + let roc_to_send: Balance = WESTEND_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubWestend::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::DestinationReserve), + bx!(fee_id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + }) + ); + }); + + // this should also fail + AssetHubWestend::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(All), + reserve: destination, + xcm: Xcm::<()>::new(), + }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 15d39858acca..ee0f297792f8 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -265,7 +265,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let delivery_fees = AssetHubWestend::execute_with(|| { xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >( + test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced @@ -530,3 +532,54 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { system_para_to_para_transfer_assets, ); } + +/// Teleport Native Asset from AssetHub to Parachain fails. +#[test] +fn teleport_to_untrusted_chain_fails() { + // Init values for Parachain Origin + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + let roc_to_send: Balance = WESTEND_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubWestend::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::Teleport), + bx!(fee_id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); + + // this should also fail + AssetHubWestend::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateTeleport { assets: Wild(All), dest: destination, xcm: Xcm::<()>::new() }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 9d54d431e839..e83b28076789 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -16,6 +16,7 @@ #[cfg(test)] mod imports { // Substrate + pub use codec::Encode; pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; pub use sp_runtime::DispatchError; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index 6df51c5f7048..11930798da44 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -432,6 +432,16 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste ASSET_MIN_BALANCE, vec![(sender.clone(), amount * 2)], ); + // Configure source Penpal chain to trust local AH as reserve of bridged WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + wnd_at_rococo_parachains.encode(), + )], + )); + }); // fund the AHR's SA on AHW with the WND tokens held in reserve let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index b540f55642a5..a989881fef09 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -231,17 +231,6 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { )), )), ); - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubRococo, - vec![ - RuntimeEvent::XcmOverBridgeHubWestend( - pallet_xcm_bridge_hub::Event::BridgeOpened { .. } - ) => {}, - ] - ); - }); // open AHW -> AHR BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); @@ -255,15 +244,4 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { )), )), ); - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubWestend, - vec![ - RuntimeEvent::XcmOverBridgeHubRococo( - pallet_xcm_bridge_hub::Event::BridgeOpened { .. } - ) => {}, - ] - ); - }); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 5e0462d14882..d9b92cb11e92 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -16,6 +16,7 @@ #[cfg(test)] mod imports { // Substrate + pub use codec::Encode; pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; pub use sp_runtime::DispatchError; @@ -52,7 +53,10 @@ mod imports { BridgeHubWestendParaPallet as BridgeHubWestendPallet, BridgeHubWestendXcmConfig, }, penpal_emulated_chain::{ - penpal_runtime::xcm_config::UniversalLocation as PenpalUniversalLocation, + penpal_runtime::xcm_config::{ + CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + UniversalLocation as PenpalUniversalLocation, + }, PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, }, westend_emulated_chain::{ diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index c3f81175da23..6492c520234f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -452,6 +452,16 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc ASSET_MIN_BALANCE, vec![(sender.clone(), amount * 2)], ); + // Configure source Penpal chain to trust local AH as reserve of bridged ROC + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + roc_at_westend_parachains.encode(), + )], + )); + }); // fund the AHW's SA on AHR with the ROC tokens held in reserve let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index 699641d3328f..f037a05a8276 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -246,17 +246,6 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { )), )), ); - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubRococo, - vec![ - RuntimeEvent::XcmOverBridgeHubWestend( - pallet_xcm_bridge_hub::Event::BridgeOpened { .. } - ) => {}, - ] - ); - }); // open AHW -> AHR BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); @@ -270,15 +259,4 @@ pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { )), )), ); - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubWestend, - vec![ - RuntimeEvent::XcmOverBridgeHubRococo( - pallet_xcm_bridge_hub::Event::BridgeOpened { .. } - ) => {}, - ] - ); - }); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs index 44e6b3934f0e..2619ca7591d0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/src/tests/teleport.rs @@ -107,7 +107,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let delivery_fees = PeopleRococo::execute_with(|| { xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >( + test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs index 83888031723f..d9a2c23ac0c6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/teleport.rs @@ -107,7 +107,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { let delivery_fees = PeopleWestend::execute_with(|| { xcm_helpers::teleport_assets_delivery_fees::< ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) + >( + test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index e46734dfa97d..8163a445220b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -545,7 +545,8 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } | RuntimeCall::NftFractionalization { .. } | - RuntimeCall::Nfts { .. } | RuntimeCall::Uniques { .. } + RuntimeCall::Nfts { .. } | + RuntimeCall::Uniques { .. } ) }, ProxyType::AssetOwner => matches!( @@ -866,7 +867,7 @@ impl pallet_nft_fractionalization::Config for Runtime { type Assets = Assets; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; - type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; + type WeightInfo = weights::pallet_nft_fractionalization::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 946b72e966e9..75aea0eb2c2f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -543,7 +543,8 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } | RuntimeCall::NftFractionalization { .. } | - RuntimeCall::Nfts { .. } | RuntimeCall::Uniques { .. } + RuntimeCall::Nfts { .. } | + RuntimeCall::Uniques { .. } ) }, ProxyType::AssetOwner => matches!( @@ -859,7 +860,7 @@ impl pallet_nft_fractionalization::Config for Runtime { type Assets = Assets; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; - type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; + type WeightInfo = weights::pallet_nft_fractionalization::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index 67b585ecfe86..c80222142304 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1143,7 +1143,8 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor .with_balances(vec![( foreign_creator_as_account_id.clone(), existential_deposit + - asset_deposit + metadata_deposit_base + + asset_deposit + + metadata_deposit_base + metadata_deposit_per_byte_eta + buy_execution_fee_amount.into() + buy_execution_fee_amount.into(), diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs index 779cc537ee96..5dca45d326b8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -64,11 +64,37 @@ impl pallet_bridge_parachains::Config for Runtim } /// Allows collect and claim rewards for relayers -impl pallet_bridge_relayers::Config for Runtime { +pub type RelayersForLegacyLaneIdsMessagesInstance = (); +impl pallet_bridge_relayers::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reward = Balance; - type PaymentProcedure = - bp_relayers::PayRewardFromAccount, AccountId>; + type PaymentProcedure = bp_relayers::PayRewardFromAccount< + pallet_balances::Pallet, + AccountId, + Self::LaneId, + >; + type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< + AccountId, + BlockNumber, + Balances, + RelayerStakeReserveId, + RequiredStakeForStakeAndSlash, + RelayerStakeLease, + >; + type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; + type LaneId = bp_messages::LegacyLaneId; +} + +/// Allows collect and claim rewards for relayers +pub type RelayersForPermissionlessLanesInstance = pallet_bridge_relayers::Instance2; +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = bp_relayers::PayRewardFromAccount< + pallet_balances::Pallet, + AccountId, + Self::LaneId, + >; type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< AccountId, BlockNumber, @@ -78,6 +104,7 @@ impl pallet_bridge_relayers::Config for Runtime { RelayerStakeLease, >; type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; + type LaneId = bp_messages::HashedLaneId; } /// Add GRANDPA bridge pallet to track Rococo Bulletin chain. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs index 00d902486c85..c971fa59c68d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -20,13 +20,14 @@ //! are reusing Polkadot Bulletin chain primitives everywhere here. use crate::{ - weights, xcm_config::UniversalLocation, AccountId, Balance, Balances, - BridgeRococoBulletinGrandpa, BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, - RuntimeHoldReason, XcmOverRococoBulletin, XcmRouter, + bridge_common_config::RelayersForPermissionlessLanesInstance, weights, + xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeRococoBulletinGrandpa, + BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeHoldReason, + XcmOverRococoBulletin, XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, + target_chain::FromBridgedChainMessagesProof, HashedLaneId, }; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; @@ -34,11 +35,11 @@ use frame_support::{ parameter_types, traits::{Equals, PalletInfoAccess}, }; -use frame_system::EnsureRoot; +use frame_system::{EnsureNever, EnsureRoot}; +use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersSignedExtension, WithMessagesExtensionConfig, }; -use pallet_xcm::EnsureXcm; use pallet_xcm_bridge_hub::XcmAsPlainPayload; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; @@ -78,11 +79,11 @@ parameter_types! { } /// Proof of messages, coming from Rococo Bulletin chain. -pub type FromRococoBulletinMessagesProof = - FromBridgedChainMessagesProof; +pub type FromRococoBulletinMessagesProof = + FromBridgedChainMessagesProof>; /// Messages delivery proof for Rococo Bridge Hub -> Rococo Bulletin messages. -pub type ToRococoBulletinMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; +pub type ToRococoBulletinMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof>; /// Dispatches received XCM messages from other bridge. type FromRococoBulletinMessageBlobDispatcher = BridgeBlobDispatcher< @@ -99,8 +100,10 @@ pub type OnBridgeHubRococoRefundRococoBulletinMessages = BridgeRelayersSignedExt StrOnBridgeHubRococoRefundRococoBulletinMessages, Runtime, WithRococoBulletinMessagesInstance, + RelayersForPermissionlessLanesInstance, PriorityBoostPerMessage, >, + LaneIdOf, >; bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundRococoBulletinMessages); @@ -116,10 +119,10 @@ impl pallet_bridge_messages::Config for Runt type BridgedHeaderChain = BridgeRococoBulletinGrandpa; type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = XcmAsPlainPayload; - type DeliveryPayments = (); + type LaneId = HashedLaneId; + type DeliveryPayments = (); type DeliveryConfirmationPayments = (); type MessageDispatch = XcmOverRococoBulletin; @@ -139,9 +142,9 @@ impl pallet_xcm_bridge_hub::Config for Runtime type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type AdminOrigin = EnsureRoot; - // Only allow calls from sibling People parachain to directly open the bridge. - type OpenBridgeOrigin = EnsureXcm>; + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance. + type OpenBridgeOrigin = EnsureNever; // Converter aligned with `OpenBridgeOrigin`. type BridgeOriginAccountIdConverter = (ParentIsPreset, SiblingParachainConvertsVia); @@ -230,14 +233,20 @@ mod tests { } #[cfg(feature = "runtime-benchmarks")] -pub(crate) fn open_bridge_for_benchmarks( - with: bp_messages::LaneId, +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, sibling_para_id: u32, -) -> InteriorLocation { +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use sp_runtime::traits::Zero; use xcm::VersionedInteriorLocation; - use xcm_executor::traits::ConvertLocation; // insert bridge metadata let lane_id = with; @@ -248,7 +257,7 @@ pub(crate) fn open_bridge_for_benchmarks( let bridge_id = BridgeId::new(&universal_source, &universal_destination); // insert only bridge metadata, because the benchmarks create lanes - pallet_xcm_bridge_hub::Bridges::::insert( + pallet_xcm_bridge_hub::Bridges::::insert( bridge_id, Bridge { bridge_origin_relative_location: alloc::boxed::Box::new( @@ -261,17 +270,12 @@ pub(crate) fn open_bridge_for_benchmarks( VersionedInteriorLocation::from(universal_destination), ), state: BridgeState::Opened, - bridge_owner_account: crate::xcm_config::LocationToAccountId::convert_location( - &sibling_parachain, - ) - .expect("valid AccountId"), - deposit: Balance::zero(), + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), lane_id, }, ); - pallet_xcm_bridge_hub::LaneToBridge::::insert( - lane_id, bridge_id, - ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); universal_source } @@ -279,13 +283,16 @@ pub(crate) fn open_bridge_for_benchmarks( /// Contains the migration for the PeopleRococo<>RococoBulletin bridge. pub mod migration { use super::*; - use bp_messages::LaneId; use frame_support::traits::ConstBool; - use sp_runtime::Either; parameter_types! { - pub RococoPeopleToRococoBulletinMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 0])); pub BulletinRococoLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); + pub RococoPeopleToRococoBulletinMessagesLane: HashedLaneId = pallet_xcm_bridge_hub::Pallet::< Runtime, XcmOverPolkadotBulletinInstance >::bridge_locations( + PeopleRococoLocation::get(), + BulletinRococoLocation::get() + ) + .unwrap() + .calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"); } /// Ensure that the existing lanes for the People<>Bulletin bridge are correctly configured. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index fc52413a909f..8fe045723107 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -17,7 +17,10 @@ //! Bridge definitions used on BridgeHubRococo for bridging to BridgeHubWestend. use crate::{ - bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, + bridge_common_config::{ + BridgeParachainWestendInstance, DeliveryRewardInBalance, + RelayersForLegacyLaneIdsMessagesInstance, + }, weights, xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, @@ -25,20 +28,18 @@ use crate::{ }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, + target_chain::FromBridgedChainMessagesProof, LegacyLaneId, }; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; use pallet_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::{parameter_types, traits::PalletInfoAccess}; -use frame_system::EnsureRoot; +use frame_system::{EnsureNever, EnsureRoot}; +use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersSignedExtension, WithMessagesExtensionConfig, }; -use pallet_xcm::EnsureXcm; -use parachains_common::xcm_config::{ - AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, -}; +use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ @@ -73,11 +74,11 @@ parameter_types! { } /// Proof of messages, coming from Westend. -pub type FromWestendBridgeHubMessagesProof = - FromBridgedChainMessagesProof; +pub type FromWestendBridgeHubMessagesProof = + FromBridgedChainMessagesProof>; /// Messages delivery proof for Rococo Bridge Hub -> Westend Bridge Hub messages. -pub type ToWestendBridgeHubMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; +pub type ToWestendBridgeHubMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof>; /// Dispatches received XCM messages from other bridge type FromWestendMessageBlobDispatcher = @@ -90,8 +91,10 @@ pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersSignedE StrOnBridgeHubRococoRefundBridgeHubWestendMessages, Runtime, WithBridgeHubWestendMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, PriorityBoostPerMessage, >, + LaneIdOf, >; bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWestendMessages); @@ -110,10 +113,10 @@ impl pallet_bridge_messages::Config for Ru >; type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = XcmAsPlainPayload; - type DeliveryPayments = (); + type LaneId = LegacyLaneId; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubWestendMessagesInstance, @@ -124,7 +127,8 @@ impl pallet_bridge_messages::Config for Ru type OnMessagesDelivered = XcmOverBridgeHubWestend; } -/// Add support for the export and dispatch of XCM programs. +/// Add support for the export and dispatch of XCM programs withing +/// `WithBridgeHubWestendMessagesInstance`. pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -137,9 +141,9 @@ impl pallet_xcm_bridge_hub::Config for Runtime type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type AdminOrigin = EnsureRoot; - // Only allow calls from relay chains and sibling parachains to directly open the bridge. - type OpenBridgeOrigin = EnsureXcm; + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance with `LegacyLaneId`. + type OpenBridgeOrigin = EnsureNever; // Converter aligned with `OpenBridgeOrigin`. type BridgeOriginAccountIdConverter = (ParentIsPreset, SiblingParachainConvertsVia); @@ -157,14 +161,20 @@ impl pallet_xcm_bridge_hub::Config for Runtime } #[cfg(feature = "runtime-benchmarks")] -pub(crate) fn open_bridge_for_benchmarks( - with: bp_messages::LaneId, +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, sibling_para_id: u32, -) -> InteriorLocation { +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use sp_runtime::traits::Zero; use xcm::VersionedInteriorLocation; - use xcm_executor::traits::ConvertLocation; // insert bridge metadata let lane_id = with; @@ -174,7 +184,7 @@ pub(crate) fn open_bridge_for_benchmarks( let bridge_id = BridgeId::new(&universal_source, &universal_destination); // insert only bridge metadata, because the benchmarks create lanes - pallet_xcm_bridge_hub::Bridges::::insert( + pallet_xcm_bridge_hub::Bridges::::insert( bridge_id, Bridge { bridge_origin_relative_location: alloc::boxed::Box::new( @@ -187,17 +197,12 @@ pub(crate) fn open_bridge_for_benchmarks( VersionedInteriorLocation::from(universal_destination), ), state: BridgeState::Opened, - bridge_owner_account: crate::xcm_config::LocationToAccountId::convert_location( - &sibling_parachain, - ) - .expect("valid AccountId"), - deposit: Balance::zero(), + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), lane_id, }, ); - pallet_xcm_bridge_hub::LaneToBridge::::insert( - lane_id, bridge_id, - ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); universal_source } @@ -297,12 +302,10 @@ mod tests { /// Contains the migration for the AssetHubRococo<>AssetHubWestend bridge. pub mod migration { use super::*; - use bp_messages::LaneId; use frame_support::traits::ConstBool; - use sp_runtime::Either; parameter_types! { - pub AssetHubRococoToAssetHubWestendMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 2])); + pub AssetHubRococoToAssetHubWestendMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]); pub AssetHubRococoLocation: Location = Location::new(1, [Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)]); pub AssetHubWestendUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)].into(); } @@ -318,4 +321,75 @@ pub mod migration { AssetHubRococoLocation, AssetHubWestendUniversalLocation, >; + + mod v1_wrong { + use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer}; + use bp_runtime::AccountIdOf; + use codec::{Decode, Encode}; + use pallet_bridge_messages::BridgedChainOf; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct StoredInboundLaneData, I: 'static>( + pub(crate) InboundLaneData>>, + ); + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct InboundLaneData { + pub state: LaneState, + pub(crate) relayers: VecDeque>, + pub(crate) last_confirmed_nonce: MessageNonce, + } + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct OutboundLaneData { + pub state: LaneState, + pub(crate) oldest_unpruned_nonce: MessageNonce, + pub(crate) latest_received_nonce: MessageNonce, + pub(crate) latest_generated_nonce: MessageNonce, + } + } + + mod v1 { + pub use bp_messages::{InboundLaneData, LaneState, OutboundLaneData}; + pub use pallet_bridge_messages::{InboundLanes, OutboundLanes, StoredInboundLaneData}; + } + + /// Fix for v1 migration - corrects data for OutboundLaneData/InboundLaneData (it is needed only + /// for Rococo/Westend). + pub struct FixMessagesV1Migration(sp_std::marker::PhantomData<(T, I)>); + + impl, I: 'static> frame_support::traits::OnRuntimeUpgrade + for FixMessagesV1Migration + { + fn on_runtime_upgrade() -> Weight { + use sp_core::Get; + let mut weight = T::DbWeight::get().reads(1); + + // `InboundLanes` - add state to the old structs + let translate_inbound = + |pre: v1_wrong::StoredInboundLaneData| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::StoredInboundLaneData(v1::InboundLaneData { + state: v1::LaneState::Opened, + relayers: pre.0.relayers, + last_confirmed_nonce: pre.0.last_confirmed_nonce, + })) + }; + v1::InboundLanes::::translate_values(translate_inbound); + + // `OutboundLanes` - add state to the old structs + let translate_outbound = + |pre: v1_wrong::OutboundLaneData| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::OutboundLaneData { + state: v1::LaneState::Opened, + oldest_unpruned_nonce: pre.oldest_unpruned_nonce, + latest_received_nonce: pre.latest_received_nonce, + latest_generated_nonce: pre.latest_generated_nonce, + }) + }; + v1::OutboundLanes::::translate_values(translate_outbound); + + weight + } + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs index e5d615985646..07048d54ab1b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs @@ -31,6 +31,7 @@ fn bridge_hub_rococo_genesis( id: ParaId, bridges_pallet_owner: Option, asset_hub_para_id: ParaId, + opened_bridges: Vec<(Location, InteriorLocation, Option)>, ) -> serde_json::Value { let config = RuntimeGenesisConfig { balances: BalancesConfig { @@ -71,6 +72,10 @@ fn bridge_hub_rococo_genesis( owner: bridges_pallet_owner.clone(), ..Default::default() }, + xcm_over_bridge_hub_westend: XcmOverBridgeHubWestendConfig { + opened_bridges, + ..Default::default() + }, ethereum_system: EthereumSystemConfig { para_id: id, asset_hub_para_id, @@ -114,6 +119,11 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option("Bob")), rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![( + Location::new(1, [Parachain(1000)]), + Junctions::from([Westend.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + )], ), Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => bridge_hub_rococo_genesis( // initial collators. @@ -144,6 +154,7 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option("Bob")), rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![], ), _ => return None, }; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 177978cee10b..13c1ab6b625b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -43,6 +43,7 @@ use bridge_runtime_common::extensions::{ CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; +use pallet_bridge_messages::LaneIdOf; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -130,10 +131,7 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, - ( - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages,), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, frame_metadata_hash_extension::CheckMetadataHash, ); @@ -163,6 +161,10 @@ pub type Migrations = ( Runtime, bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, >, + bridge_to_westend_config::migration::FixMessagesV1Migration< + Runtime, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, + >, bridge_to_westend_config::migration::StaticToDynamicLanes, bridge_to_bulletin_config::migration::StaticToDynamicLanes, frame_support::migrations::RemoveStorage< @@ -175,6 +177,7 @@ pub type Migrations = ( OutboundLanesCongestedSignalsKey, RocksDbWeight, >, + pallet_bridge_relayers::migration::v1::MigrationToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -235,10 +238,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_016_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, + transaction_version: 6, system_version: 1, }; @@ -593,6 +596,9 @@ construct_runtime!( // With-Rococo Bulletin bridge hub pallet. XcmOverPolkadotBulletin: pallet_xcm_bridge_hub:: = 62, + // Bridge relayers pallet, used by several bridges here (another instance). + BridgeRelayersForPermissionlessLanes: pallet_bridge_relayers:: = 63, + EthereumInboundQueue: snowbridge_pallet_inbound_queue = 80, EthereumOutboundQueue: snowbridge_pallet_outbound_queue = 81, EthereumBeaconClient: snowbridge_pallet_ethereum_client = 82, @@ -662,7 +668,8 @@ mod benches { [pallet_bridge_parachains, WithinWestend] [pallet_bridge_messages, RococoToWestend] [pallet_bridge_messages, RococoToRococoBulletin] - [pallet_bridge_relayers, BridgeRelayersBench::] + [pallet_bridge_relayers, Legacy] + [pallet_bridge_relayers, PermissionlessLanes] // Ethereum Bridge [snowbridge_pallet_inbound_queue, EthereumInboundQueue] [snowbridge_pallet_outbound_queue, EthereumOutboundQueue] @@ -671,6 +678,11 @@ mod benches { ); } +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} + impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { @@ -914,7 +926,7 @@ impl_runtime_apis! { // This is exposed by BridgeHubRococo impl bp_bridge_hub_westend::FromBridgeHubWestendInboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< @@ -927,7 +939,7 @@ impl_runtime_apis! { // This is exposed by BridgeHubRococo impl bp_bridge_hub_westend::ToBridgeHubWestendOutboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> Vec { @@ -957,7 +969,7 @@ impl_runtime_apis! { impl bp_polkadot_bulletin::FromPolkadotBulletinInboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< @@ -969,7 +981,7 @@ impl_runtime_apis! { impl bp_polkadot_bulletin::ToPolkadotBulletinOutboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> Vec { @@ -1039,6 +1051,8 @@ impl_runtime_apis! { type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet ::; + type Legacy = BridgeRelayersBench::; + type PermissionlessLanes = BridgeRelayersBench::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1248,15 +1262,20 @@ impl_runtime_apis! { ); // open bridge - let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(sibling_parachain_location.clone())); - XcmOverBridgeHubWestend::open_bridge( - origin.clone(), - Box::new(VersionedInteriorLocation::from([GlobalConsensus(NetworkId::Westend), Parachain(8765)])), + let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(8765)].into(); + let locations = XcmOverBridgeHubWestend::bridge_locations( + sibling_parachain_location.clone(), + bridge_destination_universal_location.clone(), + )?; + XcmOverBridgeHubWestend::do_open_bridge( + locations, + bp_messages::LegacyLaneId([1, 2, 3, 4]), + true, ).map_err(|e| { log::error!( "Failed to `XcmOverBridgeHubWestend::open_bridge`({:?}, {:?})`, error: {:?}", - origin, - [GlobalConsensus(NetworkId::Westend), Parachain(8765)], + sibling_parachain_location, + bridge_destination_universal_location, e ); BenchmarkError::Stop("Bridge was not opened!") @@ -1283,6 +1302,8 @@ impl_runtime_apis! { type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet ::; + type Legacy = BridgeRelayersBench::; + type PermissionlessLanes = BridgeRelayersBench::; use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_grandpa_chain, @@ -1313,12 +1334,16 @@ impl_runtime_apis! { } fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_westend_config::FromWestendBridgeHubMessagesProof, Weight) { + params: MessageProofParams>, + ) -> (bridge_to_westend_config::FromWestendBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - let universal_source = bridge_to_westend_config::open_bridge_for_benchmarks(params.lane, 42); + let universal_source = bridge_to_westend_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_westend_config::XcmOverBridgeHubWestendInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, @@ -1327,9 +1352,13 @@ impl_runtime_apis! { } fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { - let _ = bridge_to_westend_config::open_bridge_for_benchmarks(params.lane, 42); + params: MessageDeliveryProofParams>, + ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { + let _ = bridge_to_westend_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_westend_config::XcmOverBridgeHubWestendInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, @@ -1350,12 +1379,16 @@ impl_runtime_apis! { } fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_bulletin_config::FromRococoBulletinMessagesProof, Weight) { + params: MessageProofParams>, + ) -> (bridge_to_bulletin_config::FromRococoBulletinMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - let universal_source = bridge_to_bulletin_config::open_bridge_for_benchmarks(params.lane, 42); + let universal_source = bridge_to_bulletin_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_bulletin_config::XcmOverPolkadotBulletinInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, @@ -1364,9 +1397,13 @@ impl_runtime_apis! { } fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_bulletin_config::ToRococoBulletinMessagesDeliveryProof { - let _ = bridge_to_bulletin_config::open_bridge_for_benchmarks(params.lane, 42); + params: MessageDeliveryProofParams>, + ) -> bridge_to_bulletin_config::ToRococoBulletinMessagesDeliveryProof { + let _ = bridge_to_bulletin_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_bulletin_config::XcmOverPolkadotBulletinInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_delivery_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, @@ -1411,16 +1448,36 @@ impl_runtime_apis! { } } - impl BridgeRelayersConfig for Runtime { + impl BridgeRelayersConfig for Runtime { fn prepare_rewards_account( - account_params: bp_relayers::RewardsAccountParams, + account_params: bp_relayers::RewardsAccountParams<>::LaneId>, reward: Balance, ) { let rewards_account = bp_relayers::PayRewardFromAccount::< Balances, - AccountId + AccountId, + >::LaneId, >::rewards_account(account_params); - Self::deposit_account(rewards_account, reward); + >::deposit_account(rewards_account, reward); + } + + fn deposit_account(account: AccountId, balance: Balance) { + use frame_support::traits::fungible::Mutate; + Balances::mint_into(&account, balance.saturating_add(ExistentialDeposit::get())).unwrap(); + } + } + + impl BridgeRelayersConfig for Runtime { + fn prepare_rewards_account( + account_params: bp_relayers::RewardsAccountParams<>::LaneId>, + reward: Balance, + ) { + let rewards_account = bp_relayers::PayRewardFromAccount::< + Balances, + AccountId, + >::LaneId, + >::rewards_account(account_params); + >::deposit_account(rewards_account, reward); } fn deposit_account(account: AccountId, balance: Balance) { @@ -1465,11 +1522,6 @@ impl_runtime_apis! { } } -cumulus_pallet_parachain_system::register_validate_block! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} - #[cfg(test)] mod tests { use super::*; @@ -1497,7 +1549,6 @@ mod tests { BridgeRejectObsoleteHeadersAndMessages, ( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::new(false), diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index c7b5850f9ffe..7a0f1462e7a7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -18,7 +18,6 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, @@ -183,10 +182,7 @@ fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), - ( - OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ), + (OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::::new(false), ); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 982c9fec6634..002e31174cb1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -62,10 +62,7 @@ fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), - ( - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::new(false), ); @@ -145,8 +142,10 @@ fn change_required_stake_by_governance_works() { mod bridge_hub_westend_tests { use super::*; + use bp_messages::LegacyLaneId; use bridge_common_config::{ BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, DeliveryRewardInBalance, + RelayersForLegacyLaneIdsMessagesInstance, }; use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ @@ -174,6 +173,7 @@ mod bridge_hub_westend_tests { BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, WithBridgeHubWestendMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, >; #[test] @@ -338,7 +338,16 @@ mod bridge_hub_westend_tests { XcmOverBridgeHubWestendInstance, LocationToAccountId, TokenLocation, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()).1 + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubWestendInstance + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + } + ).1 }, ) } @@ -393,10 +402,20 @@ mod bridge_hub_westend_tests { XcmOverBridgeHubWestendInstance, LocationToAccountId, TokenLocation, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubWestendInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) .1 }, construct_and_apply_extrinsic, + true, ) } @@ -417,10 +436,20 @@ mod bridge_hub_westend_tests { XcmOverBridgeHubWestendInstance, LocationToAccountId, TokenLocation, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubWestendInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) .1 }, construct_and_apply_extrinsic, + false, ) } @@ -482,30 +511,13 @@ mod bridge_hub_westend_tests { ), ) } - - #[test] - fn open_and_close_bridge_works() { - let origins = [SiblingParachainLocation::get(), SiblingSystemParachainLocation::get()]; - - for origin in origins { - bridge_hub_test_utils::test_cases::open_and_close_bridge_works::< - Runtime, - XcmOverBridgeHubWestendInstance, - LocationToAccountId, - TokenLocation, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - origin, - BridgedUniversalLocation::get(), - ) - } - } } mod bridge_hub_bulletin_tests { use super::*; + use bp_messages::{HashedLaneId, LaneIdType}; use bridge_common_config::BridgeGrandpaRococoBulletinInstance; + use bridge_hub_rococo_runtime::bridge_common_config::RelayersForPermissionlessLanesInstance; use bridge_hub_test_utils::test_cases::from_grandpa_chain; use bridge_to_bulletin_config::{ RococoBulletinGlobalConsensusNetwork, RococoBulletinGlobalConsensusNetworkLocation, @@ -527,6 +539,7 @@ mod bridge_hub_bulletin_tests { AllPalletsWithoutSystem, BridgeGrandpaRococoBulletinInstance, WithRococoBulletinMessagesInstance, + RelayersForPermissionlessLanesInstance, >; #[test] @@ -589,7 +602,16 @@ mod bridge_hub_bulletin_tests { XcmOverPolkadotBulletinInstance, LocationToAccountId, TokenLocation, - >(SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get()).1 + >( + SiblingPeopleParachainLocation::get(), + BridgedBulletinLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverPolkadotBulletinInstance + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + } + ).1 }, ) } @@ -643,10 +665,20 @@ mod bridge_hub_bulletin_tests { XcmOverPolkadotBulletinInstance, LocationToAccountId, TokenLocation, - >(SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get()) + >( + SiblingPeopleParachainLocation::get(), + BridgedBulletinLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverPolkadotBulletinInstance, + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + }, + ) .1 }, construct_and_apply_extrinsic, + false, ) } @@ -666,29 +698,20 @@ mod bridge_hub_bulletin_tests { XcmOverPolkadotBulletinInstance, LocationToAccountId, TokenLocation, - >(SiblingPeopleParachainLocation::get(), BridgedBulletinLocation::get()) + >( + SiblingPeopleParachainLocation::get(), + BridgedBulletinLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverPolkadotBulletinInstance, + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + }, + ) .1 }, construct_and_apply_extrinsic, + false, ) } - - #[test] - fn open_and_close_bridge_works() { - let origins = [SiblingPeopleParachainLocation::get()]; - - for origin in origins { - bridge_hub_test_utils::test_cases::open_and_close_bridge_works::< - Runtime, - XcmOverPolkadotBulletinInstance, - LocationToAccountId, - TokenLocation, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - origin, - BridgedBulletinLocation::get(), - ) - } - } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs index 9bae106395a6..0872d0498f85 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs @@ -22,6 +22,7 @@ //! GRANDPA tracking pallet only needs to be aware of one chain. use super::{weights, AccountId, Balance, Balances, BlockNumber, Runtime, RuntimeEvent}; +use bp_messages::LegacyLaneId; use frame_support::parameter_types; parameter_types! { @@ -33,11 +34,15 @@ parameter_types! { } /// Allows collect and claim rewards for relayers -impl pallet_bridge_relayers::Config for Runtime { +pub type RelayersForLegacyLaneIdsMessagesInstance = (); +impl pallet_bridge_relayers::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reward = Balance; - type PaymentProcedure = - bp_relayers::PayRewardFromAccount, AccountId>; + type PaymentProcedure = bp_relayers::PayRewardFromAccount< + pallet_balances::Pallet, + AccountId, + Self::LaneId, + >; type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< AccountId, BlockNumber, @@ -47,4 +52,5 @@ impl pallet_bridge_relayers::Config for Runtime { RelayerStakeLease, >; type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; + type LaneId = LegacyLaneId; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 2d9e8f664276..e45654bc62bd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -17,13 +17,15 @@ //! Bridge definitions used on BridgeHub with the Westend flavor. use crate::{ - bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, + bridge_common_config::{DeliveryRewardInBalance, RelayersForLegacyLaneIdsMessagesInstance}, + weights, + xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, + target_chain::FromBridgedChainMessagesProof, LegacyLaneId, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; @@ -33,14 +35,12 @@ use frame_support::{ parameter_types, traits::{ConstU32, PalletInfoAccess}, }; -use frame_system::EnsureRoot; +use frame_system::{EnsureNever, EnsureRoot}; +use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ BridgeRelayersSignedExtension, WithMessagesExtensionConfig, }; -use pallet_xcm::EnsureXcm; -use parachains_common::xcm_config::{ - AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, -}; +use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; use polkadot_parachain_primitives::primitives::Sibling; use testnet_parachains_constants::westend::currency::UNITS as WND; use xcm::{ @@ -81,11 +81,11 @@ parameter_types! { } /// Proof of messages, coming from Rococo. -pub type FromRococoBridgeHubMessagesProof = - FromBridgedChainMessagesProof; +pub type FromRococoBridgeHubMessagesProof = + FromBridgedChainMessagesProof>; /// Messages delivery proof for Rococo Bridge Hub -> Westend Bridge Hub messages. -pub type ToRococoBridgeHubMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; +pub type ToRococoBridgeHubMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof>; /// Dispatches received XCM messages from other bridge type FromRococoMessageBlobDispatcher = @@ -98,8 +98,10 @@ pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersSignedE StrOnBridgeHubWestendRefundBridgeHubRococoMessages, Runtime, WithBridgeHubRococoMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, PriorityBoostPerMessage, >, + LaneIdOf, >; bp_runtime::generate_static_str_provider!(OnBridgeHubWestendRefundBridgeHubRococoMessages); @@ -142,10 +144,10 @@ impl pallet_bridge_messages::Config for Run >; type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = XcmAsPlainPayload; - type DeliveryPayments = (); + type LaneId = LegacyLaneId; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubRococoMessagesInstance, @@ -168,9 +170,9 @@ impl pallet_xcm_bridge_hub::Config for Runtime { type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type AdminOrigin = EnsureRoot; - // Only allow calls from relay chains and sibling parachains to directly open the bridge. - type OpenBridgeOrigin = EnsureXcm; + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance with `LegacyLaneId`. + type OpenBridgeOrigin = EnsureNever; // Converter aligned with `OpenBridgeOrigin`. type BridgeOriginAccountIdConverter = (ParentIsPreset, SiblingParachainConvertsVia); @@ -188,14 +190,20 @@ impl pallet_xcm_bridge_hub::Config for Runtime { } #[cfg(feature = "runtime-benchmarks")] -pub(crate) fn open_bridge_for_benchmarks( - with: bp_messages::LaneId, +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, sibling_para_id: u32, -) -> InteriorLocation { +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; use sp_runtime::traits::Zero; use xcm::VersionedInteriorLocation; - use xcm_executor::traits::ConvertLocation; // insert bridge metadata let lane_id = with; @@ -205,7 +213,7 @@ pub(crate) fn open_bridge_for_benchmarks( let bridge_id = BridgeId::new(&universal_source, &universal_destination); // insert only bridge metadata, because the benchmarks create lanes - pallet_xcm_bridge_hub::Bridges::::insert( + pallet_xcm_bridge_hub::Bridges::::insert( bridge_id, Bridge { bridge_origin_relative_location: alloc::boxed::Box::new( @@ -218,17 +226,12 @@ pub(crate) fn open_bridge_for_benchmarks( VersionedInteriorLocation::from(universal_destination), ), state: BridgeState::Opened, - bridge_owner_account: crate::xcm_config::LocationToAccountId::convert_location( - &sibling_parachain, - ) - .expect("valid AccountId"), - deposit: Balance::zero(), + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), lane_id, }, ); - pallet_xcm_bridge_hub::LaneToBridge::::insert( - lane_id, bridge_id, - ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); universal_source } @@ -327,12 +330,11 @@ mod tests { /// Contains the migration for the AssetHubWestend<>AssetHubRococo bridge. pub mod migration { use super::*; - use bp_messages::LaneId; + use bp_messages::LegacyLaneId; use frame_support::traits::ConstBool; - use sp_runtime::Either; parameter_types! { - pub AssetHubWestendToAssetHubRococoMessagesLane: LaneId = LaneId::from_inner(Either::Right([0, 0, 0, 2])); + pub AssetHubWestendToAssetHubRococoMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]); pub AssetHubWestendLocation: Location = Location::new(1, [Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)]); pub AssetHubRococoUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)].into(); } @@ -348,4 +350,75 @@ pub mod migration { AssetHubWestendLocation, AssetHubRococoUniversalLocation, >; + + mod v1_wrong { + use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer}; + use bp_runtime::AccountIdOf; + use codec::{Decode, Encode}; + use pallet_bridge_messages::BridgedChainOf; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct StoredInboundLaneData, I: 'static>( + pub(crate) InboundLaneData>>, + ); + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct InboundLaneData { + pub state: LaneState, + pub(crate) relayers: VecDeque>, + pub(crate) last_confirmed_nonce: MessageNonce, + } + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct OutboundLaneData { + pub state: LaneState, + pub(crate) oldest_unpruned_nonce: MessageNonce, + pub(crate) latest_received_nonce: MessageNonce, + pub(crate) latest_generated_nonce: MessageNonce, + } + } + + mod v1 { + pub use bp_messages::{InboundLaneData, LaneState, OutboundLaneData}; + pub use pallet_bridge_messages::{InboundLanes, OutboundLanes, StoredInboundLaneData}; + } + + /// Fix for v1 migration - corrects data for OutboundLaneData/InboundLaneData (it is needed only + /// for Rococo/Westend). + pub struct FixMessagesV1Migration(sp_std::marker::PhantomData<(T, I)>); + + impl, I: 'static> frame_support::traits::OnRuntimeUpgrade + for FixMessagesV1Migration + { + fn on_runtime_upgrade() -> Weight { + use sp_core::Get; + let mut weight = T::DbWeight::get().reads(1); + + // `InboundLanes` - add state to the old structs + let translate_inbound = + |pre: v1_wrong::StoredInboundLaneData| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::StoredInboundLaneData(v1::InboundLaneData { + state: v1::LaneState::Opened, + relayers: pre.0.relayers, + last_confirmed_nonce: pre.0.last_confirmed_nonce, + })) + }; + v1::InboundLanes::::translate_values(translate_inbound); + + // `OutboundLanes` - add state to the old structs + let translate_outbound = + |pre: v1_wrong::OutboundLaneData| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::OutboundLaneData { + state: v1::LaneState::Opened, + oldest_unpruned_nonce: pre.oldest_unpruned_nonce, + latest_received_nonce: pre.latest_received_nonce, + latest_generated_nonce: pre.latest_generated_nonce, + }) + }; + v1::OutboundLanes::::translate_values(translate_outbound); + + weight + } + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs index 4c948656d9f8..0b270e584339 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs @@ -31,6 +31,7 @@ fn bridge_hub_westend_genesis( id: ParaId, bridges_pallet_owner: Option, asset_hub_para_id: ParaId, + opened_bridges: Vec<(Location, InteriorLocation, Option)>, ) -> serde_json::Value { let config = RuntimeGenesisConfig { balances: BalancesConfig { @@ -71,6 +72,10 @@ fn bridge_hub_westend_genesis( owner: bridges_pallet_owner.clone(), ..Default::default() }, + xcm_over_bridge_hub_rococo: XcmOverBridgeHubRococoConfig { + opened_bridges, + ..Default::default() + }, ethereum_system: EthereumSystemConfig { para_id: id, asset_hub_para_id, @@ -114,6 +119,11 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option("Bob")), westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![( + Location::new(1, [Parachain(1000)]), + Junctions::from([Rococo.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + )], ), Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => bridge_hub_westend_genesis( // initial collators. @@ -144,6 +154,7 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option("Bob")), westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![], ), _ => return None, }; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 5c40506442df..03b69a218020 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -82,6 +82,7 @@ use xcm_runtime_apis::{ }; use bp_runtime::HeaderId; +use pallet_bridge_messages::LaneIdOf; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -147,12 +148,17 @@ pub type Migrations = ( Runtime, bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, >, + bridge_to_rococo_config::migration::FixMessagesV1Migration< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >, bridge_to_rococo_config::migration::StaticToDynamicLanes, frame_support::migrations::RemoveStorage< BridgeRococoMessagesPalletName, OutboundLanesCongestedSignalsKey, RocksDbWeight, >, + pallet_bridge_relayers::migration::v1::MigrationToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, snowbridge_pallet_system::migration::v0::InitializeOnUpgrade< @@ -220,7 +226,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, + transaction_version: 6, system_version: 1, }; @@ -851,7 +857,7 @@ impl_runtime_apis! { impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< @@ -863,7 +869,7 @@ impl_runtime_apis! { impl bp_bridge_hub_rococo::ToBridgeHubRococoOutboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> Vec { @@ -1141,15 +1147,20 @@ impl_runtime_apis! { ); // open bridge - let origin = RuntimeOrigin::from(pallet_xcm::Origin::Xcm(sibling_parachain_location.clone())); - XcmOverBridgeHubRococo::open_bridge( - origin.clone(), - alloc::boxed::Box::new(VersionedInteriorLocation::from([GlobalConsensus(NetworkId::Rococo), Parachain(8765)])), + let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Rococo), Parachain(8765)].into(); + let locations = XcmOverBridgeHubRococo::bridge_locations( + sibling_parachain_location.clone(), + bridge_destination_universal_location.clone(), + )?; + XcmOverBridgeHubRococo::do_open_bridge( + locations, + bp_messages::LegacyLaneId([1, 2, 3, 4]), + true, ).map_err(|e| { log::error!( "Failed to `XcmOverBridgeHubRococo::open_bridge`({:?}, {:?})`, error: {:?}", - origin, - [GlobalConsensus(NetworkId::Rococo), Parachain(8765)], + sibling_parachain_location, + bridge_destination_universal_location, e ); BenchmarkError::Stop("Bridge was not opened!") @@ -1203,12 +1214,16 @@ impl_runtime_apis! { } fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { + params: MessageProofParams>, + ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); - let universal_source = bridge_to_rococo_config::open_bridge_for_benchmarks(params.lane, 42); + let universal_source = bridge_to_rococo_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, @@ -1217,9 +1232,13 @@ impl_runtime_apis! { } fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { - let _ = bridge_to_rococo_config::open_bridge_for_benchmarks(params.lane, 42); + params: MessageDeliveryProofParams>, + ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { + let _ = bridge_to_rococo_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, @@ -1264,14 +1283,15 @@ impl_runtime_apis! { } } - impl BridgeRelayersConfig for Runtime { + impl BridgeRelayersConfig for Runtime { fn prepare_rewards_account( - account_params: bp_relayers::RewardsAccountParams, + account_params: bp_relayers::RewardsAccountParams<>::LaneId>, reward: Balance, ) { let rewards_account = bp_relayers::PayRewardFromAccount::< Balances, - AccountId + AccountId, + >::LaneId, >::rewards_account(account_params); Self::deposit_account(rewards_account, reward); } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 4391b069cf09..d168d1b7a13c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -16,8 +16,12 @@ #![cfg(test)] +use bp_messages::LegacyLaneId; use bp_polkadot_core::Signature; -use bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlash}; +use bridge_common_config::{ + DeliveryRewardInBalance, RelayersForLegacyLaneIdsMessagesInstance, + RequiredStakeForStakeAndSlash, +}; use bridge_hub_test_utils::{test_cases::from_parachain, SlotDurations}; use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, @@ -63,6 +67,7 @@ type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, WithBridgeHubRococoMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, >; parameter_types! { @@ -235,7 +240,15 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { XcmOverBridgeHubRococoInstance, LocationToAccountId, WestendLocation, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()).1 + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, XcmOverBridgeHubRococoInstance + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + } + ).1 }, ) } @@ -288,10 +301,20 @@ fn relayed_incoming_message_works() { XcmOverBridgeHubRococoInstance, LocationToAccountId, WestendLocation, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubRococoInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) .1 }, construct_and_apply_extrinsic, + true, ) } @@ -312,10 +335,20 @@ fn free_relay_extrinsic_works() { XcmOverBridgeHubRococoInstance, LocationToAccountId, WestendLocation, - >(SiblingParachainLocation::get(), BridgedUniversalLocation::get()) + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubRococoInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) .1 }, construct_and_apply_extrinsic, + true, ) } @@ -377,22 +410,3 @@ pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { ), ) } - -#[test] -fn open_and_close_bridge_works() { - let origins = [SiblingParachainLocation::get(), SiblingSystemParachainLocation::get()]; - - for origin in origins { - bridge_hub_test_utils::test_cases::open_and_close_bridge_works::< - Runtime, - XcmOverBridgeHubRococoInstance, - LocationToAccountId, - WestendLocation, - >( - collator_session_keys(), - bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - origin, - BridgedUniversalLocation::get(), - ) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 8c048a0d2dbd..915b3090092f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -37,6 +37,7 @@ parachains-runtimes-test-utils = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +pallet-xcm = { workspace = true } # Bridges bp-header-chain = { workspace = true } @@ -81,6 +82,7 @@ std = [ "pallet-timestamp/std", "pallet-utility/std", "pallet-xcm-bridge-hub/std", + "pallet-xcm/std", "parachains-common/std", "parachains-runtimes-test-utils/std", "sp-core/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs index b8d6d87051c7..bc28df0eb829 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs @@ -24,7 +24,9 @@ extern crate alloc; pub use bp_test_utils::test_header; pub use parachains_runtimes_test_utils::*; use sp_runtime::Perbill; -pub use test_cases::helpers::ensure_opened_bridge; +pub use test_cases::helpers::{ + ensure_opened_bridge, open_bridge_with_extrinsic, open_bridge_with_storage, +}; /// A helper function for comparing the actual value of a fee constant with its estimated value. The /// estimated value can be overestimated (`overestimate_in_percent`), and if the difference to the diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs index 72743eaa41db..320f3030b60a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs @@ -24,12 +24,12 @@ use crate::{ use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; -use bp_messages::{LaneId, UnrewardedRelayersState}; +use bp_messages::UnrewardedRelayersState; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; +use pallet_bridge_messages::{BridgedChainOf, LaneIdOf, ThisChainOf}; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; @@ -50,7 +50,7 @@ pub trait WithRemoteGrandpaChainHelper { Self::MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config; + > + pallet_bridge_relayers::Config>; /// All pallets of this chain, excluding system pallet. type AllPalletsWithoutSystem: OnInitialize> + OnFinalize>; @@ -58,15 +58,18 @@ pub trait WithRemoteGrandpaChainHelper { type GPI: 'static; /// Instance of the `pallet-bridge-messages`, used to bridge with remote GRANDPA chain. type MPI: 'static; + /// Instance of the `pallet-bridge-relayers`, used to collect rewards from messages `MPI` + /// instance. + type RPI: 'static; } /// Adapter struct that implements [`WithRemoteGrandpaChainHelper`]. -pub struct WithRemoteGrandpaChainHelperAdapter( - core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI)>, +pub struct WithRemoteGrandpaChainHelperAdapter( + core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI, RPI)>, ); -impl WithRemoteGrandpaChainHelper - for WithRemoteGrandpaChainHelperAdapter +impl WithRemoteGrandpaChainHelper + for WithRemoteGrandpaChainHelperAdapter where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -75,16 +78,18 @@ where MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config, + > + pallet_bridge_relayers::Config>, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, GPI: 'static, MPI: 'static, + RPI: 'static, { type Runtime = Runtime; type AllPalletsWithoutSystem = AllPalletsWithoutSystem; type GPI = GPI; type MPI = MPI; + type RPI = RPI; } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -96,11 +101,12 @@ pub fn relayed_incoming_message_works( runtime_para_id: u32, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteGrandpaChainHelper, AccountIdOf: From, @@ -140,6 +146,7 @@ pub fn relayed_incoming_message_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, + LaneIdOf, >( lane_id, xcm.into(), @@ -172,14 +179,18 @@ pub fn relayed_incoming_message_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -197,11 +208,12 @@ pub fn free_relay_extrinsic_works( runtime_para_id: u32, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteGrandpaChainHelper, RuntimeHelper::Runtime: pallet_balances::Config, @@ -263,6 +275,7 @@ pub fn free_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, + LaneIdOf, >( lane_id, xcm.into(), @@ -301,14 +314,18 @@ pub fn free_relay_extrinsic_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -325,7 +342,7 @@ pub fn complex_relay_extrinsic_works( runtime_para_id: u32, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, @@ -372,6 +389,7 @@ pub fn complex_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, + LaneIdOf, >( lane_id, xcm.into(), @@ -382,9 +400,10 @@ pub fn complex_relay_extrinsic_works( ); let relay_chain_header_hash = relay_chain_header.hash(); - vec![( - pallet_utility::Call::::batch_all { - calls: vec![ + vec![ + ( + pallet_utility::Call::::batch_all { + calls: vec![ BridgeGrandpaCall::::submit_finality_proof { finality_target: Box::new(relay_chain_header), justification: grandpa_justification, @@ -396,27 +415,33 @@ pub fn complex_relay_extrinsic_works( dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), ], - } - .into(), - Box::new(( - helpers::VerifySubmitGrandpaFinalityProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::GPI, - >::expect_best_header_hash(relay_chain_header_hash), - helpers::VerifySubmitMessagesProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::MPI, - >::expect_last_delivered_nonce(lane_id, 1), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, + } + .into(), + Box::new( + ( + helpers::VerifySubmitGrandpaFinalityProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::GPI, + >::expect_best_header_hash(relay_chain_header_hash), + helpers::VerifySubmitMessagesProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::MPI, + >::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::< + RuntimeHelper::Runtime, + RuntimeHelper::RPI, + >::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), ), ), - )), - )] + ), + ] }, ); } @@ -446,8 +471,9 @@ where test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -502,8 +528,9 @@ where BridgedChainOf, ThisChainOf, (), + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), 1u32.into(), AccountId32::from(Alice.public()).into(), unrewarded_relayers.clone(), @@ -550,8 +577,9 @@ where test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -602,8 +630,9 @@ where BridgedChainOf, ThisChainOf, (), + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), 1u32.into(), AccountId32::from(Alice.public()).into(), unrewarded_relayers.clone(), diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs index 82edcacdcab5..1da901e0bcdf 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs @@ -24,14 +24,14 @@ use crate::{ use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; -use bp_messages::{LaneId, UnrewardedRelayersState}; +use bp_messages::UnrewardedRelayersState; use bp_polkadot_core::parachains::ParaHash; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::{Chain, Parachain}; use bp_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; +use pallet_bridge_messages::{BridgedChainOf, LaneIdOf, ThisChainOf}; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; @@ -53,7 +53,7 @@ pub trait WithRemoteParachainHelper { Self::MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config; + > + pallet_bridge_relayers::Config>; /// All pallets of this chain, excluding system pallet. type AllPalletsWithoutSystem: OnInitialize> + OnFinalize>; @@ -63,15 +63,18 @@ pub trait WithRemoteParachainHelper { type PPI: 'static; /// Instance of the `pallet-bridge-messages`, used to bridge with remote parachain. type MPI: 'static; + /// Instance of the `pallet-bridge-relayers`, used to collect rewards from messages `MPI` + /// instance. + type RPI: 'static; } /// Adapter struct that implements `WithRemoteParachainHelper`. -pub struct WithRemoteParachainHelperAdapter( - core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, PPI, MPI)>, +pub struct WithRemoteParachainHelperAdapter( + core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, PPI, MPI, RPI)>, ); -impl WithRemoteParachainHelper - for WithRemoteParachainHelperAdapter +impl WithRemoteParachainHelper + for WithRemoteParachainHelperAdapter where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -81,19 +84,20 @@ where MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config, + > + pallet_bridge_relayers::Config>, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, GPI: 'static, PPI: 'static, MPI: 'static, - // MB: MessageBridge, + RPI: 'static, { type Runtime = Runtime; type AllPalletsWithoutSystem = AllPalletsWithoutSystem; type GPI = GPI; type PPI = PPI; type MPI = MPI; + type RPI = RPI; } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -106,11 +110,12 @@ pub fn relayed_incoming_message_works( bridged_para_id: u32, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteParachainHelper, AccountIdOf: From, @@ -161,6 +166,7 @@ pub fn relayed_incoming_message_works( >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf, >( lane_id, xcm.into(), @@ -208,14 +214,18 @@ pub fn relayed_incoming_message_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -234,11 +244,12 @@ pub fn free_relay_extrinsic_works( bridged_para_id: u32, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteParachainHelper, RuntimeHelper::Runtime: pallet_balances::Config, @@ -312,6 +323,7 @@ pub fn free_relay_extrinsic_works( >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf, >( lane_id, xcm.into(), @@ -353,10 +365,10 @@ pub fn free_relay_extrinsic_works( bridged_para_id, parachain_head_hash, ), - /*helpers::VerifyRelayerBalance::::expect_relayer_balance( + helpers::VerifyRelayerBalance::::expect_relayer_balance( relayer_id_at_this_chain.clone(), initial_relayer_balance, - ),*/ + ), )), ), ( @@ -371,14 +383,18 @@ pub fn free_relay_extrinsic_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -396,7 +412,7 @@ pub fn complex_relay_extrinsic_works( bridged_para_id: u32, sibling_parachain_id: u32, local_relay_chain_id: NetworkId, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, @@ -454,6 +470,7 @@ pub fn complex_relay_extrinsic_works( >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf, >( lane_id, xcm.into(), @@ -468,9 +485,10 @@ pub fn complex_relay_extrinsic_works( let parachain_head_hash = parachain_head.hash(); let relay_chain_header_hash = relay_chain_header.hash(); let relay_chain_header_number = *relay_chain_header.number(); - vec![( - pallet_utility::Call::::batch_all { - calls: vec![ + vec![ + ( + pallet_utility::Call::::batch_all { + calls: vec![ BridgeGrandpaCall::::submit_finality_proof { finality_target: Box::new(relay_chain_header), justification: grandpa_justification, @@ -487,31 +505,37 @@ pub fn complex_relay_extrinsic_works( dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), ], - } - .into(), - Box::new(( - helpers::VerifySubmitGrandpaFinalityProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::GPI, - >::expect_best_header_hash(relay_chain_header_hash), - helpers::VerifySubmitParachainHeaderProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::PPI, - >::expect_best_header_hash(bridged_para_id, parachain_head_hash), - helpers::VerifySubmitMessagesProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::MPI, - >::expect_last_delivered_nonce(lane_id, 1), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, + } + .into(), + Box::new( + ( + helpers::VerifySubmitGrandpaFinalityProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::GPI, + >::expect_best_header_hash(relay_chain_header_hash), + helpers::VerifySubmitParachainHeaderProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::PPI, + >::expect_best_header_hash(bridged_para_id, parachain_head_hash), + helpers::VerifySubmitMessagesProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::MPI, + >::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::< + RuntimeHelper::Runtime, + RuntimeHelper::RPI, + >::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), ), ), - )), - )] + ), + ] }, ); } @@ -551,8 +575,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf >( - LaneId::new(1, 2), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -621,8 +646,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), 1, 5, 1_000, @@ -683,8 +709,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -738,8 +765,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, + LaneIdOf, >( - LaneId::new(1, 2), + LaneIdOf::::default(), 1, 5, 1_000, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs index c343e9b3e09a..aac60bba0b53 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -19,7 +19,7 @@ use crate::test_cases::{bridges_prelude::*, run_test, RuntimeHelper}; use asset_test_utils::BasicParachainRuntime; -use bp_messages::{LaneId, MessageNonce}; +use bp_messages::MessageNonce; use bp_polkadot_core::parachains::{ParaHash, ParaId}; use bp_relayers::RewardsAccountParams; use bp_runtime::Chain; @@ -33,7 +33,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader}; -use pallet_bridge_messages::BridgedChainOf; +use pallet_bridge_messages::{BridgedChainOf, LaneIdOf}; use parachains_common::AccountId; use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, CollatorSessionKeys, RuntimeCallOf, SlotDurations, @@ -132,8 +132,8 @@ where } /// Checks that the latest delivered nonce in the bridge messages pallet equals to given one. -pub struct VerifySubmitMessagesProofOutcome { - lane: LaneId, +pub struct VerifySubmitMessagesProofOutcome, MPI: 'static> { + lane: LaneIdOf, expected_nonce: MessageNonce, _marker: PhantomData<(Runtime, MPI)>, } @@ -145,7 +145,7 @@ where { /// Expect given delivered nonce to be the latest after transaction. pub fn expect_last_delivered_nonce( - lane: LaneId, + lane: LaneIdOf, expected_nonce: MessageNonce, ) -> Box { Box::new(Self { lane, expected_nonce, _marker: PhantomData }) @@ -167,30 +167,32 @@ where } /// Verifies that relayer is rewarded at this chain. -pub struct VerifyRelayerRewarded { +pub struct VerifyRelayerRewarded, RPI: 'static> { relayer: Runtime::AccountId, - reward_params: RewardsAccountParams, + reward_params: RewardsAccountParams, } -impl VerifyRelayerRewarded +impl VerifyRelayerRewarded where - Runtime: pallet_bridge_relayers::Config, + Runtime: pallet_bridge_relayers::Config, + RPI: 'static, { /// Expect given delivered nonce to be the latest after transaction. pub fn expect_relayer_reward( relayer: Runtime::AccountId, - reward_params: RewardsAccountParams, + reward_params: RewardsAccountParams, ) -> Box { Box::new(Self { relayer, reward_params }) } } -impl VerifyTransactionOutcome for VerifyRelayerRewarded +impl VerifyTransactionOutcome for VerifyRelayerRewarded where - Runtime: pallet_bridge_relayers::Config, + Runtime: pallet_bridge_relayers::Config, + RPI: 'static, { fn verify_outcome(&self) { - assert!(pallet_bridge_relayers::RelayerRewards::::get( + assert!(pallet_bridge_relayers::RelayerRewards::::get( &self.relayer, &self.reward_params, ) @@ -388,7 +390,12 @@ fn execute_and_verify_calls( /// Helper function to open the bridge/lane for `source` and `destination` while ensuring all /// required balances are placed into the SA of the source. -pub fn ensure_opened_bridge(source: Location, destination: InteriorLocation) -> (BridgeLocations, LaneId) +pub fn ensure_opened_bridge< + Runtime, + XcmOverBridgePalletInstance, + LocationToAccountId, + TokenLocation> +(source: Location, destination: InteriorLocation, bridge_opener: impl Fn(BridgeLocations, Asset)) -> (BridgeLocations, pallet_xcm_bridge_hub::LaneIdOf) where Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, XcmOverBridgePalletInstance: 'static, @@ -425,34 +432,74 @@ TokenLocation: Get{ let _ = >::mint_into(&source_account_id, balance_needed) .expect("mint_into passes"); + // call the bridge opener + bridge_opener(*locations.clone(), buy_execution_fee); + + // check opened bridge + let bridge = pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id(), + ) + .expect("opened bridge"); + + // check state + assert_ok!( + pallet_xcm_bridge_hub::Pallet::::do_try_state() + ); + + // return locations + (*locations, bridge.lane_id) +} + +/// Utility for opening bridge with dedicated `pallet_xcm_bridge_hub`'s extrinsic. +pub fn open_bridge_with_extrinsic( + locations: BridgeLocations, + buy_execution_fee: Asset, +) where + Runtime: frame_system::Config + + pallet_xcm_bridge_hub::Config + + cumulus_pallet_parachain_system::Config + + pallet_xcm::Config, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: + GetDispatchInfo + From>, +{ // open bridge with `Transact` call let open_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< Runtime, XcmOverBridgePalletInstance, >::open_bridge { - bridge_destination_universal_location: Box::new(destination.into()), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), }); // execute XCM as source origin would do with `Transact -> Origin::Xcm` assert_ok!(RuntimeHelper::::execute_as_origin_xcm( + locations.bridge_origin_relative_location().clone(), open_bridge_call, - source.clone(), buy_execution_fee ) .ensure_complete()); +} - let bridge = pallet_xcm_bridge_hub::Bridges::::get( - locations.bridge_id(), - ) - .expect("opened bridge"); - - // check state +/// Utility for opening bridge directly inserting data to the storage (used only for legacy +/// purposes). +pub fn open_bridge_with_storage( + locations: BridgeLocations, + _buy_execution_fee: Asset, + lane_id: pallet_xcm_bridge_hub::LaneIdOf, +) where + Runtime: pallet_xcm_bridge_hub::Config, + XcmOverBridgePalletInstance: 'static, +{ + // insert bridge data directly to the storage assert_ok!( - pallet_xcm_bridge_hub::Pallet::::do_try_state() + pallet_xcm_bridge_hub::Pallet::::do_open_bridge( + Box::new(locations), + lane_id, + true + ) ); - - // return locations - (*locations, bridge.lane_id) } /// Helper function to close the bridge/lane for `source` and `destination`. @@ -504,8 +551,8 @@ TokenLocation: Get{ // execute XCM as source origin would do with `Transact -> Origin::Xcm` assert_ok!(RuntimeHelper::::execute_as_origin_xcm( - close_bridge_call, source.clone(), + close_bridge_call, buy_execution_fee ) .ensure_complete()); diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index de117982b26f..9c5d6269dc0e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -29,7 +29,7 @@ use crate::{test_cases::bridges_prelude::*, test_data}; use asset_test_utils::BasicParachainRuntime; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - LaneId, LaneState, MessageKey, MessagesOperatingMode, OutboundLaneData, + LaneState, MessageKey, MessagesOperatingMode, OutboundLaneData, }; use bp_runtime::BasicOperatingMode; use bp_xcm_bridge_hub::{Bridge, BridgeState, XcmAsPlainPayload}; @@ -71,11 +71,13 @@ pub(crate) mod bridges_prelude { // Re-export test_case from assets pub use asset_test_utils::include_teleports_for_native_asset_works; +use pallet_bridge_messages::LaneIdOf; pub type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; // Re-export test_case from `parachains-runtimes-test-utils` +use crate::test_cases::helpers::open_bridge_with_extrinsic; pub use parachains_runtimes_test_utils::test_cases::{ change_storage_constant_by_governance_works, set_storage_keys_by_governance_works, }; @@ -326,7 +328,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< export_message_instruction: fn() -> Instruction, existential_deposit: Option, maybe_paid_export_message: Option, - prepare_configuration: impl Fn() -> LaneId, + prepare_configuration: impl Fn() -> LaneIdOf, ) where Runtime: BasicParachainRuntime + BridgeMessagesConfig, XcmConfig: xcm_executor::Config, @@ -469,7 +471,7 @@ pub fn message_dispatch_routing_works< run_test::(collator_session_key, runtime_para_id, vec![], || { prepare_configuration(); - let dummy_lane_id = LaneId::new(1, 2); + let dummy_lane_id = LaneIdOf::::default(); let mut alice = [0u8; 32]; alice[0] = 1; @@ -504,11 +506,12 @@ pub fn message_dispatch_routing_works< // 2. this message is sent from other global consensus with destination of this Runtime // sibling parachain (HRMP) - let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::< - BridgedNetwork, - NetworkWithParentCount, - AlwaysLatest, - >((RuntimeNetwork::get(), [Parachain(sibling_parachain_id)].into())); + let bridging_message = + test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >((RuntimeNetwork::get(), [Parachain(sibling_parachain_id)].into())); // 2.1. WITHOUT opened hrmp channel -> RoutingError let result = @@ -714,7 +717,11 @@ pub fn open_and_close_bridge_works(source.clone(), destination.clone()) + >( + source.clone(), + destination.clone(), + open_bridge_with_extrinsic:: + ) .0 .bridge_id(), locations.bridge_id() diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs index 2940c4e00f42..7461085330f2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs @@ -20,8 +20,8 @@ use crate::test_data::prepare_inbound_xcm; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, LaneState, - MessageNonce, UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneState, MessageNonce, + UnrewardedRelayersState, }; use bp_runtime::{AccountIdOf, BlockNumberOf, Chain, HeaderOf, UnverifiedStorageProofParams}; use bp_test_utils::make_default_justification; @@ -40,7 +40,7 @@ use pallet_bridge_messages::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, - BridgedChainOf, + BridgedChainOf, LaneIdOf, }; use sp_runtime::DigestItem; @@ -48,7 +48,10 @@ use sp_runtime::DigestItem; pub fn make_complex_relayer_delivery_batch( bridged_header: BridgedHeader, bridged_justification: GrandpaJustification>, - message_proof: FromBridgedChainMessagesProof>>, + message_proof: FromBridgedChainMessagesProof< + HashOf>, + LaneIdOf, + >, relayer_id_at_bridged_chain: InboundRelayerId, ) -> pallet_utility::Call where @@ -82,6 +85,7 @@ pub fn make_complex_relayer_confirmation_batch( bridged_justification: GrandpaJustification>, message_delivery_proof: FromBridgedChainMessagesDeliveryProof< HashOf>, + LaneIdOf, >, relayers_state: UnrewardedRelayersState, ) -> pallet_utility::Call @@ -111,7 +115,10 @@ where /// Prepare a call with message proof. pub fn make_standalone_relayer_delivery_call( - message_proof: FromBridgedChainMessagesProof>>, + message_proof: FromBridgedChainMessagesProof< + HashOf>, + LaneIdOf, + >, relayer_id_at_bridged_chain: InboundRelayerId, ) -> Runtime::RuntimeCall where @@ -134,6 +141,7 @@ where pub fn make_standalone_relayer_confirmation_call( message_delivery_proof: FromBridgedChainMessagesDeliveryProof< HashOf>, + LaneIdOf, >, relayers_state: UnrewardedRelayersState, ) -> Runtime::RuntimeCall @@ -152,7 +160,7 @@ where } /// Prepare storage proofs of messages, stored at the (bridged) source GRANDPA chain. -pub fn make_complex_relayer_delivery_proofs( +pub fn make_complex_relayer_delivery_proofs( lane_id: LaneId, xcm_message: Xcm<()>, message_nonce: MessageNonce, @@ -162,17 +170,18 @@ pub fn make_complex_relayer_delivery_proofs ) -> ( HeaderOf, GrandpaJustification>, - FromBridgedChainMessagesProof>, + FromBridgedChainMessagesProof, LaneId>, ) where BridgedChain: ChainWithGrandpa, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare message let message_payload = prepare_inbound_xcm(xcm_message, message_destination); // prepare storage proof containing message let (state_root, storage_proof) = - prepare_messages_storage_proof::( + prepare_messages_storage_proof::( lane_id, message_nonce..=message_nonce, None, @@ -206,6 +215,7 @@ pub fn make_complex_relayer_confirmation_proofs< BridgedChain, ThisChainWithMessages, InnerXcmRuntimeCall, + LaneId, >( lane_id: LaneId, header_number: BlockNumberOf, @@ -214,15 +224,16 @@ pub fn make_complex_relayer_confirmation_proofs< ) -> ( HeaderOf, GrandpaJustification>, - FromBridgedChainMessagesDeliveryProof>, + FromBridgedChainMessagesDeliveryProof, LaneId>, ) where BridgedChain: ChainWithGrandpa, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare storage proof containing message delivery proof let (state_root, storage_proof) = - prepare_message_delivery_storage_proof::( + prepare_message_delivery_storage_proof::( lane_id, InboundLaneData { state: LaneState::Opened, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs index aefbc0dbd0a7..a6659b8241df 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs @@ -20,7 +20,7 @@ use super::{from_grandpa_chain::make_complex_bridged_grandpa_header_proof, prepa use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, LaneState, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneState, UnrewardedRelayersState, Weight, }; use bp_parachains::{RelayBlockHash, RelayBlockNumber}; @@ -43,7 +43,7 @@ use pallet_bridge_messages::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, - BridgedChainOf, + BridgedChainOf, LaneIdOf, }; use sp_runtime::SaturatedConversion; @@ -53,7 +53,7 @@ pub fn make_complex_relayer_delivery_batch( grandpa_justification: GrandpaJustification>, parachain_heads: Vec<(ParaId, ParaHash)>, para_heads_proof: ParaHeadsProof, - message_proof: FromBridgedChainMessagesProof, + message_proof: FromBridgedChainMessagesProof>, relayer_id_at_bridged_chain: InboundRelayerId, ) -> pallet_utility::Call where @@ -106,7 +106,7 @@ pub fn make_complex_relayer_confirmation_batch( grandpa_justification: GrandpaJustification>, parachain_heads: Vec<(ParaId, ParaHash)>, para_heads_proof: ParaHeadsProof, - message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof>, relayers_state: UnrewardedRelayersState, ) -> pallet_utility::Call where @@ -154,7 +154,7 @@ where /// Prepare a call with message proof. pub fn make_standalone_relayer_delivery_call( - message_proof: FromBridgedChainMessagesProof, + message_proof: FromBridgedChainMessagesProof>, relayer_id_at_bridged_chain: InboundRelayerId, ) -> Runtime::RuntimeCall where @@ -174,7 +174,7 @@ where /// Prepare a call with message delivery proof. pub fn make_standalone_relayer_confirmation_call( - message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof>, relayers_state: UnrewardedRelayersState, ) -> Runtime::RuntimeCall where @@ -195,6 +195,7 @@ pub fn make_complex_relayer_delivery_proofs< BridgedRelayChain, BridgedParachain, ThisChainWithMessages, + LaneId, >( lane_id: LaneId, xcm_message: Xcm<()>, @@ -210,19 +211,20 @@ pub fn make_complex_relayer_delivery_proofs< ParaHead, Vec<(ParaId, ParaHash)>, ParaHeadsProof, - FromBridgedChainMessagesProof, + FromBridgedChainMessagesProof, ) where BridgedRelayChain: bp_runtime::Chain + ChainWithGrandpa, BridgedParachain: bp_runtime::Chain + Parachain, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare message let message_payload = prepare_inbound_xcm(xcm_message, message_destination); // prepare para storage proof containing message let (para_state_root, para_storage_proof) = - prepare_messages_storage_proof::( + prepare_messages_storage_proof::( lane_id, message_nonce..=message_nonce, None, @@ -266,6 +268,7 @@ pub fn make_complex_relayer_confirmation_proofs< BridgedRelayChain, BridgedParachain, ThisChainWithMessages, + LaneId, >( lane_id: LaneId, para_header_number: u32, @@ -279,17 +282,18 @@ pub fn make_complex_relayer_confirmation_proofs< ParaHead, Vec<(ParaId, ParaHash)>, ParaHeadsProof, - FromBridgedChainMessagesDeliveryProof, + FromBridgedChainMessagesDeliveryProof, ) where BridgedRelayChain: bp_runtime::Chain + ChainWithGrandpa, BridgedParachain: bp_runtime::Chain + Parachain, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare para storage proof containing message delivery proof let (para_state_root, para_storage_proof) = - prepare_message_delivery_storage_proof::( + prepare_message_delivery_storage_proof::( lane_id, InboundLaneData { state: LaneState::Opened, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs index 106eacd799ca..c34188af5068 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs @@ -21,7 +21,7 @@ pub mod from_parachain; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData}, - LaneId, MessageKey, + MessageKey, }; use codec::Encode; use frame_support::traits::Get; @@ -65,11 +65,11 @@ pub(crate) fn dummy_xcm() -> Xcm<()> { vec![Trap(42)].into() } -pub(crate) fn dispatch_message( +pub(crate) fn dispatch_message( lane_id: LaneId, nonce: MessageNonce, payload: Vec, -) -> DispatchMessage> { +) -> DispatchMessage, LaneId> { DispatchMessage { key: MessageKey { lane_id, nonce }, data: DispatchMessageData { payload: Ok(payload) }, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 7174595f12a3..a60d3ed66ac6 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives-westend"), impl_name: create_runtime_str!("collectives-westend"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 5f03b6ab7e2c..853c8b48dc88 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -144,7 +144,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 7, diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index be332f67c9e6..74569af9ec7a 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -149,7 +149,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-rococo"), impl_name: create_runtime_str!("coretime-rococo"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index cc43c95f005c..5e37faf61819 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -148,7 +148,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("coretime-westend"), impl_name: create_runtime_str!("coretime-westend"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 1b213785cf90..bc76f174b507 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -102,7 +102,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton-westend"), impl_name: create_runtime_str!("glutton-westend"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 150152964b90..bfd31e2b484e 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -111,6 +111,7 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( pallet_collator_selection::migration::v2::MigrationToV2, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -136,7 +137,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-rococo"), impl_name: create_runtime_str!("people-rococo"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 60b861678c5a..8258ba0564f9 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -136,7 +136,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("people-westend"), impl_name: create_runtime_str!("people-westend"), authoring_version: 1, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index a7c8bc239358..c7e81d67bbab 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -218,11 +218,7 @@ parameter_types! { impl pallet_message_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] + // NOTE: Changes are needed here if you add benchmarking to the runtime. type MessageProcessor = xcm_builder::ProcessXcmMessage< AggregateMessageOrigin, xcm_executor::XcmExecutor, diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index fe75b2b6e72f..3b38eee244f1 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -465,8 +465,8 @@ impl< } pub fn execute_as_origin_xcm( - call: Call, origin: Location, + call: Call, buy_execution_fee: Asset, ) -> Outcome { // prepare `Transact` xcm diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index ad88be60d747..d52bc639b3bc 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -57,6 +57,9 @@ xcm = { workspace = true, default-features = true } # Cumulus cumulus-primitives-core = { workspace = true, default-features = true } +# Bridges +bp-messages = { workspace = true, default-features = true } + [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs index 43fb551f80d2..63562f192aee 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs @@ -39,7 +39,6 @@ use sc_cli::{Result, SubstrateCli}; use sp_runtime::traits::AccountIdConversion; #[cfg(feature = "runtime-benchmarks")] use sp_runtime::traits::HashingFor; -use std::panic::{RefUnwindSafe, UnwindSafe}; /// Structure that can be used in order to provide customizers for different functionalities of the /// node binary that is being built using this library. @@ -55,8 +54,7 @@ pub fn new_aura_node_spec( extra_args: &NodeExtraArgs, ) -> Box where - Block: NodeBlock + UnwindSafe + RefUnwindSafe, - Block::BoundedHeader: UnwindSafe + RefUnwindSafe, + Block: NodeBlock, { match aura_id { AuraConsensusId::Sr25519 => crate::service::new_aura_node_spec::< diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs index 02aa867d70fe..bd4ff167d8f1 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs @@ -24,12 +24,14 @@ use utils::{impl_node_runtime_apis, imports::*}; type CustomBlock = crate::common::types::Block; pub mod aura_sr25519 { use super::*; + #[allow(dead_code)] struct FakeRuntime; impl_node_runtime_apis!(FakeRuntime, CustomBlock, sp_consensus_aura::sr25519::AuthorityId); } pub mod aura_ed25519 { use super::*; + #[allow(dead_code)] struct FakeRuntime; impl_node_runtime_apis!(FakeRuntime, CustomBlock, sp_consensus_aura::ed25519::AuthorityId); } diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index 6bd14d136a62..8530f5b87487 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -385,7 +385,8 @@ impl< FungiblesAssetMatcher, OnUnbalanced, AccountId, - > where + > +where Fungibles::Balance: Into, { fn new() -> Self { @@ -545,7 +546,8 @@ impl< FungiblesAssetMatcher, OnUnbalanced, AccountId, - > where + > +where Fungibles::Balance: Into, { fn drop(&mut self) { diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 6924f11292d6..8598481fae76 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -13,7 +13,6 @@ workspace = true codec = { workspace = true, default-features = true } paste = { workspace = true, default-features = true } log = { workspace = true } -lazy_static = { workspace = true } impl-trait-for-tuples = { workspace = true } array-bytes = { workspace = true } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index d393d4537734..bb2945dc267d 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -18,12 +18,16 @@ extern crate alloc; pub use array_bytes; pub use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -pub use lazy_static::lazy_static; pub use log; pub use paste; pub use std::{ - any::type_name, collections::HashMap, error::Error, fmt, marker::PhantomData, ops::Deref, - sync::Mutex, + any::type_name, + collections::HashMap, + error::Error, + fmt, + marker::PhantomData, + ops::Deref, + sync::{LazyLock, Mutex}, }; // Substrate @@ -443,10 +447,8 @@ macro_rules! __impl_test_ext_for_relay_chain { = $crate::RefCell::new($crate::TestExternalities::new($genesis)); } - $crate::lazy_static! { - pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap>> - = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); - } + pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap>>> + = $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new()))); impl<$network: $crate::Network> $crate::TestExt for $name<$network> { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { @@ -478,10 +480,10 @@ macro_rules! __impl_test_ext_for_relay_chain { v.take() }); - // Get TestExternality from lazy_static + // Get TestExternality from LazyLock let global_ext_guard = $global_ext.lock().unwrap(); - // Replace TestExternality in lazy_static by TestExternality from thread_local + // Replace TestExternality in LazyLock by TestExternality from thread_local global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext); } @@ -490,10 +492,10 @@ macro_rules! __impl_test_ext_for_relay_chain { let mut global_ext_unlocked = false; - // Keep the mutex unlocked until TesExternality from lazy_static + // Keep the mutex unlocked until TesExternality from LazyLock // has been updated while !global_ext_unlocked { - // Get TesExternality from lazy_static + // Get TesExternality from LazyLock let global_ext_result = $global_ext.try_lock(); if let Ok(global_ext_guard) = global_ext_result { @@ -506,10 +508,10 @@ macro_rules! __impl_test_ext_for_relay_chain { } } - // Now that we know that lazy_static TestExt has been updated, we lock its mutex + // Now that we know that TestExt has been updated, we lock its mutex let mut global_ext_guard = $global_ext.lock().unwrap(); - // and set TesExternality from lazy_static into TesExternality for local_thread + // and set TesExternality from LazyLock into TesExternality for local_thread let global_ext = global_ext_guard.deref(); $local_ext.with(|v| { @@ -744,10 +746,8 @@ macro_rules! __impl_test_ext_for_parachain { = $crate::RefCell::new($crate::TestExternalities::new($genesis)); } - $crate::lazy_static! { - pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap>> - = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); - } + pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap>>> + = $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new()))); impl<$network: $crate::Network> $crate::TestExt for $name<$network> { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { @@ -777,10 +777,10 @@ macro_rules! __impl_test_ext_for_parachain { v.take() }); - // Get TestExternality from lazy_static + // Get TestExternality from LazyLock let global_ext_guard = $global_ext.lock().unwrap(); - // Replace TestExternality in lazy_static by TestExternality from thread_local + // Replace TestExternality in LazyLock by TestExternality from thread_local global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext); } @@ -789,10 +789,10 @@ macro_rules! __impl_test_ext_for_parachain { let mut global_ext_unlocked = false; - // Keep the mutex unlocked until TesExternality from lazy_static + // Keep the mutex unlocked until TesExternality from LazyLock // has been updated while !global_ext_unlocked { - // Get TesExternality from lazy_static + // Get TesExternality from LazyLock let global_ext_result = $global_ext.try_lock(); if let Ok(global_ext_guard) = global_ext_result { @@ -805,10 +805,10 @@ macro_rules! __impl_test_ext_for_parachain { } } - // Now that we know that lazy_static TestExt has been updated, we lock its mutex + // Now that we know that TestExt has been updated, we lock its mutex let mut global_ext_guard = $global_ext.lock().unwrap(); - // and set TesExternality from lazy_static into TesExternality for local_thread + // and set TesExternality from LazyLock into TesExternality for local_thread let global_ext = global_ext_guard.deref(); $local_ext.with(|v| { diff --git a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile index 55b9156e6a0a..2198da13a4b7 100644 --- a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile +++ b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile @@ -1,7 +1,7 @@ # this image is built on top of existing Zombienet image ARG ZOMBIENET_IMAGE # this image uses substrate-relay image built elsewhere -ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.6.8 +ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.6.10 # metadata ARG VCS_REF diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 3e5a6ccdd3c2..1445ade08e20 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -151,6 +151,13 @@ pub struct RunCmd { /// TESTING ONLY: disable the version check between nodes and workers. #[arg(long, hide = true)] pub disable_worker_version_check: bool, + + /// Enable approval-voting message processing in parallel. + /// + ///**Dangerous!** This is an experimental feature and should not be used in production, unless + /// explicitly advised to. + #[arg(long)] + pub enable_approval_voting_parallel: bool, } #[allow(missing_docs)] diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 89e21bf135b6..34ada58bbcdb 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -29,8 +29,6 @@ use sp_keyring::Sr25519Keyring; use std::net::ToSocketAddrs; pub use crate::error::Error; -#[cfg(feature = "hostperfcheck")] -pub use polkadot_performance_test::PerfCheckError; #[cfg(feature = "pyroscope")] use pyroscope_pprofrs::{pprof_backend, PprofConfig}; @@ -244,6 +242,7 @@ where execute_workers_max_num: cli.run.execute_workers_max_num, prepare_workers_hard_max_num: cli.run.prepare_workers_hard_max_num, prepare_workers_soft_max_num: cli.run.prepare_workers_soft_max_num, + enable_approval_voting_parallel: cli.run.enable_approval_voting_parallel, }, ) .map(|full| full.task_manager)?; diff --git a/polkadot/node/core/approval-voting-parallel/Cargo.toml b/polkadot/node/core/approval-voting-parallel/Cargo.toml new file mode 100644 index 000000000000..e62062eab409 --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "polkadot-node-core-approval-voting-parallel" +version = "7.0.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +description = "Approval Voting Subsystem running approval work in parallel" + +[lints] +workspace = true + +[dependencies] +async-trait = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true } +itertools = { workspace = true } +thiserror = { workspace = true } + +polkadot-node-core-approval-voting = { workspace = true, default-features = true } +polkadot-approval-distribution = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-jaeger = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } + +sc-keystore = { workspace = true, default-features = false } +sp-consensus = { workspace = true, default-features = false } +sp-consensus-slots = { workspace = true, default-features = false } +sp-application-crypto = { workspace = true, default-features = false, features = ["full_crypto"] } +sp-runtime = { workspace = true, default-features = false } + +rand = { workspace = true } +rand_core = { workspace = true } +rand_chacha = { workspace = true } + +[dev-dependencies] +async-trait = { workspace = true } +parking_lot = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-tracing = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true, default-features = true } +assert_matches = { workspace = true } +kvdb-memorydb = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true, default-features = true } +log = { workspace = true, default-features = true } +polkadot-subsystem-bench = { workspace = true, default-features = true } +schnorrkel = { workspace = true, default-features = true } diff --git a/polkadot/node/core/approval-voting-parallel/src/lib.rs b/polkadot/node/core/approval-voting-parallel/src/lib.rs new file mode 100644 index 000000000000..1a7ef756bdfc --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/src/lib.rs @@ -0,0 +1,958 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! The Approval Voting Parallel Subsystem. +//! +//! This subsystem is responsible for orchestrating the work done by +//! approval-voting and approval-distribution subsystem, so they can +//! do their work in parallel, rather than serially, when they are run +//! as independent subsystems. +use itertools::Itertools; +use metrics::{Meters, MetricsWatcher}; +use polkadot_node_core_approval_voting::{Config, RealAssignmentCriteria}; +use polkadot_node_metrics::metered::{ + self, channel, unbounded, MeteredReceiver, MeteredSender, UnboundedMeteredReceiver, + UnboundedMeteredSender, +}; + +use polkadot_node_primitives::{ + approval::time::{Clock, SystemClock}, + DISPUTE_WINDOW, +}; +use polkadot_node_subsystem::{ + messages::{ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage}, + overseer, FromOrchestra, SpawnedSubsystem, SubsystemError, SubsystemResult, +}; +use polkadot_node_subsystem_util::{ + self, + database::Database, + runtime::{Config as RuntimeInfoConfig, RuntimeInfo}, +}; +use polkadot_overseer::{OverseerSignal, Priority, SubsystemSender, TimeoutExt}; +use polkadot_primitives::{CandidateIndex, Hash, ValidatorIndex, ValidatorSignature}; +use rand::SeedableRng; + +use sc_keystore::LocalKeystore; +use sp_consensus::SyncOracle; + +use futures::{channel::oneshot, prelude::*, StreamExt}; +pub use metrics::Metrics; +use polkadot_node_core_approval_voting::{ + approval_db::common::Config as DatabaseConfig, ApprovalVotingWorkProvider, +}; +use std::{ + collections::{HashMap, HashSet}, + fmt::Debug, + sync::Arc, + time::Duration, +}; +use stream::{select_with_strategy, PollNext, SelectWithStrategy}; +pub mod metrics; + +#[cfg(test)] +mod tests; + +pub(crate) const LOG_TARGET: &str = "parachain::approval-voting-parallel"; +// Value rather arbitrarily: Should not be hit in practice, it exists to more easily diagnose dead +// lock issues for example. +const WAIT_FOR_SIGS_GATHER_TIMEOUT: Duration = Duration::from_millis(2000); + +/// The number of workers used for running the approval-distribution logic. +pub const APPROVAL_DISTRIBUTION_WORKER_COUNT: usize = 4; + +/// The default channel size for the workers, can be overridden by the user through +/// `overseer_channel_capacity_override` +pub const DEFAULT_WORKERS_CHANNEL_SIZE: usize = 64000 / APPROVAL_DISTRIBUTION_WORKER_COUNT; + +fn prio_right<'a>(_val: &'a mut ()) -> PollNext { + PollNext::Right +} + +/// The approval voting parallel subsystem. +pub struct ApprovalVotingParallelSubsystem { + /// `LocalKeystore` is needed for assignment keys, but not necessarily approval keys. + /// + /// We do a lot of VRF signing and need the keys to have low latency. + keystore: Arc, + db_config: DatabaseConfig, + slot_duration_millis: u64, + db: Arc, + sync_oracle: Box, + metrics: Metrics, + spawner: Arc, + clock: Arc, + overseer_message_channel_capacity_override: Option, +} + +impl ApprovalVotingParallelSubsystem { + /// Create a new approval voting subsystem with the given keystore, config, and database. + pub fn with_config( + config: Config, + db: Arc, + keystore: Arc, + sync_oracle: Box, + metrics: Metrics, + spawner: impl overseer::gen::Spawner + 'static + Clone, + overseer_message_channel_capacity_override: Option, + ) -> Self { + ApprovalVotingParallelSubsystem::with_config_and_clock( + config, + db, + keystore, + sync_oracle, + metrics, + Arc::new(SystemClock {}), + spawner, + overseer_message_channel_capacity_override, + ) + } + + /// Create a new approval voting subsystem with the given keystore, config, clock, and database. + pub fn with_config_and_clock( + config: Config, + db: Arc, + keystore: Arc, + sync_oracle: Box, + metrics: Metrics, + clock: Arc, + spawner: impl overseer::gen::Spawner + 'static, + overseer_message_channel_capacity_override: Option, + ) -> Self { + ApprovalVotingParallelSubsystem { + keystore, + slot_duration_millis: config.slot_duration_millis, + db, + db_config: DatabaseConfig { col_approval_data: config.col_approval_data }, + sync_oracle, + metrics, + spawner: Arc::new(spawner), + clock, + overseer_message_channel_capacity_override, + } + } + + /// The size of the channel used for the workers. + fn workers_channel_size(&self) -> usize { + self.overseer_message_channel_capacity_override + .unwrap_or(DEFAULT_WORKERS_CHANNEL_SIZE) + } +} + +#[overseer::subsystem(ApprovalVotingParallel, error = SubsystemError, prefix = self::overseer)] +impl ApprovalVotingParallelSubsystem { + fn start(self, ctx: Context) -> SpawnedSubsystem { + let future = run::(ctx, self) + .map_err(|e| SubsystemError::with_origin("approval-voting-parallel", e)) + .boxed(); + + SpawnedSubsystem { name: "approval-voting-parallel-subsystem", future } + } +} + +// It starts worker for the approval voting subsystem and the `APPROVAL_DISTRIBUTION_WORKER_COUNT` +// workers for the approval distribution subsystem. +// +// It returns handles that can be used to send messages to the workers. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn start_workers( + ctx: &mut Context, + subsystem: ApprovalVotingParallelSubsystem, + metrics_watcher: &mut MetricsWatcher, +) -> SubsystemResult<(ToWorker, Vec>)> +where +{ + gum::info!(target: LOG_TARGET, "Starting approval distribution workers"); + + // Build approval voting handles. + let (to_approval_voting_worker, approval_voting_work_provider) = build_worker_handles( + "approval-voting-parallel-db".into(), + subsystem.workers_channel_size(), + metrics_watcher, + prio_right, + ); + let mut to_approval_distribution_workers = Vec::new(); + let slot_duration_millis = subsystem.slot_duration_millis; + + for i in 0..APPROVAL_DISTRIBUTION_WORKER_COUNT { + let mut network_sender = ctx.sender().clone(); + let mut runtime_api_sender = ctx.sender().clone(); + let mut approval_distribution_to_approval_voting = to_approval_voting_worker.clone(); + + let approval_distr_instance = + polkadot_approval_distribution::ApprovalDistribution::new_with_clock( + subsystem.metrics.approval_distribution_metrics(), + subsystem.slot_duration_millis, + subsystem.clock.clone(), + Arc::new(RealAssignmentCriteria {}), + ); + let task_name = format!("approval-voting-parallel-{}", i); + let (to_approval_distribution_worker, mut approval_distribution_work_provider) = + build_worker_handles( + task_name.clone(), + subsystem.workers_channel_size(), + metrics_watcher, + prio_right, + ); + + metrics_watcher.watch(task_name.clone(), to_approval_distribution_worker.meter()); + + subsystem.spawner.spawn_blocking( + task_name.leak(), + Some("approval-voting-parallel"), + Box::pin(async move { + let mut state = + polkadot_approval_distribution::State::with_config(slot_duration_millis); + let mut rng = rand::rngs::StdRng::from_entropy(); + let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + loop { + let message = match approval_distribution_work_provider.next().await { + Some(message) => message, + None => { + gum::info!( + target: LOG_TARGET, + "Approval distribution stream finished, most likely shutting down", + ); + break; + }, + }; + if approval_distr_instance + .handle_from_orchestra( + message, + &mut approval_distribution_to_approval_voting, + &mut network_sender, + &mut runtime_api_sender, + &mut state, + &mut rng, + &mut session_info_provider, + ) + .await + { + gum::info!( + target: LOG_TARGET, + "Approval distribution worker {}, exiting because of shutdown", i + ); + }; + } + }), + ); + to_approval_distribution_workers.push(to_approval_distribution_worker); + } + + gum::info!(target: LOG_TARGET, "Starting approval voting workers"); + + let sender = ctx.sender().clone(); + let to_approval_distribution = ApprovalVotingToApprovalDistribution(sender.clone()); + polkadot_node_core_approval_voting::start_approval_worker( + approval_voting_work_provider, + sender.clone(), + to_approval_distribution, + polkadot_node_core_approval_voting::Config { + slot_duration_millis: subsystem.slot_duration_millis, + col_approval_data: subsystem.db_config.col_approval_data, + }, + subsystem.db.clone(), + subsystem.keystore.clone(), + subsystem.sync_oracle, + subsystem.metrics.approval_voting_metrics(), + subsystem.spawner.clone(), + "approval-voting-parallel-db", + "approval-voting-parallel", + subsystem.clock.clone(), + ) + .await?; + + Ok((to_approval_voting_worker, to_approval_distribution_workers)) +} + +// The main run function of the approval parallel voting subsystem. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn run( + mut ctx: Context, + subsystem: ApprovalVotingParallelSubsystem, +) -> SubsystemResult<()> { + let mut metrics_watcher = MetricsWatcher::new(subsystem.metrics.clone()); + gum::info!( + target: LOG_TARGET, + "Starting workers" + ); + + let (to_approval_voting_worker, to_approval_distribution_workers) = + start_workers(&mut ctx, subsystem, &mut metrics_watcher).await?; + + gum::info!( + target: LOG_TARGET, + "Starting main subsystem loop" + ); + + run_main_loop(ctx, to_approval_voting_worker, to_approval_distribution_workers, metrics_watcher) + .await +} + +// Main loop of the subsystem, it shouldn't include any logic just dispatching of messages to +// the workers. +// +// It listens for messages from the overseer and dispatches them to the workers. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn run_main_loop( + mut ctx: Context, + mut to_approval_voting_worker: ToWorker, + mut to_approval_distribution_workers: Vec>, + metrics_watcher: MetricsWatcher, +) -> SubsystemResult<()> { + loop { + futures::select! { + next_msg = ctx.recv().fuse() => { + let next_msg = match next_msg { + Ok(msg) => msg, + Err(err) => { + gum::info!(target: LOG_TARGET, ?err, "Approval voting parallel subsystem received an error"); + return Err(err); + } + }; + + match next_msg { + FromOrchestra::Signal(msg) => { + if matches!(msg, OverseerSignal::ActiveLeaves(_)) { + metrics_watcher.collect_metrics(); + } + + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_signal(msg.clone()).await?; + } + + to_approval_voting_worker.send_signal(msg.clone()).await?; + if matches!(msg, OverseerSignal::Conclude) { + break; + } + }, + FromOrchestra::Communication { msg } => match msg { + // The message the approval voting subsystem would've handled. + ApprovalVotingParallelMessage::ApprovedAncestor(_, _,_) | + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate(_, _) => { + to_approval_voting_worker.send_message( + msg.try_into().expect( + "Message is one of ApprovedAncestor, GetApprovalSignaturesForCandidate + and that can be safely converted to ApprovalVotingMessage; qed" + ) + ).await; + }, + // Now the message the approval distribution subsystem would've handled and need to + // be forwarded to the workers. + ApprovalVotingParallelMessage::NewBlocks(msg) => { + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_message( + ApprovalDistributionMessage::NewBlocks(msg.clone()), + ) + .await; + } + }, + ApprovalVotingParallelMessage::DistributeAssignment(assignment, claimed) => { + let worker = assigned_worker_for_validator(assignment.validator, &mut to_approval_distribution_workers); + worker + .send_message( + ApprovalDistributionMessage::DistributeAssignment(assignment, claimed) + ) + .await; + + }, + ApprovalVotingParallelMessage::DistributeApproval(vote) => { + let worker = assigned_worker_for_validator(vote.validator, &mut to_approval_distribution_workers); + worker + .send_message( + ApprovalDistributionMessage::DistributeApproval(vote) + ).await; + + }, + ApprovalVotingParallelMessage::NetworkBridgeUpdate(msg) => { + if let polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + peer_id, + msg, + ) = msg + { + let (all_msgs_from_same_validator, messages_split_by_validator) = validator_index_for_msg(msg); + + for (validator_index, msg) in all_msgs_from_same_validator.into_iter().chain(messages_split_by_validator.into_iter().flatten()) { + let worker = assigned_worker_for_validator(validator_index, &mut to_approval_distribution_workers); + + worker + .send_message( + ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + peer_id, msg, + ), + ), + ).await; + } + } else { + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_message_with_priority::( + ApprovalDistributionMessage::NetworkBridgeUpdate(msg.clone()), + ).await; + } + } + }, + ApprovalVotingParallelMessage::GetApprovalSignatures(indices, tx) => { + handle_get_approval_signatures(&mut ctx, &mut to_approval_distribution_workers, indices, tx).await; + }, + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag) => { + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_message( + ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag) + ).await; + } + }, + }, + }; + + }, + }; + } + Ok(()) +} + +// It sends a message to all approval workers to get the approval signatures for the requested +// candidates and then merges them all together and sends them back to the requester. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn handle_get_approval_signatures( + ctx: &mut Context, + to_approval_distribution_workers: &mut Vec>, + requested_candidates: HashSet<(Hash, CandidateIndex)>, + result_channel: oneshot::Sender< + HashMap, ValidatorSignature)>, + >, +) { + let mut sigs = HashMap::new(); + let mut signatures_channels = Vec::new(); + for worker in to_approval_distribution_workers.iter_mut() { + let (tx, rx) = oneshot::channel(); + worker.send_unbounded_message(ApprovalDistributionMessage::GetApprovalSignatures( + requested_candidates.clone(), + tx, + )); + signatures_channels.push(rx); + } + + let gather_signatures = async move { + let Some(results) = futures::future::join_all(signatures_channels) + .timeout(WAIT_FOR_SIGS_GATHER_TIMEOUT) + .await + else { + gum::warn!( + target: LOG_TARGET, + "Waiting for approval signatures timed out - dead lock?" + ); + return; + }; + + for result in results { + let worker_sigs = match result { + Ok(sigs) => sigs, + Err(_) => { + gum::error!( + target: LOG_TARGET, + "Getting approval signatures failed, oneshot got closed" + ); + continue; + }, + }; + sigs.extend(worker_sigs); + } + + if let Err(_) = result_channel.send(sigs) { + gum::debug!( + target: LOG_TARGET, + "Sending back approval signatures failed, oneshot got closed" + ); + } + }; + + if let Err(err) = ctx.spawn("approval-voting-gather-signatures", Box::pin(gather_signatures)) { + gum::warn!(target: LOG_TARGET, "Failed to spawn gather signatures task: {:?}", err); + } +} + +// Returns the worker that should receive the message for the given validator. +fn assigned_worker_for_validator( + validator: ValidatorIndex, + to_approval_distribution_workers: &mut Vec>, +) -> &mut ToWorker { + let worker_index = validator.0 as usize % to_approval_distribution_workers.len(); + to_approval_distribution_workers + .get_mut(worker_index) + .expect("Worker index is obtained modulo len; qed") +} + +// Returns the validators that initially created this assignments/votes, the validator index +// is later used to decide which approval-distribution worker should receive the message. +// +// Because this is on the hot path and we don't want to be unnecessarily slow, it contains two logic +// paths. The ultra fast path where all messages have the same validator index and we don't do +// any cloning or allocation and the path where we need to split the messages into multiple +// messages, because they have different validator indices, where we do need to clone and allocate. +// In practice most of the message will fall on the ultra fast path. +fn validator_index_for_msg( + msg: polkadot_node_network_protocol::ApprovalDistributionMessage, +) -> ( + Option<(ValidatorIndex, polkadot_node_network_protocol::ApprovalDistributionMessage)>, + Option>, +) { + match msg { + polkadot_node_network_protocol::Versioned::V1(ref message) => match message { + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments(msgs) => + if let Ok(validator) = msgs.iter().map(|(msg, _)| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|(msg, claimed_candidates)| { + ( + msg.validator, + polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments( + vec![(msg.clone(), *claimed_candidates)] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals(msgs) => + if let Ok(validator) = msgs.iter().map(|msg| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|vote| { + ( + vote.validator, + polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals( + vec![vote.clone()] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + }, + polkadot_node_network_protocol::Versioned::V2(ref message) => match message { + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments(msgs) => + if let Ok(validator) = msgs.iter().map(|(msg, _)| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|(msg, claimed_candidates)| { + ( + msg.validator, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments( + vec![(msg.clone(), *claimed_candidates)] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals(msgs) => + if let Ok(validator) = msgs.iter().map(|msg| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|vote| { + ( + vote.validator, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals( + vec![vote.clone()] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + }, + polkadot_node_network_protocol::Versioned::V3(ref message) => match message { + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments(msgs) => + if let Ok(validator) = msgs.iter().map(|(msg, _)| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|(msg, claimed_candidates)| { + ( + msg.validator, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments( + vec![(msg.clone(), claimed_candidates.clone())] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals(msgs) => + if let Ok(validator) = msgs.iter().map(|msg| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|vote| { + ( + vote.validator, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + vec![vote.clone()] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + }, + } +} + +/// A handler object that both type of workers use for receiving work. +/// +/// In practive this is just a wrapper over two channels Receiver, that is injected into +/// approval-voting worker and approval-distribution workers. +type WorkProvider = WorkProviderImpl< + SelectWithStrategy< + MeteredReceiver>, + UnboundedMeteredReceiver>, + Clos, + State, + >, +>; + +pub struct WorkProviderImpl(T); + +impl Stream for WorkProviderImpl +where + T: Stream> + Unpin + Send, +{ + type Item = FromOrchestra; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.0.poll_next_unpin(cx) + } +} + +#[async_trait::async_trait] +impl ApprovalVotingWorkProvider for WorkProviderImpl +where + T: Stream> + Unpin + Send, +{ + async fn recv(&mut self) -> SubsystemResult> { + self.0.next().await.ok_or(SubsystemError::Context( + "ApprovalVotingWorkProviderImpl: Channel closed".to_string(), + )) + } +} + +impl WorkProvider +where + M: Send + Sync + 'static, + Clos: FnMut(&mut State) -> PollNext, + State: Default, +{ + // Constructs a work providers from the channels handles. + fn from_rx_worker(rx: RxWorker, prio: Clos) -> Self { + let prioritised = select_with_strategy(rx.0, rx.1, prio); + WorkProviderImpl(prioritised) + } +} + +/// Just a wrapper for implementing `overseer::SubsystemSender` and +/// `overseer::SubsystemSender`. +/// +/// The instance of this struct can be injected into the workers, so they can talk +/// directly with each other without intermediating in this subsystem loop. +pub struct ToWorker( + MeteredSender>, + UnboundedMeteredSender>, +); + +impl Clone for ToWorker { + fn clone(&self) -> Self { + Self(self.0.clone(), self.1.clone()) + } +} + +impl ToWorker { + async fn send_signal(&mut self, signal: OverseerSignal) -> Result<(), SubsystemError> { + self.1 + .unbounded_send(FromOrchestra::Signal(signal)) + .map_err(|err| SubsystemError::QueueError(err.into_send_error())) + } + + fn meter(&self) -> Meters { + Meters::new(self.0.meter(), self.1.meter()) + } +} + +impl overseer::SubsystemSender for ToWorker { + fn send_message<'life0, 'async_trait>( + &'life0 mut self, + msg: T, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + async { + if let Err(err) = + self.0.send(polkadot_overseer::FromOrchestra::Communication { msg }).await + { + gum::error!( + target: LOG_TARGET, + "Failed to send message to approval voting worker: {:?}, subsystem is probably shutting down.", + err + ); + } + } + .boxed() + } + + fn try_send_message(&mut self, msg: T) -> Result<(), metered::TrySendError> { + self.0 + .try_send(polkadot_overseer::FromOrchestra::Communication { msg }) + .map_err(|result| { + let is_full = result.is_full(); + let msg = match result.into_inner() { + polkadot_overseer::FromOrchestra::Signal(_) => + panic!("Cannot happen variant is never built"), + polkadot_overseer::FromOrchestra::Communication { msg } => msg, + }; + if is_full { + metered::TrySendError::Full(msg) + } else { + metered::TrySendError::Closed(msg) + } + }) + } + + fn send_messages<'life0, 'async_trait, I>( + &'life0 mut self, + msgs: I, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + I: IntoIterator + Send, + I::IntoIter: Send, + I: 'async_trait, + 'life0: 'async_trait, + Self: 'async_trait, + { + async { + for msg in msgs { + self.send_message(msg).await; + } + } + .boxed() + } + + fn send_unbounded_message(&mut self, msg: T) { + if let Err(err) = + self.1.unbounded_send(polkadot_overseer::FromOrchestra::Communication { msg }) + { + gum::error!( + target: LOG_TARGET, + "Failed to send unbounded message to approval voting worker: {:?}, subsystem is probably shutting down.", + err + ); + } + } + + fn send_message_with_priority<'life0, 'async_trait, P>( + &'life0 mut self, + msg: T, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + P: 'async_trait + Priority, + 'life0: 'async_trait, + Self: 'async_trait, + { + match P::priority() { + polkadot_overseer::PriorityLevel::Normal => self.send_message(msg), + polkadot_overseer::PriorityLevel::High => + async { self.send_unbounded_message(msg) }.boxed(), + } + } + + fn try_send_message_with_priority( + &mut self, + msg: T, + ) -> Result<(), metered::TrySendError> { + match P::priority() { + polkadot_overseer::PriorityLevel::Normal => self.try_send_message(msg), + polkadot_overseer::PriorityLevel::High => Ok(self.send_unbounded_message(msg)), + } + } +} + +/// Handles that are used by an worker to receive work. +pub struct RxWorker( + MeteredReceiver>, + UnboundedMeteredReceiver>, +); + +// Build all the necessary channels for sending messages to an worker +// and for the worker to receive them. +fn build_channels( + channel_name: String, + channel_size: usize, + metrics_watcher: &mut MetricsWatcher, +) -> (ToWorker, RxWorker) { + let (tx_work, rx_work) = channel::>(channel_size); + let (tx_work_unbounded, rx_work_unbounded) = unbounded::>(); + let to_worker = ToWorker(tx_work, tx_work_unbounded); + + metrics_watcher.watch(channel_name, to_worker.meter()); + + (to_worker, RxWorker(rx_work, rx_work_unbounded)) +} + +/// Build the worker handles used for interacting with the workers. +/// +/// `ToWorker` is used for sending messages to the workers. +/// `WorkProvider` is used by the workers for receiving the messages. +fn build_worker_handles( + channel_name: String, + channel_size: usize, + metrics_watcher: &mut MetricsWatcher, + prio_right: Clos, +) -> (ToWorker, WorkProvider) +where + M: Send + Sync + 'static, + Clos: FnMut(&mut State) -> PollNext, + State: Default, +{ + let (to_worker, rx_worker) = build_channels(channel_name, channel_size, metrics_watcher); + (to_worker, WorkProviderImpl::from_rx_worker(rx_worker, prio_right)) +} + +/// Just a wrapper for implementing `overseer::SubsystemSender`, so +/// that we can inject into the approval voting subsystem. +#[derive(Clone)] +pub struct ApprovalVotingToApprovalDistribution>( + S, +); + +impl> + overseer::SubsystemSender + for ApprovalVotingToApprovalDistribution +{ + #[allow(clippy::type_complexity, clippy::type_repetition_in_bounds)] + fn send_message<'life0, 'async_trait>( + &'life0 mut self, + msg: ApprovalDistributionMessage, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + self.0.send_message(msg.into()) + } + + fn try_send_message( + &mut self, + msg: ApprovalDistributionMessage, + ) -> Result<(), metered::TrySendError> { + self.0.try_send_message(msg.into()).map_err(|err| match err { + // Safe to unwrap because it was built from the same type. + metered::TrySendError::Closed(msg) => + metered::TrySendError::Closed(msg.try_into().unwrap()), + metered::TrySendError::Full(msg) => + metered::TrySendError::Full(msg.try_into().unwrap()), + }) + } + + #[allow(clippy::type_complexity, clippy::type_repetition_in_bounds)] + fn send_messages<'life0, 'async_trait, I>( + &'life0 mut self, + msgs: I, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + I: IntoIterator + Send, + I::IntoIter: Send, + I: 'async_trait, + 'life0: 'async_trait, + Self: 'async_trait, + { + self.0.send_messages(msgs.into_iter().map(|msg| msg.into())) + } + + fn send_unbounded_message(&mut self, msg: ApprovalDistributionMessage) { + self.0.send_unbounded_message(msg.into()) + } + + fn send_message_with_priority<'life0, 'async_trait, P>( + &'life0 mut self, + msg: ApprovalDistributionMessage, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + P: 'async_trait + Priority, + 'life0: 'async_trait, + Self: 'async_trait, + { + self.0.send_message_with_priority::

(msg.into()) + } + + fn try_send_message_with_priority( + &mut self, + msg: ApprovalDistributionMessage, + ) -> Result<(), metered::TrySendError> { + self.0.try_send_message_with_priority::

(msg.into()).map_err(|err| match err { + // Safe to unwrap because it was built from the same type. + metered::TrySendError::Closed(msg) => + metered::TrySendError::Closed(msg.try_into().unwrap()), + metered::TrySendError::Full(msg) => + metered::TrySendError::Full(msg.try_into().unwrap()), + }) + } +} diff --git a/polkadot/node/core/approval-voting-parallel/src/metrics.rs b/polkadot/node/core/approval-voting-parallel/src/metrics.rs new file mode 100644 index 000000000000..1b4ab4bd9b88 --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/src/metrics.rs @@ -0,0 +1,236 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! The Metrics for Approval Voting Parallel Subsystem. + +use std::collections::HashMap; + +use polkadot_node_metrics::{metered::Meter, metrics}; +use polkadot_overseer::prometheus; + +#[derive(Default, Clone)] +pub struct Metrics(Option); + +/// Approval Voting parallel metrics. +#[derive(Clone)] +pub struct MetricsInner { + // The inner metrics of the approval distribution workers. + approval_distribution: polkadot_approval_distribution::metrics::Metrics, + // The inner metrics of the approval voting workers. + approval_voting: polkadot_node_core_approval_voting::Metrics, + + // Time of flight metrics for bounded channels. + to_worker_bounded_tof: prometheus::HistogramVec, + // Number of elements sent to the worker's bounded queue. + to_worker_bounded_sent: prometheus::GaugeVec, + // Number of elements received by the worker's bounded queue. + to_worker_bounded_received: prometheus::GaugeVec, + // Number of times senders blocked while sending messages to the worker. + to_worker_bounded_blocked: prometheus::GaugeVec, + // Time of flight metrics for unbounded channels. + to_worker_unbounded_tof: prometheus::HistogramVec, + // Number of elements sent to the worker's unbounded queue. + to_worker_unbounded_sent: prometheus::GaugeVec, + // Number of elements received by the worker's unbounded queue. + to_worker_unbounded_received: prometheus::GaugeVec, +} + +impl Metrics { + /// Get the approval distribution metrics. + pub fn approval_distribution_metrics( + &self, + ) -> polkadot_approval_distribution::metrics::Metrics { + self.0 + .as_ref() + .map(|metrics_inner| metrics_inner.approval_distribution.clone()) + .unwrap_or_default() + } + + /// Get the approval voting metrics. + pub fn approval_voting_metrics(&self) -> polkadot_node_core_approval_voting::Metrics { + self.0 + .as_ref() + .map(|metrics_inner| metrics_inner.approval_voting.clone()) + .unwrap_or_default() + } +} + +impl metrics::Metrics for Metrics { + /// Try to register the metrics. + fn try_register( + registry: &prometheus::Registry, + ) -> std::result::Result { + Ok(Metrics(Some(MetricsInner { + approval_distribution: polkadot_approval_distribution::metrics::Metrics::try_register( + registry, + )?, + approval_voting: polkadot_node_core_approval_voting::Metrics::try_register(registry)?, + to_worker_bounded_tof: prometheus::register( + prometheus::HistogramVec::new( + prometheus::HistogramOpts::new( + "polkadot_approval_voting_parallel_worker_bounded_tof", + "Duration spent in a particular approval voting worker channel from entrance to removal", + ) + .buckets(vec![ + 0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, + 4.9152, 6.5536, + ]), + &["worker_name"], + )?, + registry, + )?, + to_worker_bounded_sent: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_bounded_sent", + "Number of elements sent to approval voting workers' bounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_bounded_received: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_bounded_received", + "Number of elements received by approval voting workers' bounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_bounded_blocked: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_bounded_blocked", + "Number of times approval voting workers blocked while sending messages to a subsystem", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_unbounded_tof: prometheus::register( + prometheus::HistogramVec::new( + prometheus::HistogramOpts::new( + "polkadot_approval_voting_parallel_worker_unbounded_tof", + "Duration spent in a particular approval voting worker channel from entrance to removal", + ) + .buckets(vec![ + 0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, + 4.9152, 6.5536, + ]), + &["worker_name"], + )?, + registry, + )?, + to_worker_unbounded_sent: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_unbounded_sent", + "Number of elements sent to approval voting workers' unbounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_unbounded_received: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_unbounded_received", + "Number of elements received by approval voting workers' unbounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + }))) + } +} + +/// The meters to watch. +#[derive(Clone)] +pub struct Meters { + bounded: Meter, + unbounded: Meter, +} + +impl Meters { + pub fn new(bounded: &Meter, unbounded: &Meter) -> Self { + Self { bounded: bounded.clone(), unbounded: unbounded.clone() } + } +} + +/// A metrics watcher that watches the meters and updates the metrics. +pub struct MetricsWatcher { + to_watch: HashMap, + metrics: Metrics, +} + +impl MetricsWatcher { + /// Create a new metrics watcher. + pub fn new(metrics: Metrics) -> Self { + Self { to_watch: HashMap::new(), metrics } + } + + /// Watch the meters of a worker with this name. + pub fn watch(&mut self, worker_name: String, meters: Meters) { + self.to_watch.insert(worker_name, meters); + } + + /// Collect all the metrics. + pub fn collect_metrics(&self) { + for (name, meter) in &self.to_watch { + let bounded_readouts = meter.bounded.read(); + let unbounded_readouts = meter.unbounded.read(); + if let Some(metrics) = self.metrics.0.as_ref() { + metrics + .to_worker_bounded_sent + .with_label_values(&[name]) + .set(bounded_readouts.sent as u64); + + metrics + .to_worker_bounded_received + .with_label_values(&[name]) + .set(bounded_readouts.received as u64); + + metrics + .to_worker_bounded_blocked + .with_label_values(&[name]) + .set(bounded_readouts.blocked as u64); + + metrics + .to_worker_unbounded_sent + .with_label_values(&[name]) + .set(unbounded_readouts.sent as u64); + + metrics + .to_worker_unbounded_received + .with_label_values(&[name]) + .set(unbounded_readouts.received as u64); + + let hist_bounded = metrics.to_worker_bounded_tof.with_label_values(&[name]); + for tof in bounded_readouts.tof { + hist_bounded.observe(tof.as_f64()); + } + + let hist_unbounded = metrics.to_worker_unbounded_tof.with_label_values(&[name]); + for tof in unbounded_readouts.tof { + hist_unbounded.observe(tof.as_f64()); + } + } + } + } +} diff --git a/polkadot/node/core/approval-voting-parallel/src/tests.rs b/polkadot/node/core/approval-voting-parallel/src/tests.rs new file mode 100644 index 000000000000..215a707147fc --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/src/tests.rs @@ -0,0 +1,1178 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +//! The tests for Approval Voting Parallel Subsystem. + +use std::{ + collections::{HashMap, HashSet}, + future::Future, + sync::Arc, + time::Duration, +}; + +use crate::{ + build_worker_handles, metrics::MetricsWatcher, prio_right, run_main_loop, start_workers, + validator_index_for_msg, ApprovalVotingParallelSubsystem, Metrics, WorkProvider, +}; +use assert_matches::assert_matches; +use futures::{channel::oneshot, future, stream::PollNext, StreamExt}; +use itertools::Itertools; +use polkadot_node_core_approval_voting::{ApprovalVotingWorkProvider, Config}; +use polkadot_node_network_protocol::{peer_set::ValidationVersion, ObservedRole, PeerId, View}; +use polkadot_node_primitives::approval::{ + time::SystemClock, + v1::{ + AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, IndirectSignedApprovalVote, + RELAY_VRF_MODULO_CONTEXT, + }, + v2::{ + AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, IndirectAssignmentCertV2, + IndirectSignedApprovalVoteV2, + }, +}; +use polkadot_node_subsystem::{ + messages::{ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage}, + FromOrchestra, +}; +use polkadot_node_subsystem_test_helpers::{mock::new_leaf, TestSubsystemContext}; +use polkadot_overseer::{ActiveLeavesUpdate, OverseerSignal, SpawnGlue, TimeoutExt}; +use polkadot_primitives::{CandidateHash, CoreIndex, Hash, ValidatorIndex}; +use sc_keystore::{Keystore, LocalKeystore}; +use sp_consensus::SyncOracle; +use sp_consensus_babe::{VrfPreOutput, VrfProof, VrfSignature}; +use sp_core::{testing::TaskExecutor, H256}; +use sp_keyring::Sr25519Keyring; +type VirtualOverseer = + polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; + +const SLOT_DURATION_MILLIS: u64 = 6000; + +pub mod test_constants { + pub(crate) const DATA_COL: u32 = 0; + pub(crate) const NUM_COLUMNS: u32 = 1; +} + +fn fake_assignment_cert(block_hash: Hash, validator: ValidatorIndex) -> IndirectAssignmentCert { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"WhenParachains?"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let preout = inout.to_preout(); + + IndirectAssignmentCert { + block_hash, + validator, + cert: AssignmentCert { + kind: AssignmentCertKind::RelayVRFModulo { sample: 1 }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + }, + } +} + +fn fake_assignment_cert_v2( + block_hash: Hash, + validator: ValidatorIndex, + core_bitfield: CoreBitfield, +) -> IndirectAssignmentCertV2 { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"WhenParachains?"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let preout = inout.to_preout(); + + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: AssignmentCertV2 { + kind: AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + }, + } +} + +/// Creates a meaningless signature +pub fn dummy_signature() -> polkadot_primitives::ValidatorSignature { + sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]) +} + +fn build_subsystem( + sync_oracle: Box, +) -> ( + ApprovalVotingParallelSubsystem, + TestSubsystemContext>, + VirtualOverseer, +) { + sp_tracing::init_for_tests(); + + let pool = sp_core::testing::TaskExecutor::new(); + let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< + ApprovalVotingParallelMessage, + _, + >(pool.clone()); + + let keystore = LocalKeystore::in_memory(); + let _ = keystore.sr25519_generate_new( + polkadot_primitives::PARACHAIN_KEY_TYPE_ID, + Some(&Sr25519Keyring::Alice.to_seed()), + ); + + let clock = Arc::new(SystemClock {}); + let db = kvdb_memorydb::create(test_constants::NUM_COLUMNS); + let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]); + + ( + ApprovalVotingParallelSubsystem::with_config_and_clock( + Config { + col_approval_data: test_constants::DATA_COL, + slot_duration_millis: SLOT_DURATION_MILLIS, + }, + Arc::new(db), + Arc::new(keystore), + sync_oracle, + Metrics::default(), + clock.clone(), + SpawnGlue(pool), + None, + ), + context, + virtual_overseer, + ) +} + +#[derive(Clone)] +struct TestSyncOracle {} + +impl SyncOracle for TestSyncOracle { + fn is_major_syncing(&self) -> bool { + false + } + + fn is_offline(&self) -> bool { + unimplemented!("not used in network bridge") + } +} + +fn test_harness( + num_approval_distro_workers: usize, + prio_right: Clos, + subsystem_gracefully_exits: bool, + test_fn: impl FnOnce( + VirtualOverseer, + WorkProvider, + Vec>, + ) -> T, +) where + T: Future, + Clos: Clone + FnMut(&mut State) -> PollNext, + State: Default, +{ + let (subsystem, context, virtual_overseer) = build_subsystem(Box::new(TestSyncOracle {})); + let mut metrics_watcher = MetricsWatcher::new(subsystem.metrics.clone()); + let channel_size = 5; + + let (to_approval_voting_worker, approval_voting_work_provider) = + build_worker_handles::( + "to_approval_voting_worker".into(), + channel_size, + &mut metrics_watcher, + prio_right.clone(), + ); + + let approval_distribution_channels = { 0..num_approval_distro_workers } + .into_iter() + .map(|worker_index| { + build_worker_handles::( + format!("to_approval_distro/{}", worker_index), + channel_size, + &mut metrics_watcher, + prio_right.clone(), + ) + }) + .collect_vec(); + + let to_approval_distribution_workers = + approval_distribution_channels.iter().map(|(tx, _)| tx.clone()).collect_vec(); + let approval_distribution_work_providers = + approval_distribution_channels.into_iter().map(|(_, rx)| rx).collect_vec(); + + let subsystem = async move { + let result = run_main_loop( + context, + to_approval_voting_worker, + to_approval_distribution_workers, + metrics_watcher, + ) + .await; + + if subsystem_gracefully_exits && result.is_err() { + result + } else { + Ok(()) + } + }; + + let test_fut = test_fn( + virtual_overseer, + approval_voting_work_provider, + approval_distribution_work_providers, + ); + + futures::pin_mut!(test_fut); + futures::pin_mut!(subsystem); + + futures::executor::block_on(future::join( + async move { + let _overseer = test_fut.await; + }, + subsystem, + )) + .1 + .unwrap(); +} + +const TIMEOUT: Duration = Duration::from_millis(2000); + +async fn overseer_signal(overseer: &mut VirtualOverseer, signal: OverseerSignal) { + overseer + .send(FromOrchestra::Signal(signal)) + .timeout(TIMEOUT) + .await + .expect(&format!("{:?} is more than enough for sending signals.", TIMEOUT)); +} + +async fn overseer_message(overseer: &mut VirtualOverseer, msg: ApprovalVotingParallelMessage) { + overseer + .send(FromOrchestra::Communication { msg }) + .timeout(TIMEOUT) + .await + .expect(&format!("{:?} is more than enough for sending signals.", TIMEOUT)); +} + +async fn run_start_workers() { + let (subsystem, mut context, _) = build_subsystem(Box::new(TestSyncOracle {})); + let mut metrics_watcher = MetricsWatcher::new(subsystem.metrics.clone()); + let _workers = start_workers(&mut context, subsystem, &mut metrics_watcher).await.unwrap(); +} + +// Test starting the workers succeeds. +#[test] +fn start_workers_succeeds() { + futures::executor::block_on(run_start_workers()); +} + +// Test main loop forwards messages to the correct worker for all type of messages. +#[test] +fn test_main_loop_forwards_correctly() { + let num_approval_distro_workers = 4; + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + // 1. Check Signals are correctly forwarded to the workers. + let signal = OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + Hash::random(), + 1, + ))); + overseer_signal(&mut overseer, signal.clone()).await; + let approval_voting_receives = approval_voting_work_provider.recv().await.unwrap(); + assert_matches!(approval_voting_receives, FromOrchestra::Signal(_)); + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + let approval_distribution_receives = + rx_approval_distribution_worker.next().await.unwrap(); + assert_matches!(approval_distribution_receives, FromOrchestra::Signal(_)); + } + + let (test_tx, _rx) = oneshot::channel(); + let test_hash = Hash::random(); + let test_block_nr = 2; + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::ApprovedAncestor(test_hash, test_block_nr, test_tx), + ) + .await; + assert_matches!( + approval_voting_work_provider.recv().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalVotingMessage::ApprovedAncestor(hash, block_nr, _) + } => { + assert_eq!(hash, test_hash); + assert_eq!(block_nr, test_block_nr); + } + ); + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + + // 2. Check GetApprovalSignaturesForCandidate is correctly forwarded to the workers. + let (test_tx, _rx) = oneshot::channel(); + let test_hash = CandidateHash(Hash::random()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate( + test_hash, test_tx, + ), + ) + .await; + + assert_matches!( + approval_voting_work_provider.recv().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalVotingMessage::GetApprovalSignaturesForCandidate(hash, _) + } => { + assert_eq!(hash, test_hash); + } + ); + + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + + // 3. Check NewBlocks is correctly forwarded to the workers. + overseer_message(&mut overseer, ApprovalVotingParallelMessage::NewBlocks(vec![])).await; + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NewBlocks(blocks) + } => { + assert!(blocks.is_empty()); + } + ); + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 4. Check DistributeAssignment is correctly forwarded to the workers. + let validator_index = ValidatorIndex(17); + let assignment = + fake_assignment_cert_v2(Hash::random(), validator_index, CoreIndex(1).into()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeAssignment(assignment.clone(), 1.into()), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeAssignment(cert, bitfield) + } => { + assert_eq!(cert, assignment); + assert_eq!(bitfield, 1.into()); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 5. Check DistributeApproval is correctly forwarded to the workers. + let validator_index = ValidatorIndex(26); + let expected_vote = IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }; + + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeApproval(expected_vote.clone()), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeApproval(vote) + } => { + assert_eq!(vote, expected_vote); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + + // 6. Check NetworkBridgeUpdate::PeerMessage is correctly forwarded just to one of the + // workers. + let approvals = vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 2.into(), + validator: validator_index, + signature: dummy_signature(), + }, + ]; + let expected_msg = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + PeerId::random(), + expected_msg.clone(), + ), + ), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + _, + msg, + ), + ) + } => { + assert_eq!(msg, expected_msg); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 7. Check NetworkBridgeUpdate::PeerConnected is correctly forwarded to all workers. + let expected_peer_id = PeerId::random(); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerConnected( + expected_peer_id, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + ), + ), + ) + .await; + + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerConnected( + peer_id, + role, + version, + authority_id, + ), + ) + } => { + assert_eq!(peer_id, expected_peer_id); + assert_eq!(role, ObservedRole::Authority); + assert_eq!(version, ValidationVersion::V3.into()); + assert_eq!(authority_id, None); + } + ); + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 8. Check ApprovalCheckingLagUpdate is correctly forwarded to all workers. + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(7), + ) + .await; + + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::ApprovalCheckingLagUpdate( + lag + ) + } => { + assert_eq!(lag, 7); + } + ); + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + + overseer + }, + ); +} + +/// Test GetApprovalSignatures correctly gatheres the signatures from all workers. +#[test] +fn test_handle_get_approval_signatures() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let (tx, rx) = oneshot::channel(); + let first_block = Hash::random(); + let second_block = Hash::random(); + let expected_candidates: HashSet<_> = + vec![(first_block, 2), (second_block, 3)].into_iter().collect(); + + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::GetApprovalSignatures( + expected_candidates.clone(), + tx, + ), + ) + .await; + + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + let mut all_votes = HashMap::new(); + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::GetApprovalSignatures( + candidates, tx + ) + } => { + assert_eq!(candidates, expected_candidates); + let to_send: HashMap<_, _> = {0..10}.into_iter().map(|validator| { + let validator_index = ValidatorIndex(validator as u32 * num_approval_distro_workers as u32 + index as u32); + (validator_index, (first_block, vec![2, 4], dummy_signature())) + }).collect(); + tx.send(to_send.clone()).unwrap(); + all_votes.extend(to_send.clone()); + + } + ); + } + + let received_votes = rx.await.unwrap(); + assert_eq!(received_votes, all_votes); + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + + overseer + }, + ) +} + +/// Test subsystem exits with error when approval_voting_work_provider exits. +#[test] +fn test_subsystem_exits_with_error_if_approval_voting_worker_errors() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + false, + |overseer, approval_voting_work_provider, _rx_approval_distribution_workers| async move { + // Drop the approval_voting_work_provider to simulate an error. + std::mem::drop(approval_voting_work_provider); + + overseer + }, + ) +} + +/// Test subsystem exits with error when approval_distribution_workers exits. +#[test] +fn test_subsystem_exits_with_error_if_approval_distribution_worker_errors() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + false, + |overseer, _approval_voting_work_provider, rx_approval_distribution_workers| async move { + // Drop the approval_distribution_workers to simulate an error. + std::mem::drop(rx_approval_distribution_workers.into_iter().next().unwrap()); + overseer + }, + ) +} + +/// Test signals sent before messages are processed in order. +#[test] +fn test_signal_before_message_keeps_receive_order() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let signal = OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + Hash::random(), + 1, + ))); + overseer_signal(&mut overseer, signal.clone()).await; + + let validator_index = ValidatorIndex(17); + let assignment = + fake_assignment_cert_v2(Hash::random(), validator_index, CoreIndex(1).into()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeAssignment(assignment.clone(), 1.into()), + ) + .await; + + let approval_voting_receives = approval_voting_work_provider.recv().await.unwrap(); + assert_matches!(approval_voting_receives, FromOrchestra::Signal(_)); + let rx_approval_distribution_worker = rx_approval_distribution_workers + .get_mut(validator_index.0 as usize % num_approval_distro_workers) + .unwrap(); + let approval_distribution_receives = + rx_approval_distribution_worker.next().await.unwrap(); + assert_matches!(approval_distribution_receives, FromOrchestra::Signal(_)); + assert_matches!( + rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeAssignment(_, _) + } + ); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + overseer + }, + ) +} + +/// Test signals sent after messages are processed with the highest priority. +#[test] +fn test_signal_is_prioritized_when_unread_messages_in_the_queue() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let validator_index = ValidatorIndex(17); + let assignment = + fake_assignment_cert_v2(Hash::random(), validator_index, CoreIndex(1).into()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeAssignment(assignment.clone(), 1.into()), + ) + .await; + + let signal = OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + Hash::random(), + 1, + ))); + overseer_signal(&mut overseer, signal.clone()).await; + + let approval_voting_receives = approval_voting_work_provider.recv().await.unwrap(); + assert_matches!(approval_voting_receives, FromOrchestra::Signal(_)); + let rx_approval_distribution_worker = rx_approval_distribution_workers + .get_mut(validator_index.0 as usize % num_approval_distro_workers) + .unwrap(); + let approval_distribution_receives = + rx_approval_distribution_worker.next().await.unwrap(); + assert_matches!(approval_distribution_receives, FromOrchestra::Signal(_)); + assert_matches!( + rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeAssignment(_, _) + } + ); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + overseer + }, + ) +} + +/// Test peer view updates have higher priority than normal messages. +#[test] +fn test_peer_view_is_prioritized_when_unread_messages_in_the_queue() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let validator_index = ValidatorIndex(17); + let approvals = vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 2.into(), + validator: validator_index, + signature: dummy_signature(), + }, + ]; + let expected_msg = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + PeerId::random(), + expected_msg.clone(), + ), + ), + ) + .await; + + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerViewChange( + PeerId::random(), + View::default(), + ), + ), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerViewChange( + _, + _, + ), + ) + } => { + } + ); + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + _, + msg, + ), + ) + } => { + assert_eq!(msg, expected_msg); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + overseer + }, + ) +} + +// Test validator_index_for_msg with empty messages. +#[test] +fn test_validator_index_with_empty_message() { + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); +} + +// Test validator_index_for_msg when all the messages are originating from the same validator. +#[test] +fn test_validator_index_with_all_messages_from_the_same_validator() { + let validator_index = ValidatorIndex(3); + let v1_assignment = polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments(vec![ + (fake_assignment_cert(H256::random(), validator_index), 1), + (fake_assignment_cert(H256::random(), validator_index), 3), + ]), + ); + let result = validator_index_for_msg(v1_assignment.clone()); + + assert_eq!(result, (Some((validator_index, v1_assignment)), None)); + + let v1_approval = polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals(vec![ + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + ]), + ); + let result = validator_index_for_msg(v1_approval.clone()); + + assert_eq!(result, (Some((validator_index, v1_approval)), None)); + + let validator_index = ValidatorIndex(3); + let v2_assignment = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments(vec![ + (fake_assignment_cert(H256::random(), validator_index), 1), + (fake_assignment_cert(H256::random(), validator_index), 3), + ]), + ); + let result = validator_index_for_msg(v2_assignment.clone()); + + assert_eq!(result, (Some((validator_index, v2_assignment)), None)); + + let v2_approval = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals(vec![ + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + ]), + ); + let result = validator_index_for_msg(v2_approval.clone()); + + assert_eq!(result, (Some((validator_index, v2_approval)), None)); + + let validator_index = ValidatorIndex(3); + let v3_assignment = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments(vec![ + ( + fake_assignment_cert_v2(H256::random(), validator_index, CoreIndex(1).into()), + 1.into(), + ), + ( + fake_assignment_cert_v2(H256::random(), validator_index, CoreIndex(3).into()), + 3.into(), + ), + ]), + ); + let result = validator_index_for_msg(v3_assignment.clone()); + + assert_eq!(result, (Some((validator_index, v3_assignment)), None)); + + let v3_approval = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals(vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + ]), + ); + let result = validator_index_for_msg(v3_approval.clone()); + + assert_eq!(result, (Some((validator_index, v3_approval)), None)); +} + +// Test validator_index_for_msg when all the messages are originating from different validators, +// so the function should split them by validator index, so we can forward them separately to the +// worker they are assigned to. +#[test] +fn test_validator_index_with_messages_from_different_validators() { + let first_validator_index = ValidatorIndex(3); + let second_validator_index = ValidatorIndex(4); + let assignments = vec![ + (fake_assignment_cert(H256::random(), first_validator_index), 1), + (fake_assignment_cert(H256::random(), second_validator_index), 3), + ]; + let v1_assignment = polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments( + assignments.clone(), + ), + ); + let result = validator_index_for_msg(v1_assignment.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), assignments.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, assignments[index].0.validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments( + assignments.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let v2_assignment = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments( + assignments.clone(), + ), + ); + let result = validator_index_for_msg(v2_assignment.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), assignments.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, assignments[index].0.validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments( + assignments.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let first_validator_index = ValidatorIndex(3); + let second_validator_index = ValidatorIndex(4); + let v2_assignments = vec![ + ( + fake_assignment_cert_v2(H256::random(), first_validator_index, CoreIndex(1).into()), + 1.into(), + ), + ( + fake_assignment_cert_v2(H256::random(), second_validator_index, CoreIndex(3).into()), + 3.into(), + ), + ]; + + let approvals = vec![ + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: first_validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 2, + validator: second_validator_index, + signature: dummy_signature(), + }, + ]; + let v2_approvals = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + let result = validator_index_for_msg(v2_approvals.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), approvals.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, approvals[index].validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals( + approvals.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let v3_assignment = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments( + v2_assignments.clone(), + ), + ); + let result = validator_index_for_msg(v3_assignment.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), v2_assignments.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, v2_assignments[index].0.validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments( + v2_assignments.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let approvals = vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: first_validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 2.into(), + validator: second_validator_index, + signature: dummy_signature(), + }, + ]; + let v3_approvals = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + let result = validator_index_for_msg(v3_approvals.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), approvals.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, approvals[index].validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.get(index).into_iter().cloned().collect(), + ), + ) + ); + } +} diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index e678118440f5..2c3db866566c 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -29,7 +29,6 @@ polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } sc-keystore = { workspace = true } sp-consensus = { workspace = true } diff --git a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs index 0b03f1127ee8..e202d1ee229d 100644 --- a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs +++ b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs @@ -53,6 +53,7 @@ fn main() -> Result<(), String> { stop_when_approved: false, workdir_prefix: "/tmp".to_string(), num_no_shows_per_candidate: 0, + approval_voting_parallel_enabled: true, }; println!("Benchmarking..."); @@ -82,8 +83,9 @@ fn main() -> Result<(), String> { ("Sent to peers", 63995.2200, 0.01), ])); messages.extend(average_usage.check_cpu_usage(&[ - ("approval-distribution", 12.2736, 0.1), - ("approval-voting", 2.7174, 0.1), + ("approval-distribution", 0.1, 0.1), + ("approval-voting", 0.1, 0.1), + ("approval-voting-parallel", 18.0758, 0.1), ])); if messages.is_empty() { diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index bf6ea0c98149..e50a2f911489 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -28,7 +28,6 @@ //! //! We maintain a rolling window of session indices. This starts as empty -use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ approval::{ self as approval_types, @@ -320,7 +319,6 @@ pub struct BlockImportedCandidates { pub block_hash: Hash, pub block_number: BlockNumber, pub block_tick: Tick, - pub no_show_duration: Tick, pub imported_candidates: Vec<(CandidateHash, CandidateEntry)>, } @@ -349,13 +347,6 @@ pub(crate) async fn handle_new_head< finalized_number: &Option, ) -> SubsystemResult> { const MAX_HEADS_LOOK_BACK: BlockNumber = MAX_FINALITY_LAG; - let _handle_new_head_span = state - .spans - .get(&head) - .map(|span| span.child("handle-new-head")) - .unwrap_or_else(|| jaeger::Span::new(head, "handle-new-head")) - .with_string_tag("head", format!("{:?}", head)) - .with_stage(jaeger::Stage::ApprovalChecking); let header = { let (h_tx, h_rx) = oneshot::channel(); @@ -469,14 +460,7 @@ pub(crate) async fn handle_new_head< None => return Ok(Vec::new()), }; - let (block_tick, no_show_duration) = { - let block_tick = slot_number_to_tick(state.slot_duration_millis, slot); - let no_show_duration = slot_number_to_tick( - state.slot_duration_millis, - Slot::from(u64::from(session_info.no_show_slots)), - ); - (block_tick, no_show_duration) - }; + let block_tick = slot_number_to_tick(state.slot_duration_millis, slot); let needed_approvals = session_info.needed_approvals; let validator_group_lens: Vec = @@ -595,7 +579,6 @@ pub(crate) async fn handle_new_head< block_hash, block_number: block_header.number, block_tick, - no_show_duration, imported_candidates: candidate_entries .into_iter() .map(|(h, e)| (h, e.into())) @@ -675,7 +658,6 @@ pub(crate) mod tests { slot_duration_millis: 6_000, clock: Arc::new(MockClock::default()), assignment_criteria: Box::new(MockAssignmentCriteria::default()), - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 2149ce81fa80..835098293050 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -21,9 +21,6 @@ //! of others. It uses this information to determine when candidates and blocks have //! been sufficiently approved to finalize. -use itertools::Itertools; -use jaeger::{hash_to_trace_identifier, PerLeafSpan}; -use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ approval::{ v1::{BlockApprovalMeta, DelayTranche}, @@ -634,11 +631,7 @@ impl Wakeups { self.wakeups.entry(tick).or_default().push((block_hash, candidate_hash)); } - fn prune_finalized_wakeups( - &mut self, - finalized_number: BlockNumber, - spans: &mut HashMap, - ) { + fn prune_finalized_wakeups(&mut self, finalized_number: BlockNumber) { let after = self.block_numbers.split_off(&(finalized_number + 1)); let pruned_blocks: HashSet<_> = std::mem::replace(&mut self.block_numbers, after) .into_iter() @@ -662,9 +655,6 @@ impl Wakeups { } } } - - // Remove all spans that are associated with pruned blocks. - spans.retain(|h, _| !pruned_blocks.contains(h)); } // Get the wakeup for a particular block/candidate combo, if any. @@ -841,7 +831,6 @@ struct State { slot_duration_millis: u64, clock: Arc, assignment_criteria: Box, - spans: HashMap, // Per block, candidate records about how long we take until we gather enough // assignments, this is relevant because it gives us a good idea about how many // tranches we trigger and why. @@ -1203,7 +1192,6 @@ where slot_duration_millis: subsystem.slot_duration_millis, clock: subsystem.clock, assignment_criteria, - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), @@ -1525,18 +1513,8 @@ async fn handle_actions< continue } - let mut launch_approval_span = state - .spans - .get(&relay_block_hash) - .map(|span| span.child("launch-approval")) - .unwrap_or_else(|| jaeger::Span::new(candidate_hash, "launch-approval")) - .with_trace_id(candidate_hash) - .with_candidate(candidate_hash) - .with_stage(jaeger::Stage::ApprovalChecking); - metrics.on_assignment_produced(assignment_tranche); let block_hash = indirect_cert.block_hash; - launch_approval_span.add_string_tag("block-hash", format!("{:?}", block_hash)); let validator_index = indirect_cert.validator; if distribute_assignment { @@ -1580,7 +1558,6 @@ async fn handle_actions< backing_group, executor_params, core_index, - &launch_approval_span, ) .await }, @@ -1591,15 +1568,6 @@ async fn handle_actions< } }, Action::NoteApprovedInChainSelection(block_hash) => { - let _span = state - .spans - .get(&block_hash) - .map(|span| span.child("note-approved-in-chain-selection")) - .unwrap_or_else(|| { - jaeger::Span::new(block_hash, "note-approved-in-chain-selection") - }) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_stage(jaeger::Stage::ApprovalChecking); sender.send_message(ChainSelectionMessage::Approved(block_hash)).await; }, Action::BecomeActive => { @@ -1704,15 +1672,6 @@ async fn distribution_messages_for_activation b, None => { @@ -1722,9 +1681,6 @@ async fn distribution_messages_for_activation c, None => { @@ -1936,9 +1890,6 @@ async fn handle_from_overseer< let mut actions = Vec::new(); if let Some(activated) = update.activated { let head = activated.hash; - let approval_voting_span = - jaeger::PerLeafSpan::new(activated.span, "approval-voting"); - state.spans.insert(head, approval_voting_span); match import::handle_new_head( sender, approval_voting_sender, @@ -2009,7 +1960,7 @@ async fn handle_from_overseer< // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans // accordingly. - wakeups.prune_finalized_wakeups(block_number, &mut state.spans); + wakeups.prune_finalized_wakeups(block_number); state.cleanup_assignments_gathering_timestamp(block_number); // // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans @@ -2051,23 +2002,8 @@ async fn handle_from_overseer< result.0 }, ApprovalVotingMessage::ApprovedAncestor(target, lower_bound, res) => { - let mut approved_ancestor_span = state - .spans - .get(&target) - .map(|span| span.child("approved-ancestor")) - .unwrap_or_else(|| jaeger::Span::new(target, "approved-ancestor")) - .with_stage(jaeger::Stage::ApprovalChecking) - .with_string_tag("leaf", format!("{:?}", target)); - match handle_approved_ancestor( - sender, - db, - target, - lower_bound, - wakeups, - &mut approved_ancestor_span, - &metrics, - ) - .await + match handle_approved_ancestor(sender, db, target, lower_bound, wakeups, &metrics) + .await { Ok(v) => { let _ = res.send(v); @@ -2260,15 +2196,11 @@ async fn handle_approved_ancestor>( target: Hash, lower_bound: BlockNumber, wakeups: &Wakeups, - span: &mut jaeger::Span, metrics: &Metrics, ) -> SubsystemResult> { const MAX_TRACING_WINDOW: usize = 200; const ABNORMAL_DEPTH_THRESHOLD: usize = 5; const LOGGING_DEPTH_THRESHOLD: usize = 10; - let mut span = span - .child("handle-approved-ancestor") - .with_stage(jaeger::Stage::ApprovalChecking); let mut all_approved_max = None; @@ -2284,8 +2216,6 @@ async fn handle_approved_ancestor>( } }; - span.add_uint_tag("leaf-number", target_number as u64); - span.add_uint_tag("lower-bound", lower_bound as u64); if target_number <= lower_bound { return Ok(None) } @@ -2317,9 +2247,6 @@ async fn handle_approved_ancestor>( let mut bits: BitVec = Default::default(); for (i, block_hash) in std::iter::once(target).chain(ancestry).enumerate() { - let mut entry_span = - span.child("load-block-entry").with_stage(jaeger::Stage::ApprovalChecking); - entry_span.add_string_tag("block-hash", format!("{:?}", block_hash)); // Block entries should be present as the assumption is that // nothing here is finalized. If we encounter any missing block // entries we can fail. @@ -2386,7 +2313,6 @@ async fn handle_approved_ancestor>( ) } metrics.on_unapproved_candidates_in_unfinalized_chain(unapproved.len()); - entry_span.add_uint_tag("unapproved-candidates", unapproved.len() as u64); for candidate_hash in unapproved { match db.load_candidate_entry(&candidate_hash)? { None => { @@ -2507,15 +2433,6 @@ async fn handle_approved_ancestor>( number: block_number, descriptions: block_descriptions, }); - match all_approved_max { - Some(HighestApprovedAncestorBlock { ref hash, ref number, .. }) => { - span.add_uint_tag("highest-approved-number", *number as u64); - span.add_string_fmt_debug_tag("highest-approved-hash", hash); - }, - None => { - span.add_string_tag("reached-lower-bound", "true"); - }, - } Ok(all_approved_max) } @@ -2548,7 +2465,12 @@ fn schedule_wakeup_action( last_assignment_tick.map(|l| l + APPROVAL_DELAY).filter(|t| t > &tick_now), next_no_show, ) - .map(|tick| Action::ScheduleWakeup { block_hash, block_number, candidate_hash, tick }) + .map(|tick| Action::ScheduleWakeup { + block_hash, + block_number, + candidate_hash, + tick, + }) }, RequiredTranches::Pending { considered, next_no_show, clock_drift, .. } => { // select the minimum of `next_no_show`, or the tick of the next non-empty tranche @@ -2617,17 +2539,6 @@ where let assignment = checked_assignment.assignment(); let candidate_indices = checked_assignment.candidate_indices(); let tranche = checked_assignment.tranche(); - let mut import_assignment_span = state - .spans - .get(&assignment.block_hash) - .map(|span| span.child("import-assignment")) - .unwrap_or_else(|| jaeger::Span::new(assignment.block_hash, "import-assignment")) - .with_relay_parent(assignment.block_hash) - .with_stage(jaeger::Stage::ApprovalChecking); - - for candidate_index in candidate_indices.iter_ones() { - import_assignment_span.add_uint_tag("candidate-index", candidate_index as u64); - } let block_entry = match db.load_block_entry(&assignment.block_hash)? { Some(b) => b, @@ -2707,13 +2618,6 @@ where )), // no candidate at core. }; - import_assignment_span - .add_string_tag("candidate-hash", format!("{:?}", assigned_candidate_hash)); - import_assignment_span.add_string_tag( - "traceID", - format!("{:?}", jaeger::hash_to_trace_identifier(assigned_candidate_hash.0)), - ); - if candidate_entry.approval_entry_mut(&assignment.block_hash).is_none() { return Ok(( AssignmentCheckResult::Bad(AssignmentCheckError::Internal( @@ -2771,7 +2675,6 @@ where }; is_duplicate &= approval_entry.is_assigned(assignment.validator); approval_entry.import_assignment(tranche, assignment.validator, tick_now); - import_assignment_span.add_uint_tag("tranche", tranche as u64); // We've imported a new assignment, so we need to schedule a wake-up for when that might // no-show. @@ -2845,14 +2748,6 @@ where return Ok((Vec::new(), $e)) }}; } - let mut span = state - .spans - .get(&approval.block_hash) - .map(|span| span.child("import-approval")) - .unwrap_or_else(|| jaeger::Span::new(approval.block_hash, "import-approval")) - .with_string_fmt_debug_tag("candidate-index", approval.candidate_indices.clone()) - .with_relay_parent(approval.block_hash) - .with_stage(jaeger::Stage::ApprovalChecking); let block_entry = match db.load_block_entry(&approval.block_hash)? { Some(b) => b, @@ -2882,20 +2777,6 @@ where }, }; - span.add_string_tag("candidate-hashes", format!("{:?}", approved_candidates_info)); - span.add_string_tag( - "traceIDs", - format!( - "{:?}", - approved_candidates_info - .iter() - .map(|(_, approved_candidate_hash)| hash_to_trace_identifier( - approved_candidate_hash.0 - )) - .collect_vec() - ), - ); - gum::trace!( target: LOG_TARGET, "Received approval for num_candidates {:}", @@ -3250,16 +3131,6 @@ async fn process_wakeup>( metrics: &Metrics, wakeups: &Wakeups, ) -> SubsystemResult> { - let mut span = state - .spans - .get(&relay_block) - .map(|span| span.child("process-wakeup")) - .unwrap_or_else(|| jaeger::Span::new(candidate_hash, "process-wakeup")) - .with_trace_id(candidate_hash) - .with_relay_parent(relay_block) - .with_candidate(candidate_hash) - .with_stage(jaeger::Stage::ApprovalChecking); - let block_entry = db.load_block_entry(&relay_block)?; let candidate_entry = db.load_candidate_entry(&candidate_hash)?; @@ -3288,7 +3159,7 @@ async fn process_wakeup>( Slot::from(u64::from(session_info.no_show_slots)), ); let tranche_now = state.clock.tranche_now(state.slot_duration_millis, block_entry.slot()); - span.add_uint_tag("tranche", tranche_now as u64); + gum::trace!( target: LOG_TARGET, tranche = tranche_now, @@ -3451,7 +3322,6 @@ async fn launch_approval< backing_group: GroupIndex, executor_params: ExecutorParams, core_index: Option, - span: &jaeger::Span, ) -> SubsystemResult> { let (a_tx, a_rx) = oneshot::channel(); let (code_tx, code_rx) = oneshot::channel(); @@ -3485,13 +3355,6 @@ async fn launch_approval< let para_id = candidate.descriptor.para_id; gum::trace!(target: LOG_TARGET, ?candidate_hash, ?para_id, "Recovering data."); - let request_validation_data_span = span - .child("request-validation-data") - .with_trace_id(candidate_hash) - .with_candidate(candidate_hash) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_stage(jaeger::Stage::ApprovalChecking); - let timer = metrics.time_recover_and_approve(); sender .send_message(AvailabilityRecoveryMessage::RecoverAvailableData( @@ -3503,13 +3366,6 @@ async fn launch_approval< )) .await; - let request_validation_result_span = span - .child("request-validation-result") - .with_trace_id(candidate_hash) - .with_candidate(candidate_hash) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_stage(jaeger::Stage::ApprovalChecking); - sender .send_message(RuntimeApiMessage::Request( block_hash, @@ -3573,7 +3429,6 @@ async fn launch_approval< return ApprovalState::failed(validator_index, candidate_hash) }, }; - drop(request_validation_data_span); let validation_code = match code_rx.await { Err(_) => return ApprovalState::failed(validator_index, candidate_hash), @@ -3645,7 +3500,6 @@ async fn launch_approval< "Failed to validate candidate due to internal error", ); metrics_guard.take().on_approval_error(); - drop(request_validation_result_span); return ApprovalState::failed(validator_index, candidate_hash) }, } @@ -3673,17 +3527,6 @@ async fn issue_approval< ApprovalVoteRequest { validator_index, block_hash }: ApprovalVoteRequest, wakeups: &Wakeups, ) -> SubsystemResult> { - let mut issue_approval_span = state - .spans - .get(&block_hash) - .map(|span| span.child("issue-approval")) - .unwrap_or_else(|| jaeger::Span::new(block_hash, "issue-approval")) - .with_trace_id(candidate_hash) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_candidate(candidate_hash) - .with_validator_index(validator_index) - .with_stage(jaeger::Stage::ApprovalChecking); - let mut block_entry = match db.load_block_entry(&block_hash)? { Some(b) => b, None => { @@ -3708,7 +3551,6 @@ async fn issue_approval< }, Some(idx) => idx, }; - issue_approval_span.add_int_tag("candidate_index", candidate_index as i64); let candidate_hash = match block_entry.candidate(candidate_index as usize) { Some((_, h)) => *h, diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 65aa4f894c23..db5ffd441c0d 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -17,6 +17,7 @@ use self::test_helpers::mock::new_leaf; use super::*; use crate::backend::V1ReadBackend; +use itertools::Itertools; use overseer::prometheus::{ prometheus::{IntCounter, IntCounterVec}, Histogram, HistogramOpts, HistogramVec, Opts, @@ -39,7 +40,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; -use polkadot_overseer::{HeadSupportsParachains, SpawnGlue}; +use polkadot_overseer::SpawnGlue; use polkadot_primitives::{ ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, DisputeStatement, GroupIndex, Header, Id as ParaId, IndexedVec, NodeFeatures, ValidDisputeStatementKind, ValidationCode, @@ -48,7 +49,6 @@ use polkadot_primitives::{ use std::{cmp::max, time::Duration}; use assert_matches::assert_matches; -use async_trait::async_trait; use parking_lot::Mutex; use sp_keyring::sr25519::Keyring as Sr25519Keyring; use sp_keystore::Keystore; @@ -131,15 +131,6 @@ pub mod test_constants { pub(crate) const TEST_CONFIG: DatabaseConfig = DatabaseConfig { col_approval_data: DATA_COL }; } -struct MockSupportsParachains; - -#[async_trait] -impl HeadSupportsParachains for MockSupportsParachains { - async fn head_supports_parachains(&self, _head: &Hash) -> bool { - true - } -} - fn slot_to_tick(t: impl Into) -> Tick { slot_number_to_tick(SLOT_DURATION_MILLIS, t.into()) } @@ -263,7 +254,8 @@ where _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, _assignment: &polkadot_node_primitives::approval::v2::AssignmentCertV2, _backing_groups: Vec, - ) -> Result { + ) -> Result + { self.1(validator_index) } } @@ -4931,7 +4923,6 @@ fn test_gathering_assignments_statements() { slot_duration_millis: 6_000, clock: Arc::new(MockClock::default()), assignment_criteria: Box::new(MockAssignmentCriteria::check_only(|_| Ok(0))), - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), @@ -5026,7 +5017,6 @@ fn test_observe_assignment_gathering_status() { slot_duration_millis: 6_000, clock: Arc::new(MockClock::default()), assignment_criteria: Box::new(MockAssignmentCriteria::check_only(|_| Ok(0))), - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index a9732e934414..50505d733916 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -46,8 +46,8 @@ use polkadot_primitives::{ DEFAULT_LENIENT_PREPARATION_TIMEOUT, DEFAULT_PRECHECK_PREPARATION_TIMEOUT, }, AuthorityDiscoveryId, CandidateCommitments, CandidateDescriptor, CandidateEvent, - CandidateReceipt, ExecutorParams, Hash, OccupiedCoreAssumption, PersistedValidationData, - PvfExecKind, PvfPrepKind, SessionIndex, ValidationCode, ValidationCodeHash, ValidatorId, + CandidateReceipt, ExecutorParams, Hash, PersistedValidationData, PvfExecKind, PvfPrepKind, + SessionIndex, ValidationCode, ValidationCodeHash, ValidatorId, }; use sp_application_crypto::{AppCrypto, ByteArray}; use sp_keystore::KeystorePtr; @@ -83,8 +83,7 @@ const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_secs(3); const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(200); // The task queue size is chosen to be somewhat bigger than the PVF host incoming queue size -// to allow exhaustive validation messages to fall through in case the tasks are clogged with -// `ValidateFromChainState` messages awaiting data from the runtime +// to allow exhaustive validation messages to fall through in case the tasks are clogged const TASK_LIMIT: usize = 30; /// Configuration for the candidate validation subsystem @@ -155,30 +154,6 @@ where S: SubsystemSender, { match msg { - CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - .. - } => async move { - let _timer = metrics.time_validate_from_chain_state(); - let res = validate_from_chain_state( - &mut sender, - validation_host, - candidate_receipt, - pov, - executor_params, - exec_kind, - &metrics, - ) - .await; - - metrics.on_validation_event(&res); - let _ = response_sender.send(res); - } - .boxed(), CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, @@ -657,170 +632,6 @@ where } } -#[derive(Debug)] -enum AssumptionCheckOutcome { - Matches(PersistedValidationData, ValidationCode), - DoesNotMatch, - BadRequest, -} - -async fn check_assumption_validation_data( - sender: &mut Sender, - descriptor: &CandidateDescriptor, - assumption: OccupiedCoreAssumption, -) -> AssumptionCheckOutcome -where - Sender: SubsystemSender, -{ - let validation_data = { - let (tx, rx) = oneshot::channel(); - let d = runtime_api_request( - sender, - descriptor.relay_parent, - RuntimeApiRequest::PersistedValidationData(descriptor.para_id, assumption, tx), - rx, - ) - .await; - - match d { - Ok(None) | Err(RuntimeRequestFailed) => return AssumptionCheckOutcome::BadRequest, - Ok(Some(d)) => d, - } - }; - - let persisted_validation_data_hash = validation_data.hash(); - - if descriptor.persisted_validation_data_hash == persisted_validation_data_hash { - let (code_tx, code_rx) = oneshot::channel(); - let validation_code = runtime_api_request( - sender, - descriptor.relay_parent, - RuntimeApiRequest::ValidationCode(descriptor.para_id, assumption, code_tx), - code_rx, - ) - .await; - - match validation_code { - Ok(None) | Err(RuntimeRequestFailed) => AssumptionCheckOutcome::BadRequest, - Ok(Some(v)) => AssumptionCheckOutcome::Matches(validation_data, v), - } - } else { - AssumptionCheckOutcome::DoesNotMatch - } -} - -async fn find_assumed_validation_data( - sender: &mut Sender, - descriptor: &CandidateDescriptor, -) -> AssumptionCheckOutcome -where - Sender: SubsystemSender, -{ - // The candidate descriptor has a `persisted_validation_data_hash` which corresponds to - // one of up to two possible values that we can derive from the state of the - // relay-parent. We can fetch these values by getting the persisted validation data - // based on the different `OccupiedCoreAssumption`s. - - const ASSUMPTIONS: &[OccupiedCoreAssumption] = &[ - OccupiedCoreAssumption::Included, - OccupiedCoreAssumption::TimedOut, - // `TimedOut` and `Free` both don't perform any speculation and therefore should be the - // same for our purposes here. In other words, if `TimedOut` matched then the `Free` must - // be matched as well. - ]; - - // Consider running these checks in parallel to reduce validation latency. - for assumption in ASSUMPTIONS { - let outcome = check_assumption_validation_data(sender, descriptor, *assumption).await; - - match outcome { - AssumptionCheckOutcome::Matches(_, _) => return outcome, - AssumptionCheckOutcome::BadRequest => return outcome, - AssumptionCheckOutcome::DoesNotMatch => continue, - } - } - - AssumptionCheckOutcome::DoesNotMatch -} - -/// Returns validation data for a given candidate. -pub async fn find_validation_data( - sender: &mut Sender, - descriptor: &CandidateDescriptor, -) -> Result, ValidationFailed> -where - Sender: SubsystemSender, -{ - match find_assumed_validation_data(sender, &descriptor).await { - AssumptionCheckOutcome::Matches(validation_data, validation_code) => - Ok(Some((validation_data, validation_code))), - AssumptionCheckOutcome::DoesNotMatch => { - // If neither the assumption of the occupied core having the para included or the - // assumption of the occupied core timing out are valid, then the - // persisted_validation_data_hash in the descriptor is not based on the relay parent and - // is thus invalid. - Ok(None) - }, - AssumptionCheckOutcome::BadRequest => - Err(ValidationFailed("Assumption Check: Bad request".into())), - } -} - -async fn validate_from_chain_state( - sender: &mut Sender, - validation_host: ValidationHost, - candidate_receipt: CandidateReceipt, - pov: Arc, - executor_params: ExecutorParams, - exec_kind: PvfExecKind, - metrics: &Metrics, -) -> Result -where - Sender: SubsystemSender, -{ - let mut new_sender = sender.clone(); - let (validation_data, validation_code) = - match find_validation_data(&mut new_sender, &candidate_receipt.descriptor).await? { - Some((validation_data, validation_code)) => (validation_data, validation_code), - None => return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent)), - }; - - let validation_result = validate_candidate_exhaustive( - validation_host, - validation_data, - validation_code, - candidate_receipt.clone(), - pov, - executor_params, - exec_kind, - metrics, - ) - .await; - - if let Ok(ValidationResult::Valid(ref outputs, _)) = validation_result { - let (tx, rx) = oneshot::channel(); - match runtime_api_request( - sender, - candidate_receipt.descriptor.relay_parent, - RuntimeApiRequest::CheckValidationOutputs( - candidate_receipt.descriptor.para_id, - outputs.clone(), - tx, - ), - rx, - ) - .await - { - Ok(true) => {}, - Ok(false) => return Ok(ValidationResult::Invalid(InvalidCandidate::InvalidOutputs)), - Err(RuntimeRequestFailed) => - return Err(ValidationFailed("Check Validation Outputs: Bad request".into())), - } - } - - validation_result -} - async fn validate_candidate_exhaustive( mut validation_backend: impl ValidationBackend + Send, persisted_validation_data: PersistedValidationData, diff --git a/polkadot/node/core/candidate-validation/src/metrics.rs b/polkadot/node/core/candidate-validation/src/metrics.rs index 1459907aa599..76ccd56555f9 100644 --- a/polkadot/node/core/candidate-validation/src/metrics.rs +++ b/polkadot/node/core/candidate-validation/src/metrics.rs @@ -20,7 +20,6 @@ use polkadot_node_metrics::metrics::{self, prometheus}; #[derive(Clone)] pub(crate) struct MetricsInner { pub(crate) validation_requests: prometheus::CounterVec, - pub(crate) validate_from_chain_state: prometheus::Histogram, pub(crate) validate_from_exhaustive: prometheus::Histogram, pub(crate) validate_candidate_exhaustive: prometheus::Histogram, } @@ -46,13 +45,6 @@ impl Metrics { } } - /// Provide a timer for `validate_from_chain_state` which observes on drop. - pub fn time_validate_from_chain_state( - &self, - ) -> Option { - self.0.as_ref().map(|metrics| metrics.validate_from_chain_state.start_timer()) - } - /// Provide a timer for `validate_from_exhaustive` which observes on drop. pub fn time_validate_from_exhaustive( &self, @@ -83,13 +75,6 @@ impl metrics::Metrics for Metrics { )?, registry, )?, - validate_from_chain_state: prometheus::register( - prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_candidate_validation_validate_from_chain_state", - "Time spent within `candidate_validation::validate_from_chain_state`", - ))?, - registry, - )?, validate_from_exhaustive: prometheus::register( prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( "polkadot_parachain_candidate_validation_validate_from_exhaustive", diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 0dcd84bab6cf..17ca67889f6b 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -25,7 +25,8 @@ use polkadot_node_subsystem::messages::AllMessages; use polkadot_node_subsystem_util::reexports::SubsystemContext; use polkadot_overseer::ActivatedLeaf; use polkadot_primitives::{ - CoreIndex, GroupIndex, HeadData, Id as ParaId, SessionInfo, UpwardMessage, ValidatorId, + CoreIndex, GroupIndex, HeadData, Id as ParaId, OccupiedCoreAssumption, SessionInfo, + UpwardMessage, ValidatorId, }; use polkadot_primitives_test_helpers::{ dummy_collator, dummy_collator_signature, dummy_hash, make_valid_candidate_descriptor, @@ -34,6 +35,58 @@ use sp_core::{sr25519::Public, testing::TaskExecutor}; use sp_keyring::Sr25519Keyring; use sp_keystore::{testing::MemoryKeystore, Keystore}; +#[derive(Debug)] +enum AssumptionCheckOutcome { + Matches(PersistedValidationData, ValidationCode), + DoesNotMatch, + BadRequest, +} + +async fn check_assumption_validation_data( + sender: &mut Sender, + descriptor: &CandidateDescriptor, + assumption: OccupiedCoreAssumption, +) -> AssumptionCheckOutcome +where + Sender: SubsystemSender, +{ + let validation_data = { + let (tx, rx) = oneshot::channel(); + let d = runtime_api_request( + sender, + descriptor.relay_parent, + RuntimeApiRequest::PersistedValidationData(descriptor.para_id, assumption, tx), + rx, + ) + .await; + + match d { + Ok(None) | Err(RuntimeRequestFailed) => return AssumptionCheckOutcome::BadRequest, + Ok(Some(d)) => d, + } + }; + + let persisted_validation_data_hash = validation_data.hash(); + + if descriptor.persisted_validation_data_hash == persisted_validation_data_hash { + let (code_tx, code_rx) = oneshot::channel(); + let validation_code = runtime_api_request( + sender, + descriptor.relay_parent, + RuntimeApiRequest::ValidationCode(descriptor.para_id, assumption, code_tx), + code_rx, + ) + .await; + + match validation_code { + Ok(None) | Err(RuntimeRequestFailed) => AssumptionCheckOutcome::BadRequest, + Ok(Some(v)) => AssumptionCheckOutcome::Matches(validation_data, v), + } + } else { + AssumptionCheckOutcome::DoesNotMatch + } +} + #[test] fn correctly_checks_included_assumption() { let validation_data: PersistedValidationData = Default::default(); diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 5096fe5e6891..9cf9047b7273 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -34,8 +34,9 @@ use polkadot_node_primitives::{ }; use polkadot_node_subsystem::{ messages::{ - ApprovalVotingMessage, BlockDescription, ChainSelectionMessage, DisputeCoordinatorMessage, - DisputeDistributionMessage, ImportStatementsResult, + ApprovalVotingMessage, ApprovalVotingParallelMessage, BlockDescription, + ChainSelectionMessage, DisputeCoordinatorMessage, DisputeDistributionMessage, + ImportStatementsResult, }, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, }; @@ -117,6 +118,7 @@ pub(crate) struct Initialized { /// `CHAIN_IMPORT_MAX_BATCH_SIZE` and put the rest here for later processing. chain_import_backlog: VecDeque, metrics: Metrics, + approval_voting_parallel_enabled: bool, } #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)] @@ -130,7 +132,13 @@ impl Initialized { highest_session_seen: SessionIndex, gaps_in_cache: bool, ) -> Self { - let DisputeCoordinatorSubsystem { config: _, store: _, keystore, metrics } = subsystem; + let DisputeCoordinatorSubsystem { + config: _, + store: _, + keystore, + metrics, + approval_voting_parallel_enabled, + } = subsystem; let (participation_sender, participation_receiver) = mpsc::channel(1); let participation = Participation::new(participation_sender, metrics.clone()); @@ -148,6 +156,7 @@ impl Initialized { participation_receiver, chain_import_backlog: VecDeque::new(), metrics, + approval_voting_parallel_enabled, } } @@ -1059,9 +1068,21 @@ impl Initialized { // 4. We are waiting (and blocking the whole subsystem) on a response right after - // therefore even with all else failing we will never have more than // one message in flight at any given time. - ctx.send_unbounded_message( - ApprovalVotingMessage::GetApprovalSignaturesForCandidate(candidate_hash, tx), - ); + if self.approval_voting_parallel_enabled { + ctx.send_unbounded_message( + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate( + candidate_hash, + tx, + ), + ); + } else { + ctx.send_unbounded_message( + ApprovalVotingMessage::GetApprovalSignaturesForCandidate( + candidate_hash, + tx, + ), + ); + } match rx.await { Err(_) => { gum::warn!( diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index 34d9ddf3a97c..84408eb96305 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -122,6 +122,7 @@ pub struct DisputeCoordinatorSubsystem { store: Arc, keystore: Arc, metrics: Metrics, + approval_voting_parallel_enabled: bool, } /// Configuration for the dispute coordinator subsystem. @@ -164,8 +165,9 @@ impl DisputeCoordinatorSubsystem { config: Config, keystore: Arc, metrics: Metrics, + approval_voting_parallel_enabled: bool, ) -> Self { - Self { store, config, keystore, metrics } + Self { store, config, keystore, metrics, approval_voting_parallel_enabled } } /// Initialize and afterwards run `Initialized::run`. diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index f97a625a9528..b41cdb94b4d2 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -580,6 +580,7 @@ impl TestState { self.config, self.subsystem_keystore.clone(), Metrics::default(), + false, ); let backend = DbBackend::new(self.db.clone(), self.config.column_config(), Metrics::default()); diff --git a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs index 9886d19e5224..3332cbeb03cb 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs @@ -1433,7 +1433,7 @@ fn test_find_ancestor_path_and_find_backable_chain() { // Now back all candidates. Back them in a random order. The result should always be the same. let mut candidates_shuffled = candidates.clone(); candidates_shuffled.shuffle(&mut thread_rng()); - for candidate in candidates.iter() { + for candidate in candidates_shuffled.iter() { chain.candidate_backed(candidate); storage.mark_backed(candidate); } diff --git a/polkadot/node/core/pvf/build.rs b/polkadot/node/core/pvf/build.rs index e01cc6deecc2..e46f2dc5f55a 100644 --- a/polkadot/node/core/pvf/build.rs +++ b/polkadot/node/core/pvf/build.rs @@ -16,6 +16,6 @@ fn main() { if let Ok(profile) = std::env::var("PROFILE") { - println!(r#"cargo:rustc-cfg=build_type="{}""#, profile); + println!(r#"cargo:rustc-cfg=build_profile="{}""#, profile); } } diff --git a/polkadot/node/core/pvf/common/src/worker/security/change_root.rs b/polkadot/node/core/pvf/common/src/worker/security/change_root.rs index 9ec66906819f..fcfaf6541c29 100644 --- a/polkadot/node/core/pvf/common/src/worker/security/change_root.rs +++ b/polkadot/node/core/pvf/common/src/worker/security/change_root.rs @@ -124,7 +124,8 @@ fn try_restrict(worker_info: &WorkerInfo) -> Result<()> { libc::MS_BIND | libc::MS_REC | libc::MS_NOEXEC | libc::MS_NODEV | libc::MS_NOSUID | - libc::MS_NOATIME | additional_flags, + libc::MS_NOATIME | + additional_flags, ptr::null(), // ignored when MS_BIND is used ) < 0 { diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 119af34082a9..1126a0c90c8c 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -56,7 +56,7 @@ use crate::{host::PrecheckResultSender, worker_interface::WORKER_DIR_PREFIX}; use always_assert::always; -use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData}; +use polkadot_node_core_pvf_common::{error::PrepareError, pvf::PvfPrepData}; use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParamsPrepHash; use std::{ @@ -144,8 +144,6 @@ pub enum ArtifactState { last_time_needed: SystemTime, /// Size in bytes size: u64, - /// Stats produced by successful preparation. - prepare_stats: PrepareStats, }, /// A task to prepare this artifact is scheduled. Preparing { @@ -269,15 +267,11 @@ impl Artifacts { path: PathBuf, last_time_needed: SystemTime, size: u64, - prepare_stats: PrepareStats, ) { // See the precondition. always!(self .inner - .insert( - artifact_id, - ArtifactState::Prepared { path, last_time_needed, size, prepare_stats } - ) + .insert(artifact_id, ArtifactState::Prepared { path, last_time_needed, size }) .is_none()); } @@ -384,21 +378,18 @@ mod tests { path1.clone(), mock_now - Duration::from_secs(5), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id2.clone(), path2.clone(), mock_now - Duration::from_secs(10), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id3.clone(), path3.clone(), mock_now - Duration::from_secs(15), 1024, - PrepareStats::default(), ); let pruned = artifacts.prune(&cleanup_config); @@ -432,21 +423,18 @@ mod tests { path1.clone(), mock_now - Duration::from_secs(5), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id2.clone(), path2.clone(), mock_now - Duration::from_secs(10), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id3.clone(), path3.clone(), mock_now - Duration::from_secs(15), 1024, - PrepareStats::default(), ); let pruned = artifacts.prune(&cleanup_config); diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 44a4cba2fbf8..22943a06c43c 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -813,12 +813,8 @@ async fn handle_prepare_done( } *state = match result { - Ok(PrepareSuccess { path, stats: prepare_stats, size }) => ArtifactState::Prepared { - path, - last_time_needed: SystemTime::now(), - size, - prepare_stats, - }, + Ok(PrepareSuccess { path, size, .. }) => + ArtifactState::Prepared { path, last_time_needed: SystemTime::now(), size }, Err(error) => { let last_time_failed = SystemTime::now(); let num_failures = *num_failures + 1; @@ -976,7 +972,6 @@ pub(crate) mod tests { use crate::{artifacts::generate_artifact_path, testing::artifact_id, PossiblyInvalidError}; use assert_matches::assert_matches; use futures::future::BoxFuture; - use polkadot_node_core_pvf_common::prepare::PrepareStats; use polkadot_node_primitives::BlockData; use sp_core::H256; @@ -1196,20 +1191,8 @@ pub(crate) mod tests { builder.cleanup_config = ArtifactsCleanupConfig::new(1024, Duration::from_secs(0)); let path1 = generate_artifact_path(cache_path); let path2 = generate_artifact_path(cache_path); - builder.artifacts.insert_prepared( - artifact_id(1), - path1.clone(), - mock_now, - 1024, - PrepareStats::default(), - ); - builder.artifacts.insert_prepared( - artifact_id(2), - path2.clone(), - mock_now, - 1024, - PrepareStats::default(), - ); + builder.artifacts.insert_prepared(artifact_id(1), path1.clone(), mock_now, 1024); + builder.artifacts.insert_prepared(artifact_id(2), path2.clone(), mock_now, 1024); let mut test = builder.build(); let mut host = test.host_handle(); diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 4e11f977c9e7..67cd71812e52 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -343,14 +343,13 @@ fn handle_mux( ), // Return `Concluded`, but do not kill the worker since the error was on the host // side. - Outcome::RenameTmpFile { worker: idle, result: _, err, src, dest } => - handle_concluded_no_rip( - from_pool, - spawned, - worker, - idle, - Err(PrepareError::RenameTmpFile { err, src, dest }), - ), + Outcome::RenameTmpFile { worker: idle, err, src, dest } => handle_concluded_no_rip( + from_pool, + spawned, + worker, + idle, + Err(PrepareError::RenameTmpFile { err, src, dest }), + ), // Could not clear worker cache. Kill the worker so other jobs can't see the data. Outcome::ClearWorkerDir { err } => { if attempt_retire(metrics, spawned, worker) { diff --git a/polkadot/node/core/pvf/src/prepare/worker_interface.rs b/polkadot/node/core/pvf/src/prepare/worker_interface.rs index d29d2717c4b6..718416e8be76 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_interface.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_interface.rs @@ -81,7 +81,6 @@ pub enum Outcome { /// final destination location. RenameTmpFile { worker: IdleWorker, - result: PrepareWorkerResult, err: String, // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible // conversion to `Option`. @@ -287,7 +286,6 @@ async fn handle_response( ); Outcome::RenameTmpFile { worker, - result, err: format!("{:?}", err), src: tmp_file.to_str().map(String::from), dest: artifact_path.to_str().map(String::from), diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 8c75dafa69c2..9a4004f39037 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -72,7 +72,7 @@ pub fn build_workers_and_get_paths() -> (PathBuf, PathBuf) { "--bin=polkadot-execute-worker", ]; - if cfg!(build_type = "release") { + if cfg!(build_profile = "release") { build_args.push("--release"); } diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index 90a6c80e3d0b..8615041bdaff 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -11,7 +11,6 @@ workspace = true [dependencies] mick-jaeger = { workspace = true } -lazy_static = { workspace = true } parking_lot = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } diff --git a/polkadot/node/jaeger/src/lib.rs b/polkadot/node/jaeger/src/lib.rs index 7de458606816..2ce5b8b6eb6d 100644 --- a/polkadot/node/jaeger/src/lib.rs +++ b/polkadot/node/jaeger/src/lib.rs @@ -61,11 +61,12 @@ use self::spans::TraceIdentifier; use sp_core::traits::SpawnNamed; use parking_lot::RwLock; -use std::{result, sync::Arc}; +use std::{ + result, + sync::{Arc, LazyLock}, +}; -lazy_static::lazy_static! { - static ref INSTANCE: RwLock = RwLock::new(Jaeger::None); -} +static INSTANCE: LazyLock> = LazyLock::new(|| RwLock::new(Jaeger::None)); /// Stateful convenience wrapper around [`mick_jaeger`]. pub enum Jaeger { diff --git a/polkadot/node/malus/src/variants/back_garbage_candidate.rs b/polkadot/node/malus/src/variants/back_garbage_candidate.rs index b939a2151e23..d6f1353a46a8 100644 --- a/polkadot/node/malus/src/variants/back_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/back_garbage_candidate.rs @@ -67,12 +67,10 @@ impl OverseerGen for BackGarbageCandidates { RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { - let spawner = args.spawner.clone(); let validation_filter = ReplaceValidationResult::new( FakeCandidateValidation::BackingAndApprovalValid, FakeCandidateValidationError::InvalidOutputs, f64::from(self.percentage), - SpawnGlue(spawner), ); validator_overseer_builder( diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index eb6988f81811..50a5af63db44 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -21,7 +21,6 @@ use crate::{ shared::{MALICIOUS_POV, MALUS}, }; -use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; use polkadot_primitives::{ @@ -149,59 +148,21 @@ impl Into for FakeCandidateValidationError { #[derive(Clone, Debug)] /// An interceptor which fakes validation result with a preconfigured result. /// Replaces `CandidateValidationSubsystem`. -pub struct ReplaceValidationResult { +pub struct ReplaceValidationResult { fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, distribution: Bernoulli, - spawner: Spawner, } -impl ReplaceValidationResult -where - Spawner: overseer::gen::Spawner, -{ +impl ReplaceValidationResult { pub fn new( fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, percentage: f64, - spawner: Spawner, ) -> Self { let distribution = Bernoulli::new(percentage / 100.0) .expect("Invalid probability! Percentage must be in range [0..=100]."); - Self { fake_validation, fake_validation_error, distribution, spawner } - } - - /// Creates and sends the validation response for a given candidate. Queries the runtime to - /// obtain the validation data for the given candidate. - pub fn send_validation_response( - &self, - candidate_descriptor: CandidateDescriptor, - subsystem_sender: Sender, - response_sender: oneshot::Sender>, - ) where - Sender: overseer::CandidateValidationSenderTrait + Clone + Send + 'static, - { - let _candidate_descriptor = candidate_descriptor.clone(); - let mut subsystem_sender = subsystem_sender.clone(); - let (sender, receiver) = std::sync::mpsc::channel(); - self.spawner.spawn_blocking( - "malus-get-validation-data", - Some("malus"), - Box::pin(async move { - match find_validation_data(&mut subsystem_sender, &_candidate_descriptor).await { - Ok(Some((validation_data, validation_code))) => { - sender - .send((validation_data, validation_code)) - .expect("channel is still open"); - }, - _ => { - panic!("Unable to fetch validation data"); - }, - } - }), - ); - let (validation_data, _) = receiver.recv().unwrap(); - create_validation_response(validation_data, candidate_descriptor, response_sender); + Self { fake_validation, fake_validation_error, distribution } } } @@ -251,10 +212,9 @@ fn create_validation_response( response_sender.send(result).unwrap(); } -impl MessageInterceptor for ReplaceValidationResult +impl MessageInterceptor for ReplaceValidationResult where Sender: overseer::CandidateValidationSenderTrait + Clone + Send + 'static, - Spawner: overseer::gen::Spawner + Clone + 'static, { type Message = CandidateValidationMessage; @@ -262,7 +222,7 @@ where // configuration fail them. fn intercept_incoming( &self, - subsystem_sender: &mut Sender, + _subsystem_sender: &mut Sender, msg: FromOrchestra, ) -> Option> { match msg { @@ -343,7 +303,7 @@ where match behave_maliciously { true => { let validation_result = - ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + ValidationResult::Invalid(self.fake_validation_error.into()); gum::info!( target: MALUS, @@ -390,109 +350,6 @@ where }), } }, - // Behaviour related to the backing subsystem - FromOrchestra::Communication { - msg: - CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - .. - }, - } => { - match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(exec_kind) => { - // Behave normally if the `PoV` is not known to be malicious. - if pov.block_data.0.as_slice() != MALICIOUS_POV { - return Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }) - } - // If the `PoV` is malicious, back the candidate with some probability `p`, - // where 'p' defaults to 100% for suggest-garbage-candidate variant. - let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); - match behave_maliciously { - true => { - gum::info!( - target: MALUS, - ?behave_maliciously, - "😈 Backing candidate with malicious PoV.", - ); - - self.send_validation_response( - candidate_receipt.descriptor, - subsystem_sender.clone(), - response_sender, - ); - None - }, - // If the `PoV` is malicious, we behave normally with some probability - // `(1-p)` - false => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }), - } - }, - x if x.misbehaves_invalid() && x.should_misbehave(exec_kind) => { - // Maliciously set the validation result to invalid for a valid candidate - // with probability `p` - let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); - match behave_maliciously { - true => { - let validation_result = - ValidationResult::Invalid(self.fake_validation_error.into()); - gum::info!( - target: MALUS, - para_id = ?candidate_receipt.descriptor.para_id, - "😈 Maliciously sending invalid validation result: {:?}.", - &validation_result, - ); - // We're not even checking the candidate, this makes us appear - // faster than honest validators. - response_sender.send(Ok(validation_result)).unwrap(); - None - }, - // With some probability `(1-p)` we behave normally - false => { - gum::info!(target: MALUS, "😈 'Decided' to not act maliciously.",); - - Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }) - }, - } - }, - _ => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }), - } - }, msg => Some(msg), } } diff --git a/polkadot/node/malus/src/variants/dispute_valid_candidates.rs b/polkadot/node/malus/src/variants/dispute_valid_candidates.rs index a50fdce16e4e..5422167545ce 100644 --- a/polkadot/node/malus/src/variants/dispute_valid_candidates.rs +++ b/polkadot/node/malus/src/variants/dispute_valid_candidates.rs @@ -84,12 +84,10 @@ impl OverseerGen for DisputeValidCandidates { RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { - let spawner = args.spawner.clone(); let validation_filter = ReplaceValidationResult::new( self.fake_validation, self.fake_validation_error, f64::from(self.percentage), - SpawnGlue(spawner.clone()), ); validator_overseer_builder( diff --git a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs index 6921352cdfc2..ab2d380fbaf4 100644 --- a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs @@ -315,7 +315,6 @@ impl OverseerGen for SuggestGarbageCandidates { FakeCandidateValidation::BackingAndApprovalValid, FakeCandidateValidationError::InvalidOutputs, fake_valid_probability, - SpawnGlue(args.spawner.clone()), ); validator_overseer_builder( diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 51478dfa4a4f..8d674a733470 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -16,7 +16,6 @@ polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } itertools = { workspace = true } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index 971b6de5f8f6..876cc59b9c28 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -27,7 +27,6 @@ use self::metrics::Metrics; use futures::{select, FutureExt as _}; use itertools::Itertools; use net_protocol::peer_set::{ProtocolVersion, ValidationVersion}; -use polkadot_node_jaeger as jaeger; use polkadot_node_network_protocol::{ self as net_protocol, filter_by_peer_version, grid_topology::{RandomRouting, RequiredRouting, SessionGridTopologies, SessionGridTopology}, @@ -73,7 +72,8 @@ use std::{ time::Duration, }; -mod metrics; +/// Approval distribution metrics. +pub mod metrics; #[cfg(test)] mod tests; @@ -99,7 +99,7 @@ const MAX_BITFIELD_SIZE: usize = 500; pub struct ApprovalDistribution { metrics: Metrics, slot_duration_millis: u64, - clock: Box, + clock: Arc, assignment_criteria: Arc, } @@ -358,9 +358,6 @@ pub struct State { /// Tracks recently finalized blocks. recent_outdated_blocks: RecentlyOutdated, - /// HashMap from active leaves to spans - spans: HashMap, - /// Aggression configuration. aggression_config: AggressionConfig, @@ -871,18 +868,9 @@ impl State { ); for meta in metas { - let mut span = self - .spans - .get(&meta.hash) - .map(|span| span.child(&"handle-new-blocks")) - .unwrap_or_else(|| jaeger::Span::new(meta.hash, &"handle-new-blocks")) - .with_string_tag("block-hash", format!("{:?}", meta.hash)) - .with_stage(jaeger::Stage::ApprovalDistribution); - match self.blocks.entry(meta.hash) { hash_map::Entry::Vacant(entry) => { let candidates_count = meta.candidates.len(); - span.add_uint_tag("candidates-count", candidates_count as u64); let mut candidates = Vec::with_capacity(candidates_count); candidates.resize_with(candidates_count, Default::default); @@ -1329,7 +1317,6 @@ impl State { if let Some(block_entry) = self.blocks.remove(relay_block) { self.topologies.dec_session_refs(block_entry.session); } - self.spans.remove(&relay_block); }); // If a block was finalized, this means we may need to move our aggression @@ -1356,21 +1343,6 @@ impl State { RA: overseer::SubsystemSender, R: CryptoRng + Rng, { - let _span = self - .spans - .get(&assignment.block_hash) - .map(|span| { - span.child(if source.peer_id().is_some() { - "peer-import-and-distribute-assignment" - } else { - "local-import-and-distribute-assignment" - }) - }) - .unwrap_or_else(|| jaeger::Span::new(&assignment.block_hash, "distribute-assignment")) - .with_string_tag("block-hash", format!("{:?}", assignment.block_hash)) - .with_optional_peer_id(source.peer_id().as_ref()) - .with_stage(jaeger::Stage::ApprovalDistribution); - let block_hash = assignment.block_hash; let validator_index = assignment.validator; @@ -1836,21 +1808,6 @@ impl State { vote: IndirectSignedApprovalVoteV2, session_info_provider: &mut RuntimeInfo, ) { - let _span = self - .spans - .get(&vote.block_hash) - .map(|span| { - span.child(if source.peer_id().is_some() { - "peer-import-and-distribute-approval" - } else { - "local-import-and-distribute-approval" - }) - }) - .unwrap_or_else(|| jaeger::Span::new(&vote.block_hash, "distribute-approval")) - .with_string_tag("block-hash", format!("{:?}", vote.block_hash)) - .with_optional_peer_id(source.peer_id().as_ref()) - .with_stage(jaeger::Stage::ApprovalDistribution); - let block_hash = vote.block_hash; let validator_index = vote.validator; let candidate_indices = &vote.candidate_indices; @@ -2090,14 +2047,6 @@ impl State { ) -> HashMap, ValidatorSignature)> { let mut all_sigs = HashMap::new(); for (hash, index) in indices { - let _span = self - .spans - .get(&hash) - .map(|span| span.child("get-approval-signatures")) - .unwrap_or_else(|| jaeger::Span::new(&hash, "get-approval-signatures")) - .with_string_tag("block-hash", format!("{:?}", hash)) - .with_stage(jaeger::Stage::ApprovalDistribution); - let block_entry = match self.blocks.get(&hash) { None => { gum::debug!( @@ -2668,7 +2617,7 @@ impl ApprovalDistribution { Self::new_with_clock( metrics, slot_duration_millis, - Box::new(SystemClock), + Arc::new(SystemClock), assignment_criteria, ) } @@ -2677,7 +2626,7 @@ impl ApprovalDistribution { pub fn new_with_clock( metrics: Metrics, slot_duration_millis: u64, - clock: Box, + clock: Arc, assignment_criteria: Arc, ) -> Self { Self { metrics, slot_duration_millis, clock, assignment_criteria } @@ -2775,18 +2724,12 @@ impl ApprovalDistribution { session_info_provider, ) .await, - FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { + FromOrchestra::Signal(OverseerSignal::ActiveLeaves(_update)) => { gum::trace!(target: LOG_TARGET, "active leaves signal (ignored)"); // the relay chain blocks relevant to the approval subsystems // are those that are available, but not finalized yet // activated and deactivated heads hence are irrelevant to this subsystem, other // than for tracing purposes. - if let Some(activated) = update.activated { - let head = activated.hash; - let approval_distribution_span = - jaeger::PerLeafSpan::new(activated.span, "approval-distribution"); - state.spans.insert(head, approval_distribution_span); - } }, FromOrchestra::Signal(OverseerSignal::BlockFinalized(_hash, number)) => { gum::trace!(target: LOG_TARGET, number = %number, "finalized signal"); @@ -2845,14 +2788,6 @@ impl ApprovalDistribution { .await; }, ApprovalDistributionMessage::DistributeAssignment(cert, candidate_indices) => { - let _span = state - .spans - .get(&cert.block_hash) - .map(|span| span.child("import-and-distribute-assignment")) - .unwrap_or_else(|| jaeger::Span::new(&cert.block_hash, "distribute-assignment")) - .with_string_tag("block-hash", format!("{:?}", cert.block_hash)) - .with_stage(jaeger::Stage::ApprovalDistribution); - gum::debug!( target: LOG_TARGET, ?candidate_indices, diff --git a/polkadot/node/network/approval-distribution/src/metrics.rs b/polkadot/node/network/approval-distribution/src/metrics.rs index 10553c352966..2f677ba415e4 100644 --- a/polkadot/node/network/approval-distribution/src/metrics.rs +++ b/polkadot/node/network/approval-distribution/src/metrics.rs @@ -79,31 +79,19 @@ impl Metrics { .map(|metrics| metrics.time_import_pending_now_known.start_timer()) } - pub fn on_approval_already_known(&self) { - if let Some(metrics) = &self.0 { - metrics.approvals_received_result.with_label_values(&["known"]).inc() - } - } - - pub fn on_approval_entry_not_found(&self) { - if let Some(metrics) = &self.0 { - metrics.approvals_received_result.with_label_values(&["noapprovalentry"]).inc() - } - } - - pub fn on_approval_recent_outdated(&self) { + pub(crate) fn on_approval_recent_outdated(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["outdated"]).inc() } } - pub fn on_approval_invalid_block(&self) { + pub(crate) fn on_approval_invalid_block(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["invalidblock"]).inc() } } - pub fn on_approval_unknown_assignment(&self) { + pub(crate) fn on_approval_unknown_assignment(&self) { if let Some(metrics) = &self.0 { metrics .approvals_received_result @@ -112,94 +100,73 @@ impl Metrics { } } - pub fn on_approval_duplicate(&self) { + pub(crate) fn on_approval_duplicate(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["duplicate"]).inc() } } - pub fn on_approval_out_of_view(&self) { + pub(crate) fn on_approval_out_of_view(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["outofview"]).inc() } } - pub fn on_approval_good_known(&self) { + pub(crate) fn on_approval_good_known(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["goodknown"]).inc() } } - pub fn on_approval_bad(&self) { + pub(crate) fn on_approval_bad(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["bad"]).inc() } } - pub fn on_approval_unexpected(&self) { - if let Some(metrics) = &self.0 { - metrics.approvals_received_result.with_label_values(&["unexpected"]).inc() - } - } - - pub fn on_approval_bug(&self) { + pub(crate) fn on_approval_bug(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["bug"]).inc() } } - pub fn on_assignment_already_known(&self) { - if let Some(metrics) = &self.0 { - metrics.assignments_received_result.with_label_values(&["known"]).inc() - } - } - - pub fn on_assignment_recent_outdated(&self) { + pub(crate) fn on_assignment_recent_outdated(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["outdated"]).inc() } } - pub fn on_assignment_invalid_block(&self) { + pub(crate) fn on_assignment_invalid_block(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["invalidblock"]).inc() } } - pub fn on_assignment_duplicate(&self) { + pub(crate) fn on_assignment_duplicate(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["duplicate"]).inc() } } - pub fn on_assignment_out_of_view(&self) { + pub(crate) fn on_assignment_out_of_view(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["outofview"]).inc() } } - pub fn on_assignment_good_known(&self) { + pub(crate) fn on_assignment_good_known(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["goodknown"]).inc() } } - pub fn on_assignment_bad(&self) { + pub(crate) fn on_assignment_bad(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["bad"]).inc() } } - pub fn on_assignment_duplicatevoting(&self) { - if let Some(metrics) = &self.0 { - metrics - .assignments_received_result - .with_label_values(&["duplicatevoting"]) - .inc() - } - } - - pub fn on_assignment_far(&self) { + pub(crate) fn on_assignment_far(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["far"]).inc() } diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 4ee9320e0e45..063e71f2f528 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -54,7 +54,7 @@ type VirtualOverseer = fn test_harness>( assignment_criteria: Arc, - clock: Box, + clock: Arc, mut state: State, test_fn: impl FnOnce(VirtualOverseer) -> T, ) -> State { @@ -535,7 +535,8 @@ impl AssignmentCriteria for MockAssignmentCriteria { _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, _assignment: &polkadot_node_primitives::approval::v2::AssignmentCertV2, _backing_groups: Vec, - ) -> Result { + ) -> Result + { self.tranche } } @@ -555,16 +556,15 @@ fn try_import_the_same_assignment() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; - // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; - // Set up a gossip topology, where a, b, c and d are topology neighbors to the node // under testing. let peers_with_optional_peer_id = peers .iter() @@ -661,7 +661,7 @@ fn try_import_the_same_assignment_v2() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -772,7 +772,7 @@ fn delay_reputation_change() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_with_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -845,7 +845,7 @@ fn spam_attack_results_in_negative_reputation_change() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -942,7 +942,7 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1043,7 +1043,7 @@ fn import_approval_happy_path_v1_v2_peers() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1183,7 +1183,7 @@ fn import_approval_happy_path_v2() { let candidate_hash_second = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xCC)); let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1314,7 +1314,7 @@ fn multiple_assignments_covered_with_one_approval_vote() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1524,7 +1524,7 @@ fn unify_with_peer_multiple_assignments_covered_with_one_approval_vote() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1723,7 +1723,7 @@ fn import_approval_bad() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1810,7 +1810,7 @@ fn update_our_view() { let state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1858,7 +1858,7 @@ fn update_our_view() { let state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1877,7 +1877,7 @@ fn update_our_view() { let state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -1905,7 +1905,7 @@ fn update_peer_view() { let state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2004,7 +2004,7 @@ fn update_peer_view() { let state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2064,7 +2064,7 @@ fn update_peer_view() { let finalized_number = 4_000_000_000; let state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2106,7 +2106,7 @@ fn update_peer_authority_id() { let _state = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2287,7 +2287,7 @@ fn import_remotely_then_locally() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2393,7 +2393,7 @@ fn sends_assignments_even_when_state_is_approved() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2499,7 +2499,7 @@ fn sends_assignments_even_when_state_is_approved_v2() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2625,7 +2625,7 @@ fn race_condition_in_local_vs_remote_view_update() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2711,7 +2711,7 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2841,7 +2841,7 @@ fn propagates_assignments_along_unshared_dimension() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3000,7 +3000,7 @@ fn propagates_to_required_after_connect() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3165,7 +3165,7 @@ fn sends_to_more_peers_after_getting_topology() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), State::default(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3303,7 +3303,7 @@ fn originator_aggression_l1() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3484,7 +3484,7 @@ fn non_originator_aggression_l1() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3609,7 +3609,7 @@ fn non_originator_aggression_l2() { let aggression_l2_threshold = state.aggression_config.l2_threshold.unwrap(); let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3794,7 +3794,7 @@ fn resends_messages_periodically() { state.aggression_config.resend_unfinalized_period = Some(2); let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -3958,7 +3958,7 @@ fn import_versioned_approval() { let candidate_hash = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -4131,7 +4131,7 @@ fn batch_test_round(message_count: usize) { let subsystem = ApprovalDistribution::new_with_clock( Default::default(), Default::default(), - Box::new(SystemClock {}), + Arc::new(SystemClock {}), Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), ); let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(12345); @@ -4318,7 +4318,7 @@ fn subsystem_rejects_assignment_in_future() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(89) }), - Box::new(DummyClock {}), + Arc::new(DummyClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -4384,7 +4384,7 @@ fn subsystem_rejects_bad_assignments() { Arc::new(MockAssignmentCriteria { tranche: Err(InvalidAssignment(criteria::InvalidAssignmentReason::NullAssignment)), }), - Box::new(DummyClock {}), + Arc::new(DummyClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -4447,7 +4447,7 @@ fn subsystem_rejects_wrong_claimed_assignments() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(DummyClock {}), + Arc::new(DummyClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -4531,7 +4531,7 @@ fn subsystem_accepts_tranche0_duplicate_assignments() { let _ = test_harness( Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), - Box::new(DummyClock {}), + Arc::new(DummyClock {}), state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; diff --git a/polkadot/node/network/availability-distribution/src/tests/mod.rs b/polkadot/node/network/availability-distribution/src/tests/mod.rs index 3320871bceb5..078220607c37 100644 --- a/polkadot/node/network/availability-distribution/src/tests/mod.rs +++ b/polkadot/node/network/availability-distribution/src/tests/mod.rs @@ -45,7 +45,7 @@ fn test_harness>( let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool.clone()); - let (pov_req_receiver, pov_req_cfg) = IncomingRequest::get_config_receiver::< + let (pov_req_receiver, _pov_req_cfg) = IncomingRequest::get_config_receiver::< Block, sc_network::NetworkWorker, >(&req_protocol_names); @@ -65,13 +65,8 @@ fn test_harness>( ); let subsystem = subsystem.run(context); - let test_fut = test_fx(TestHarness { - virtual_overseer, - pov_req_cfg, - chunk_req_v1_cfg, - chunk_req_v2_cfg, - pool, - }); + let test_fut = + test_fx(TestHarness { virtual_overseer, chunk_req_v1_cfg, chunk_req_v2_cfg, pool }); futures::pin_mut!(test_fut); futures::pin_mut!(subsystem); diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 97e616f79fb7..53d6fd2c530f 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -60,7 +60,6 @@ type VirtualOverseer = polkadot_node_subsystem_test_helpers::TestSubsystemContex >; pub struct TestHarness { pub virtual_overseer: VirtualOverseer, - pub pov_req_cfg: RequestResponseConfig, pub chunk_req_v1_cfg: RequestResponseConfig, pub chunk_req_v2_cfg: RequestResponseConfig, pub pool: TaskExecutor, diff --git a/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs b/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs index b6376a5b543e..6b34538b6266 100644 --- a/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs +++ b/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs @@ -107,9 +107,10 @@ impl FetchChunks { state: &mut State, common_params: &RecoveryParams, ) -> Result { - let recovery_duration = common_params - .metrics - .time_erasure_recovery(RecoveryStrategy::::strategy_type(self)); + let recovery_duration = + common_params + .metrics + .time_erasure_recovery(RecoveryStrategy::::strategy_type(self)); // Send request to reconstruct available data from chunks. let (avilable_data_tx, available_data_rx) = oneshot::channel(); @@ -136,18 +137,16 @@ impl FetchChunks { // Attempt post-recovery check. Ok(data) => do_post_recovery_check(common_params, data) .await - .map_err(|e| { + .inspect_err(|_| { recovery_duration.map(|rd| rd.stop_and_discard()); - e }) - .map(|data| { + .inspect(|_| { gum::trace!( target: LOG_TARGET, candidate_hash = ?common_params.candidate_hash, erasure_root = ?common_params.erasure_root, "Data recovery from chunks complete", ); - data }), Err(err) => { recovery_duration.map(|rd| rd.stop_and_discard()); diff --git a/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs b/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs index 677bc2d1375a..8b8cff549912 100644 --- a/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs +++ b/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs @@ -125,18 +125,16 @@ impl FetchSystematicChunks { // Attempt post-recovery check. do_post_recovery_check(common_params, data) .await - .map_err(|e| { + .inspect_err(|_| { recovery_duration.map(|rd| rd.stop_and_discard()); - e }) - .map(|data| { + .inspect(|_| { gum::trace!( target: LOG_TARGET, candidate_hash = ?common_params.candidate_hash, erasure_root = ?common_params.erasure_root, "Data recovery from systematic chunks complete", ); - data }) }, Err(err) => { diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 7745c42f78a1..9a2357f02d8b 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -45,8 +45,9 @@ use polkadot_node_subsystem::{ errors::SubsystemError, messages::{ network_bridge_event::NewGossipTopology, ApprovalDistributionMessage, - BitfieldDistributionMessage, CollatorProtocolMessage, GossipSupportMessage, - NetworkBridgeEvent, NetworkBridgeRxMessage, StatementDistributionMessage, + ApprovalVotingParallelMessage, BitfieldDistributionMessage, CollatorProtocolMessage, + GossipSupportMessage, NetworkBridgeEvent, NetworkBridgeRxMessage, + StatementDistributionMessage, }, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, }; @@ -89,6 +90,7 @@ pub struct NetworkBridgeRx { validation_service: Box, collation_service: Box, notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, } impl NetworkBridgeRx { @@ -105,6 +107,7 @@ impl NetworkBridgeRx { peerset_protocol_names: PeerSetProtocolNames, mut notification_services: HashMap>, notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, ) -> Self { let shared = Shared::default(); @@ -125,6 +128,7 @@ impl NetworkBridgeRx { validation_service, collation_service, notification_sinks, + approval_voting_parallel_enabled, } } } @@ -156,6 +160,7 @@ async fn handle_validation_message( peerset_protocol_names: &PeerSetProtocolNames, notification_service: &mut Box, notification_sinks: &mut Arc>>>, + approval_voting_parallel_enabled: bool, ) where AD: validator_discovery::AuthorityDiscovery + Send, { @@ -276,6 +281,7 @@ async fn handle_validation_message( ], sender, &metrics, + approval_voting_parallel_enabled, ) .await; @@ -329,6 +335,7 @@ async fn handle_validation_message( NetworkBridgeEvent::PeerDisconnected(peer), sender, &metrics, + approval_voting_parallel_enabled, ) .await; } @@ -398,7 +405,13 @@ async fn handle_validation_message( network_service.report_peer(peer, report.into()); } - dispatch_validation_events_to_all(events, sender, &metrics).await; + dispatch_validation_events_to_all( + events, + sender, + &metrics, + approval_voting_parallel_enabled, + ) + .await; }, } } @@ -652,6 +665,7 @@ async fn handle_network_messages( mut validation_service: Box, mut collation_service: Box, mut notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, ) -> Result<(), Error> where AD: validator_discovery::AuthorityDiscovery + Send, @@ -669,6 +683,7 @@ where &peerset_protocol_names, &mut validation_service, &mut notification_sinks, + approval_voting_parallel_enabled, ).await, None => return Err(Error::EventStreamConcluded), }, @@ -727,6 +742,7 @@ async fn run_incoming_orchestra_signals( sync_oracle: Box, metrics: Metrics, notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, ) -> Result<(), Error> where AD: validator_discovery::AuthorityDiscovery + Clone, @@ -766,6 +782,7 @@ where local_index, }), ctx.sender(), + approval_voting_parallel_enabled, ); }, FromOrchestra::Communication { @@ -787,6 +804,7 @@ where dispatch_validation_event_to_all_unbounded( NetworkBridgeEvent::UpdatedAuthorityIds(peer_id, authority_ids), ctx.sender(), + approval_voting_parallel_enabled, ); }, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), @@ -826,6 +844,7 @@ where finalized_number, &metrics, ¬ification_sinks, + approval_voting_parallel_enabled, ); note_peers_count(&metrics, &shared); } @@ -875,6 +894,7 @@ where validation_service, collation_service, notification_sinks, + approval_voting_parallel_enabled, } = bridge; let (task, network_event_handler) = handle_network_messages( @@ -887,6 +907,7 @@ where validation_service, collation_service, notification_sinks.clone(), + approval_voting_parallel_enabled, ) .remote_handle(); @@ -900,6 +921,7 @@ where sync_oracle, metrics, notification_sinks, + approval_voting_parallel_enabled, ); futures::pin_mut!(orchestra_signal_handler); @@ -926,6 +948,7 @@ fn update_our_view( finalized_number: BlockNumber, metrics: &Metrics, notification_sinks: &Arc>>>, + approval_voting_parallel_enabled: bool, ) { let new_view = construct_view(live_heads.iter().map(|v| v.hash), finalized_number); @@ -970,6 +993,7 @@ fn update_our_view( dispatch_validation_event_to_all_unbounded( NetworkBridgeEvent::OurViewChange(our_view.clone()), ctx.sender(), + approval_voting_parallel_enabled, ); dispatch_collation_event_to_all_unbounded( @@ -1081,8 +1105,15 @@ async fn dispatch_validation_event_to_all( event: NetworkBridgeEvent, ctx: &mut impl overseer::NetworkBridgeRxSenderTrait, metrics: &Metrics, + approval_voting_parallel_enabled: bool, ) { - dispatch_validation_events_to_all(std::iter::once(event), ctx, metrics).await + dispatch_validation_events_to_all( + std::iter::once(event), + ctx, + metrics, + approval_voting_parallel_enabled, + ) + .await } async fn dispatch_collation_event_to_all( @@ -1095,6 +1126,7 @@ async fn dispatch_collation_event_to_all( fn dispatch_validation_event_to_all_unbounded( event: NetworkBridgeEvent, sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + approval_voting_parallel_enabled: bool, ) { event .focus() @@ -1106,11 +1138,20 @@ fn dispatch_validation_event_to_all_unbounded( .ok() .map(BitfieldDistributionMessage::from) .and_then(|msg| Some(sender.send_unbounded_message(msg))); - event - .focus() - .ok() - .map(ApprovalDistributionMessage::from) - .and_then(|msg| Some(sender.send_unbounded_message(msg))); + + if approval_voting_parallel_enabled { + event + .focus() + .ok() + .map(ApprovalVotingParallelMessage::from) + .and_then(|msg| Some(sender.send_unbounded_message(msg))); + } else { + event + .focus() + .ok() + .map(ApprovalDistributionMessage::from) + .and_then(|msg| Some(sender.send_unbounded_message(msg))); + } event .focus() .ok() @@ -1131,6 +1172,7 @@ async fn dispatch_validation_events_to_all( events: I, sender: &mut impl overseer::NetworkBridgeRxSenderTrait, _metrics: &Metrics, + approval_voting_parallel_enabled: bool, ) where I: IntoIterator>, I::IntoIter: Send, @@ -1160,7 +1202,11 @@ async fn dispatch_validation_events_to_all( for event in events { send_message!(event, StatementDistributionMessage); send_message!(event, BitfieldDistributionMessage); - send_message!(event, ApprovalDistributionMessage); + if approval_voting_parallel_enabled { + send_message!(event, ApprovalVotingParallelMessage); + } else { + send_message!(event, ApprovalDistributionMessage); + } send_message!(event, GossipSupportMessage); } } diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 601dca5cb8a3..a96817eb2546 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -529,6 +529,7 @@ fn test_harness>( validation_service, collation_service, notification_sinks, + approval_voting_parallel_enabled: false, }; let network_bridge = run_network_in(bridge, context) diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index ccf1b5daad7c..b4dcafe09eb6 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -38,5 +38,4 @@ sp-tracing = { workspace = true, default-features = true } sc-keystore = { workspace = true, default-features = true } futures-timer = { workspace = true } assert_matches = { workspace = true } -lazy_static = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/dispute-distribution/src/tests/mock.rs b/polkadot/node/network/dispute-distribution/src/tests/mock.rs index ccc050233e84..baa857e2eb68 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mock.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mock.rs @@ -19,12 +19,11 @@ use std::{ collections::{HashMap, HashSet}, - sync::Arc, + sync::{Arc, LazyLock}, time::Instant, }; use async_trait::async_trait; -use lazy_static::lazy_static; use polkadot_node_network_protocol::{authority_discovery::AuthorityDiscovery, PeerId}; use sc_keystore::LocalKeystore; @@ -60,64 +59,60 @@ pub const ALICE_INDEX: ValidatorIndex = ValidatorIndex(1); pub const BOB_INDEX: ValidatorIndex = ValidatorIndex(2); pub const CHARLIE_INDEX: ValidatorIndex = ValidatorIndex(3); -lazy_static! { - /// Mocked `AuthorityDiscovery` service. -pub static ref MOCK_AUTHORITY_DISCOVERY: MockAuthorityDiscovery = MockAuthorityDiscovery::new(); +pub static MOCK_AUTHORITY_DISCOVERY: LazyLock = + LazyLock::new(|| MockAuthorityDiscovery::new()); // Creating an innocent looking `SessionInfo` is really expensive in a debug build. Around // 700ms on my machine, We therefore cache those keys here: -pub static ref MOCK_VALIDATORS_DISCOVERY_KEYS: HashMap = - MOCK_VALIDATORS - .iter() - .chain(MOCK_AUTHORITIES_NEXT_SESSION.iter()) - .map(|v| (*v, v.public().into())) - .collect() -; -pub static ref FERDIE_DISCOVERY_KEY: AuthorityDiscoveryId = - MOCK_VALIDATORS_DISCOVERY_KEYS.get(&Sr25519Keyring::Ferdie).unwrap().clone(); - -pub static ref MOCK_SESSION_INFO: SessionInfo = - SessionInfo { - validators: MOCK_VALIDATORS.iter().take(4).map(|k| k.public().into()).collect(), - discovery_keys: MOCK_VALIDATORS +pub static MOCK_VALIDATORS_DISCOVERY_KEYS: LazyLock> = + LazyLock::new(|| { + MOCK_VALIDATORS .iter() - .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) - .collect(), - assignment_keys: vec![], - validator_groups: Default::default(), - n_cores: 0, - zeroth_delay_tranche_width: 0, - relay_vrf_modulo_samples: 0, - n_delay_tranches: 0, - no_show_slots: 0, - needed_approvals: 0, - active_validator_indices: vec![], - dispute_period: 6, - random_seed: [0u8; 32], - }; + .chain(MOCK_AUTHORITIES_NEXT_SESSION.iter()) + .map(|v| (*v, v.public().into())) + .collect() + }); +pub static FERDIE_DISCOVERY_KEY: LazyLock = + LazyLock::new(|| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&Sr25519Keyring::Ferdie).unwrap().clone()); + +pub static MOCK_SESSION_INFO: LazyLock = LazyLock::new(|| SessionInfo { + validators: MOCK_VALIDATORS.iter().take(4).map(|k| k.public().into()).collect(), + discovery_keys: MOCK_VALIDATORS + .iter() + .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) + .collect(), + assignment_keys: vec![], + validator_groups: Default::default(), + n_cores: 0, + zeroth_delay_tranche_width: 0, + relay_vrf_modulo_samples: 0, + n_delay_tranches: 0, + no_show_slots: 0, + needed_approvals: 0, + active_validator_indices: vec![], + dispute_period: 6, + random_seed: [0u8; 32], +}); /// `SessionInfo` for the second session. (No more validators, but two more authorities. -pub static ref MOCK_NEXT_SESSION_INFO: SessionInfo = - SessionInfo { - discovery_keys: - MOCK_AUTHORITIES_NEXT_SESSION - .iter() - .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) - .collect(), - validators: Default::default(), - assignment_keys: vec![], - validator_groups: Default::default(), - n_cores: 0, - zeroth_delay_tranche_width: 0, - relay_vrf_modulo_samples: 0, - n_delay_tranches: 0, - no_show_slots: 0, - needed_approvals: 0, - active_validator_indices: vec![], - dispute_period: 6, - random_seed: [0u8; 32], - }; -} +pub static MOCK_NEXT_SESSION_INFO: LazyLock = LazyLock::new(|| SessionInfo { + discovery_keys: MOCK_AUTHORITIES_NEXT_SESSION + .iter() + .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) + .collect(), + validators: Default::default(), + assignment_keys: vec![], + validator_groups: Default::default(), + n_cores: 0, + zeroth_delay_tranche_width: 0, + relay_vrf_modulo_samples: 0, + n_delay_tranches: 0, + no_show_slots: 0, + needed_approvals: 0, + active_validator_indices: vec![], + dispute_period: 6, + random_seed: [0u8; 32], +}); pub fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { CandidateReceipt { diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 83fdc7e26191..c8c19e5de070 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -39,5 +39,4 @@ polkadot-node-subsystem-test-helpers = { workspace = true } assert_matches = { workspace = true } async-trait = { workspace = true } parking_lot = { workspace = true, default-features = true } -lazy_static = { workspace = true } quickcheck = { workspace = true, default-features = true } diff --git a/polkadot/node/network/gossip-support/src/tests.rs b/polkadot/node/network/gossip-support/src/tests.rs index 09622254f523..399f29db67da 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -16,12 +16,11 @@ //! Unit tests for Gossip Support Subsystem. -use std::{collections::HashSet, time::Duration}; +use std::{collections::HashSet, sync::LazyLock, time::Duration}; use assert_matches::assert_matches; use async_trait::async_trait; use futures::{executor, future, Future}; -use lazy_static::lazy_static; use quickcheck::quickcheck; use rand::seq::SliceRandom as _; @@ -56,39 +55,29 @@ const AUTHORITY_KEYRINGS: &[Sr25519Keyring] = &[ Sr25519Keyring::Ferdie, ]; -lazy_static! { - static ref AUTHORITIES: Vec = - AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect(); +static AUTHORITIES: LazyLock> = + LazyLock::new(|| AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect()); - static ref AUTHORITIES_WITHOUT_US: Vec = { - let mut a = AUTHORITIES.clone(); - a.pop(); // remove FERDIE. - a - }; - - static ref PAST_PRESENT_FUTURE_AUTHORITIES: Vec = { - (0..50) - .map(|_| AuthorityDiscoveryPair::generate().0.public()) - .chain(AUTHORITIES.clone()) - .collect() - }; +static AUTHORITIES_WITHOUT_US: LazyLock> = LazyLock::new(|| { + let mut a = AUTHORITIES.clone(); + a.pop(); // remove FERDIE. + a +}); - // [2 6] - // [4 5] - // [1 3] - // [0 ] +static PAST_PRESENT_FUTURE_AUTHORITIES: LazyLock> = LazyLock::new(|| { + (0..50) + .map(|_| AuthorityDiscoveryPair::generate().0.public()) + .chain(AUTHORITIES.clone()) + .collect() +}); - static ref EXPECTED_SHUFFLING: Vec = vec![6, 4, 0, 5, 2, 3, 1]; +static EXPECTED_SHUFFLING: LazyLock> = LazyLock::new(|| vec![6, 4, 0, 5, 2, 3, 1]); - static ref ROW_NEIGHBORS: Vec = vec![ - ValidatorIndex::from(2), - ]; +static ROW_NEIGHBORS: LazyLock> = + LazyLock::new(|| vec![ValidatorIndex::from(2)]); - static ref COLUMN_NEIGHBORS: Vec = vec![ - ValidatorIndex::from(3), - ValidatorIndex::from(5), - ]; -} +static COLUMN_NEIGHBORS: LazyLock> = + LazyLock::new(|| vec![ValidatorIndex::from(3), ValidatorIndex::from(5)]); type VirtualOverseer = polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index 86a1801a5f2d..c2cb1817312c 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -31,8 +31,10 @@ use polkadot_overseer::{ gen::{FromOrchestra, SpawnedSubsystem}, HeadSupportsParachains, SubsystemError, }; -use polkadot_primitives::{CandidateReceipt, Hash, PvfExecKind}; -use polkadot_primitives_test_helpers::{dummy_candidate_descriptor, dummy_hash}; +use polkadot_primitives::{CandidateReceipt, Hash, PersistedValidationData, PvfExecKind}; +use polkadot_primitives_test_helpers::{ + dummy_candidate_descriptor, dummy_hash, dummy_validation_code, +}; struct AlwaysSupportsParachains; @@ -73,7 +75,9 @@ impl Subsystem1 { commitments_hash: Hash::zero(), }; - let msg = CandidateValidationMessage::ValidateFromChainState { + let msg = CandidateValidationMessage::ValidateFromExhaustive { + validation_data: PersistedValidationData { ..Default::default() }, + validation_code: dummy_validation_code(), candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), diff --git a/polkadot/node/overseer/src/dummy.rs b/polkadot/node/overseer/src/dummy.rs index fc5f0070773b..6f9cd9d00403 100644 --- a/polkadot/node/overseer/src/dummy.rs +++ b/polkadot/node/overseer/src/dummy.rs @@ -88,6 +88,7 @@ pub fn dummy_overseer_builder( DummySubsystem, DummySubsystem, DummySubsystem, + DummySubsystem, >, SubsystemError, > @@ -131,6 +132,7 @@ pub fn one_for_all_overseer_builder( Sub, Sub, Sub, + Sub, >, SubsystemError, > @@ -155,6 +157,7 @@ where + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> + + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> @@ -183,6 +186,7 @@ where .statement_distribution(subsystem.clone()) .approval_distribution(subsystem.clone()) .approval_voting(subsystem.clone()) + .approval_voting_parallel(subsystem.clone()) .gossip_support(subsystem.clone()) .dispute_coordinator(subsystem.clone()) .dispute_distribution(subsystem.clone()) diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 23adf4f4d8a4..e30ed69f9e37 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -60,6 +60,7 @@ // unused dependencies can not work for test and examples at the same time // yielding false positives #![warn(missing_docs)] +#![allow(dead_code)] // TODO https://github.com/paritytech/polkadot-sdk/issues/5793 use std::{ collections::{hash_map, HashMap}, @@ -76,13 +77,13 @@ use sc_client_api::{BlockImportNotification, BlockchainEvents, FinalityNotificat use self::messages::{BitfieldSigningMessage, PvfCheckerMessage}; use polkadot_node_subsystem_types::messages::{ - ApprovalDistributionMessage, ApprovalVotingMessage, AvailabilityDistributionMessage, - AvailabilityRecoveryMessage, AvailabilityStoreMessage, BitfieldDistributionMessage, - CandidateBackingMessage, CandidateValidationMessage, ChainApiMessage, ChainSelectionMessage, - CollationGenerationMessage, CollatorProtocolMessage, DisputeCoordinatorMessage, - DisputeDistributionMessage, GossipSupportMessage, NetworkBridgeRxMessage, - NetworkBridgeTxMessage, ProspectiveParachainsMessage, ProvisionerMessage, RuntimeApiMessage, - StatementDistributionMessage, + ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage, + AvailabilityDistributionMessage, AvailabilityRecoveryMessage, AvailabilityStoreMessage, + BitfieldDistributionMessage, CandidateBackingMessage, CandidateValidationMessage, + ChainApiMessage, ChainSelectionMessage, CollationGenerationMessage, CollatorProtocolMessage, + DisputeCoordinatorMessage, DisputeDistributionMessage, GossipSupportMessage, + NetworkBridgeRxMessage, NetworkBridgeTxMessage, ProspectiveParachainsMessage, + ProvisionerMessage, RuntimeApiMessage, StatementDistributionMessage, }; pub use polkadot_node_subsystem_types::{ @@ -550,6 +551,7 @@ pub struct Overseer { BitfieldDistributionMessage, StatementDistributionMessage, ApprovalDistributionMessage, + ApprovalVotingParallelMessage, GossipSupportMessage, DisputeDistributionMessage, CollationGenerationMessage, @@ -595,7 +597,19 @@ pub struct Overseer { RuntimeApiMessage, ])] approval_voting: ApprovalVoting, - + #[subsystem(blocking, message_capacity: 64000, ApprovalVotingParallelMessage, sends: [ + AvailabilityRecoveryMessage, + CandidateValidationMessage, + ChainApiMessage, + ChainSelectionMessage, + DisputeCoordinatorMessage, + RuntimeApiMessage, + NetworkBridgeTxMessage, + ApprovalVotingMessage, + ApprovalDistributionMessage, + ApprovalVotingParallelMessage, + ])] + approval_voting_parallel: ApprovalVotingParallel, #[subsystem(GossipSupportMessage, sends: [ NetworkBridgeTxMessage, NetworkBridgeRxMessage, // TODO @@ -613,6 +627,7 @@ pub struct Overseer { AvailabilityStoreMessage, AvailabilityRecoveryMessage, ChainSelectionMessage, + ApprovalVotingParallelMessage, ])] dispute_coordinator: DisputeCoordinator, diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 8e78d8fc8921..47c26186b518 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -29,10 +29,10 @@ use polkadot_node_subsystem_types::messages::{ }; use polkadot_primitives::{ CandidateHash, CandidateReceipt, CollatorPair, Id as ParaId, InvalidDisputeStatementKind, - PvfExecKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, + PersistedValidationData, PvfExecKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, }; use polkadot_primitives_test_helpers::{ - dummy_candidate_descriptor, dummy_candidate_receipt, dummy_hash, + dummy_candidate_descriptor, dummy_candidate_receipt, dummy_hash, dummy_validation_code, }; use crate::{ @@ -104,7 +104,9 @@ where }; let (tx, _) = oneshot::channel(); - ctx.send_message(CandidateValidationMessage::ValidateFromChainState { + ctx.send_message(CandidateValidationMessage::ValidateFromExhaustive { + validation_data: PersistedValidationData { ..Default::default() }, + validation_code: dummy_validation_code(), candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), @@ -802,7 +804,9 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { commitments_hash: Hash::zero(), }; - CandidateValidationMessage::ValidateFromChainState { + CandidateValidationMessage::ValidateFromExhaustive { + validation_data: PersistedValidationData { ..Default::default() }, + validation_code: dummy_validation_code(), candidate_receipt, pov, executor_params: Default::default(), @@ -950,7 +954,7 @@ fn test_prospective_parachains_msg() -> ProspectiveParachainsMessage { // Checks that `stop`, `broadcast_signal` and `broadcast_message` are implemented correctly. #[test] fn overseer_all_subsystems_receive_signals_and_messages() { - const NUM_SUBSYSTEMS: usize = 23; + const NUM_SUBSYSTEMS: usize = 24; // -4 for BitfieldSigning, GossipSupport, AvailabilityDistribution and PvfCheckerSubsystem. const NUM_SUBSYSTEMS_MESSAGED: usize = NUM_SUBSYSTEMS - 4; @@ -1028,6 +1032,11 @@ fn overseer_all_subsystems_receive_signals_and_messages() { handle .send_msg_anon(AllMessages::ApprovalDistribution(test_approval_distribution_msg())) .await; + handle + .send_msg_anon(AllMessages::ApprovalVotingParallel( + test_approval_distribution_msg().into(), + )) + .await; handle .send_msg_anon(AllMessages::ApprovalVoting(test_approval_voting_msg())) .await; @@ -1101,6 +1110,7 @@ fn context_holds_onto_message_until_enough_signals_received() { let (chain_selection_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (pvf_checker_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (prospective_parachains_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); + let (approval_voting_parallel_tx, _) = metered::channel(CHANNEL_CAPACITY); let (candidate_validation_unbounded_tx, _) = metered::unbounded(); let (candidate_backing_unbounded_tx, _) = metered::unbounded(); @@ -1125,6 +1135,7 @@ fn context_holds_onto_message_until_enough_signals_received() { let (chain_selection_unbounded_tx, _) = metered::unbounded(); let (pvf_checker_unbounded_tx, _) = metered::unbounded(); let (prospective_parachains_unbounded_tx, _) = metered::unbounded(); + let (approval_voting_parallel_unbounded_tx, _) = metered::unbounded(); let channels_out = ChannelsOut { candidate_validation: candidate_validation_bounded_tx.clone(), @@ -1150,6 +1161,7 @@ fn context_holds_onto_message_until_enough_signals_received() { chain_selection: chain_selection_bounded_tx.clone(), pvf_checker: pvf_checker_bounded_tx.clone(), prospective_parachains: prospective_parachains_bounded_tx.clone(), + approval_voting_parallel: approval_voting_parallel_tx.clone(), candidate_validation_unbounded: candidate_validation_unbounded_tx.clone(), candidate_backing_unbounded: candidate_backing_unbounded_tx.clone(), @@ -1174,6 +1186,7 @@ fn context_holds_onto_message_until_enough_signals_received() { chain_selection_unbounded: chain_selection_unbounded_tx.clone(), pvf_checker_unbounded: pvf_checker_unbounded_tx.clone(), prospective_parachains_unbounded: prospective_parachains_unbounded_tx.clone(), + approval_voting_parallel_unbounded: approval_voting_parallel_unbounded_tx.clone(), }; let (mut signal_tx, signal_rx) = metered::channel(CHANNEL_CAPACITY); diff --git a/polkadot/node/primitives/src/approval/mod.rs b/polkadot/node/primitives/src/approval/mod.rs index 79f4cfa9e0be..42342f9889a9 100644 --- a/polkadot/node/primitives/src/approval/mod.rs +++ b/polkadot/node/primitives/src/approval/mod.rs @@ -124,7 +124,7 @@ pub mod v1 { } /// Metadata about a block which is now live in the approval protocol. - #[derive(Debug)] + #[derive(Debug, Clone)] pub struct BlockApprovalMeta { /// The hash of the block. pub hash: Hash, diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 685a9fd337df..99d3a3e515b8 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -59,7 +59,7 @@ pub use disputes::{ /// relatively rare. /// /// The associated worker binaries should use the same version as the node that spawns them. -pub const NODE_VERSION: &'static str = "1.15.1"; +pub const NODE_VERSION: &'static str = "1.16.0"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: @@ -105,7 +105,7 @@ pub const MAX_FINALITY_LAG: u32 = 500; /// Type of a session window size. /// /// We are not using `NonZeroU32` here because `expect` and `unwrap` are not yet const, so global -/// constants of `SessionWindowSize` would require `lazy_static` in that case. +/// constants of `SessionWindowSize` would require `LazyLock` in that case. /// /// See: #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 89f8212bf9d8..8d50b54b2fdc 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -116,6 +116,7 @@ polkadot-gossip-support = { optional = true, workspace = true, default-features polkadot-network-bridge = { optional = true, workspace = true, default-features = true } polkadot-node-collation-generation = { optional = true, workspace = true, default-features = true } polkadot-node-core-approval-voting = { optional = true, workspace = true, default-features = true } +polkadot-node-core-approval-voting-parallel = { optional = true, workspace = true, default-features = true } polkadot-node-core-av-store = { optional = true, workspace = true, default-features = true } polkadot-node-core-backing = { optional = true, workspace = true, default-features = true } polkadot-node-core-bitfield-signing = { optional = true, workspace = true, default-features = true } @@ -160,6 +161,7 @@ full-node = [ "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index 1f2efdbbb5b3..d8f147a9cf7b 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -53,6 +53,7 @@ sp_api::decl_runtime_apis! { } } +#[allow(dead_code)] struct Runtime; sp_api::impl_runtime_apis! { diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 794243568804..d029f3be53eb 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -660,6 +660,8 @@ pub struct NewFullParams { #[allow(dead_code)] pub malus_finality_delay: Option, pub hwbench: Option, + /// Enable approval voting processing in parallel. + pub enable_approval_voting_parallel: bool, } #[cfg(feature = "full-node")] @@ -753,6 +755,7 @@ pub fn new_full< execute_workers_max_num, prepare_workers_soft_max_num, prepare_workers_hard_max_num, + enable_approval_voting_parallel, }: NewFullParams, ) -> Result { use polkadot_availability_recovery::FETCH_CHUNKS_THRESHOLD; @@ -784,6 +787,14 @@ pub fn new_full< Some(backoff) }; + // Running approval voting in parallel is enabled by default on all networks except Polkadot and + // Kusama, unless explicitly enabled by the commandline option. + // This is meant to be temporary until we have enough confidence in the new system to enable it + // by default on all networks. + let enable_approval_voting_parallel = (!config.chain_spec.is_kusama() && + !config.chain_spec.is_polkadot()) || + enable_approval_voting_parallel; + let disable_grandpa = config.disable_grandpa; let name = config.network.node_name.clone(); @@ -806,6 +817,7 @@ pub fn new_full< overseer_handle.clone(), metrics, Some(basics.task_manager.spawn_handle()), + enable_approval_voting_parallel, ) } else { SelectRelayChain::new_longest_chain(basics.backend.clone()) @@ -1016,6 +1028,7 @@ pub fn new_full< dispute_coordinator_config, chain_selection_config, fetch_chunks_threshold, + enable_approval_voting_parallel, }) }; diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 3c071e34fe11..a98b6bcb3083 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -58,6 +58,9 @@ pub use polkadot_network_bridge::{ }; pub use polkadot_node_collation_generation::CollationGenerationSubsystem; pub use polkadot_node_core_approval_voting::ApprovalVotingSubsystem; +pub use polkadot_node_core_approval_voting_parallel::{ + ApprovalVotingParallelSubsystem, Metrics as ApprovalVotingParallelMetrics, +}; pub use polkadot_node_core_av_store::AvailabilityStoreSubsystem; pub use polkadot_node_core_backing::CandidateBackingSubsystem; pub use polkadot_node_core_bitfield_signing::BitfieldSigningSubsystem; @@ -139,9 +142,16 @@ pub struct ExtendedOverseerGenArgs { /// than the value put in here we always try to recovery availability from backers. /// The presence of this parameter here is needed to have different values per chain. pub fetch_chunks_threshold: Option, + /// Enable approval-voting-parallel subsystem and disable the standalone approval-voting and + /// approval-distribution subsystems. + pub enable_approval_voting_parallel: bool, } /// Obtain a prepared validator `Overseer`, that is initialized with all default values. +/// +/// The difference between this function and `validator_with_parallel_overseer_builder` is that this +/// function enables the standalone approval-voting and approval-distribution subsystems +/// and disables the approval-voting-parallel subsystem. pub fn validator_overseer_builder( OverseerGenArgs { runtime_client, @@ -174,6 +184,7 @@ pub fn validator_overseer_builder( dispute_coordinator_config, chain_selection_config, fetch_chunks_threshold, + enable_approval_voting_parallel, }: ExtendedOverseerGenArgs, ) -> Result< InitializedOverseerBuilder< @@ -203,6 +214,7 @@ pub fn validator_overseer_builder( CollatorProtocolSubsystem, ApprovalDistributionSubsystem, ApprovalVotingSubsystem, + DummySubsystem, GossipSupportSubsystem, DisputeCoordinatorSubsystem, DisputeDistributionSubsystem, @@ -223,7 +235,8 @@ where let spawner = SpawnGlue(spawner); let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; - + let approval_voting_parallel_metrics: ApprovalVotingParallelMetrics = + Metrics::register(registry)?; let builder = Overseer::builder() .network_bridge_tx(NetworkBridgeTxSubsystem::new( network_service.clone(), @@ -241,6 +254,7 @@ where peerset_protocol_names, notification_services, notification_sinks, + enable_approval_voting_parallel, )) .availability_distribution(AvailabilityDistributionSubsystem::new( keystore.clone(), @@ -310,18 +324,19 @@ where rand::rngs::StdRng::from_entropy(), )) .approval_distribution(ApprovalDistributionSubsystem::new( - Metrics::register(registry)?, + approval_voting_parallel_metrics.approval_distribution_metrics(), approval_voting_config.slot_duration_millis, Arc::new(RealAssignmentCriteria {}), )) .approval_voting(ApprovalVotingSubsystem::with_config( - approval_voting_config, + approval_voting_config.clone(), parachains_db.clone(), keystore.clone(), Box::new(sync_service.clone()), - Metrics::register(registry)?, + approval_voting_parallel_metrics.approval_voting_metrics(), Arc::new(spawner.clone()), )) + .approval_voting_parallel(DummySubsystem) .gossip_support(GossipSupportSubsystem::new( keystore.clone(), authority_discovery_service.clone(), @@ -332,6 +347,229 @@ where dispute_coordinator_config, keystore.clone(), Metrics::register(registry)?, + enable_approval_voting_parallel, + )) + .dispute_distribution(DisputeDistributionSubsystem::new( + keystore.clone(), + dispute_req_receiver, + authority_discovery_service.clone(), + Metrics::register(registry)?, + )) + .chain_selection(ChainSelectionSubsystem::new(chain_selection_config, parachains_db)) + .prospective_parachains(ProspectiveParachainsSubsystem::new(Metrics::register(registry)?)) + .activation_external_listeners(Default::default()) + .span_per_active_leaf(Default::default()) + .active_leaves(Default::default()) + .supports_parachains(runtime_client) + .metrics(metrics) + .spawner(spawner); + + let builder = if let Some(capacity) = overseer_message_channel_capacity_override { + builder.message_channel_capacity(capacity) + } else { + builder + }; + Ok(builder) +} + +/// Obtain a prepared validator `Overseer`, that is initialized with all default values. +/// +/// The difference between this function and `validator_overseer_builder` is that this +/// function enables the approval-voting-parallel subsystem and disables the standalone +/// approval-voting and approval-distribution subsystems. +pub fn validator_with_parallel_overseer_builder( + OverseerGenArgs { + runtime_client, + network_service, + sync_service, + authority_discovery_service, + collation_req_v1_receiver: _, + collation_req_v2_receiver: _, + available_data_req_receiver, + registry, + spawner, + is_parachain_node, + overseer_message_channel_capacity_override, + req_protocol_names, + peerset_protocol_names, + notification_services, + }: OverseerGenArgs, + ExtendedOverseerGenArgs { + keystore, + parachains_db, + candidate_validation_config, + availability_config, + pov_req_receiver, + chunk_req_v1_receiver, + chunk_req_v2_receiver, + statement_req_receiver, + candidate_req_v2_receiver, + approval_voting_config, + dispute_req_receiver, + dispute_coordinator_config, + chain_selection_config, + fetch_chunks_threshold, + enable_approval_voting_parallel, + }: ExtendedOverseerGenArgs, +) -> Result< + InitializedOverseerBuilder< + SpawnGlue, + Arc, + CandidateValidationSubsystem, + PvfCheckerSubsystem, + CandidateBackingSubsystem, + StatementDistributionSubsystem, + AvailabilityDistributionSubsystem, + AvailabilityRecoverySubsystem, + BitfieldSigningSubsystem, + BitfieldDistributionSubsystem, + ProvisionerSubsystem, + RuntimeApiSubsystem, + AvailabilityStoreSubsystem, + NetworkBridgeRxSubsystem< + Arc, + AuthorityDiscoveryService, + >, + NetworkBridgeTxSubsystem< + Arc, + AuthorityDiscoveryService, + >, + ChainApiSubsystem, + CollationGenerationSubsystem, + CollatorProtocolSubsystem, + DummySubsystem, + DummySubsystem, + ApprovalVotingParallelSubsystem, + GossipSupportSubsystem, + DisputeCoordinatorSubsystem, + DisputeDistributionSubsystem, + ChainSelectionSubsystem, + ProspectiveParachainsSubsystem, + >, + Error, +> +where + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, + Spawner: 'static + SpawnNamed + Clone + Unpin, +{ + use polkadot_node_subsystem_util::metrics::Metrics; + + let metrics = ::register(registry)?; + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); + + let spawner = SpawnGlue(spawner); + + let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; + let approval_voting_parallel_metrics: ApprovalVotingParallelMetrics = + Metrics::register(registry)?; + let builder = Overseer::builder() + .network_bridge_tx(NetworkBridgeTxSubsystem::new( + network_service.clone(), + authority_discovery_service.clone(), + network_bridge_metrics.clone(), + req_protocol_names.clone(), + peerset_protocol_names.clone(), + notification_sinks.clone(), + )) + .network_bridge_rx(NetworkBridgeRxSubsystem::new( + network_service.clone(), + authority_discovery_service.clone(), + Box::new(sync_service.clone()), + network_bridge_metrics, + peerset_protocol_names, + notification_services, + notification_sinks, + enable_approval_voting_parallel, + )) + .availability_distribution(AvailabilityDistributionSubsystem::new( + keystore.clone(), + IncomingRequestReceivers { + pov_req_receiver, + chunk_req_v1_receiver, + chunk_req_v2_receiver, + }, + req_protocol_names.clone(), + Metrics::register(registry)?, + )) + .availability_recovery(AvailabilityRecoverySubsystem::for_validator( + fetch_chunks_threshold, + available_data_req_receiver, + &req_protocol_names, + Metrics::register(registry)?, + )) + .availability_store(AvailabilityStoreSubsystem::new( + parachains_db.clone(), + availability_config, + Box::new(sync_service.clone()), + Metrics::register(registry)?, + )) + .bitfield_distribution(BitfieldDistributionSubsystem::new(Metrics::register(registry)?)) + .bitfield_signing(BitfieldSigningSubsystem::new( + keystore.clone(), + Metrics::register(registry)?, + )) + .candidate_backing(CandidateBackingSubsystem::new( + keystore.clone(), + Metrics::register(registry)?, + )) + .candidate_validation(CandidateValidationSubsystem::with_config( + candidate_validation_config, + keystore.clone(), + Metrics::register(registry)?, // candidate-validation metrics + Metrics::register(registry)?, // validation host metrics + )) + .pvf_checker(PvfCheckerSubsystem::new(keystore.clone(), Metrics::register(registry)?)) + .chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?)) + .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) + .collator_protocol({ + let side = match is_parachain_node { + IsParachainNode::Collator(_) | IsParachainNode::FullNode => + return Err(Error::Overseer(SubsystemError::Context( + "build validator overseer for parachain node".to_owned(), + ))), + IsParachainNode::No => ProtocolSide::Validator { + keystore: keystore.clone(), + eviction_policy: Default::default(), + metrics: Metrics::register(registry)?, + }, + }; + CollatorProtocolSubsystem::new(side) + }) + .provisioner(ProvisionerSubsystem::new(Metrics::register(registry)?)) + .runtime_api(RuntimeApiSubsystem::new( + runtime_client.clone(), + Metrics::register(registry)?, + spawner.clone(), + )) + .statement_distribution(StatementDistributionSubsystem::new( + keystore.clone(), + statement_req_receiver, + candidate_req_v2_receiver, + Metrics::register(registry)?, + rand::rngs::StdRng::from_entropy(), + )) + .approval_distribution(DummySubsystem) + .approval_voting(DummySubsystem) + .approval_voting_parallel(ApprovalVotingParallelSubsystem::with_config( + approval_voting_config, + parachains_db.clone(), + keystore.clone(), + Box::new(sync_service.clone()), + approval_voting_parallel_metrics, + spawner.clone(), + overseer_message_channel_capacity_override, + )) + .gossip_support(GossipSupportSubsystem::new( + keystore.clone(), + authority_discovery_service.clone(), + Metrics::register(registry)?, + )) + .dispute_coordinator(DisputeCoordinatorSubsystem::new( + parachains_db.clone(), + dispute_coordinator_config, + keystore.clone(), + Metrics::register(registry)?, + enable_approval_voting_parallel, )) .dispute_distribution(DisputeDistributionSubsystem::new( keystore.clone(), @@ -407,6 +645,7 @@ pub fn collator_overseer_builder( DummySubsystem, DummySubsystem, DummySubsystem, + DummySubsystem, >, Error, > @@ -439,6 +678,7 @@ where peerset_protocol_names, notification_services, notification_sinks, + false, )) .availability_distribution(DummySubsystem) .availability_recovery(AvailabilityRecoverySubsystem::for_collator( @@ -481,6 +721,7 @@ where .statement_distribution(DummySubsystem) .approval_distribution(DummySubsystem) .approval_voting(DummySubsystem) + .approval_voting_parallel(DummySubsystem) .gossip_support(DummySubsystem) .dispute_coordinator(DummySubsystem) .dispute_distribution(DummySubsystem) @@ -537,9 +778,15 @@ impl OverseerGen for ValidatorOverseerGen { "create validator overseer as mandatory extended arguments were not provided" .to_owned(), )))?; - validator_overseer_builder(args, ext_args)? - .build_with_connector(connector) - .map_err(|e| e.into()) + if ext_args.enable_approval_voting_parallel { + validator_with_parallel_overseer_builder(args, ext_args)? + .build_with_connector(connector) + .map_err(|e| e.into()) + } else { + validator_overseer_builder(args, ext_args)? + .build_with_connector(connector) + .map_err(|e| e.into()) + } } } diff --git a/polkadot/node/service/src/parachains_db/mod.rs b/polkadot/node/service/src/parachains_db/mod.rs index 59af30dceeb9..887db80a3034 100644 --- a/polkadot/node/service/src/parachains_db/mod.rs +++ b/polkadot/node/service/src/parachains_db/mod.rs @@ -100,18 +100,11 @@ pub struct CacheSizes { pub availability_meta: usize, /// Cache used by approval data. pub approval_data: usize, - /// Cache used by session window data - pub session_data: usize, } impl Default for CacheSizes { fn default() -> Self { - CacheSizes { - availability_data: 25, - availability_meta: 1, - approval_data: 5, - session_data: 1, - } + CacheSizes { availability_data: 25, availability_meta: 1, approval_data: 5 } } } diff --git a/polkadot/node/service/src/relay_chain_selection.rs b/polkadot/node/service/src/relay_chain_selection.rs index c0b1ce8b0ebe..e48874f01ca6 100644 --- a/polkadot/node/service/src/relay_chain_selection.rs +++ b/polkadot/node/service/src/relay_chain_selection.rs @@ -39,8 +39,8 @@ use super::{HeaderProvider, HeaderProviderProvider}; use futures::channel::oneshot; use polkadot_node_primitives::MAX_FINALITY_LAG as PRIMITIVES_MAX_FINALITY_LAG; use polkadot_node_subsystem::messages::{ - ApprovalDistributionMessage, ApprovalVotingMessage, ChainSelectionMessage, - DisputeCoordinatorMessage, HighestApprovedAncestorBlock, + ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage, + ChainSelectionMessage, DisputeCoordinatorMessage, HighestApprovedAncestorBlock, }; use polkadot_node_subsystem_util::metrics::{self, prometheus}; use polkadot_overseer::{AllMessages, Handle}; @@ -169,6 +169,7 @@ where overseer: Handle, metrics: Metrics, spawn_handle: Option, + approval_voting_parallel_enabled: bool, ) -> Self { gum::debug!(target: LOG_TARGET, "Using dispute aware relay-chain selection algorithm",); @@ -179,6 +180,7 @@ where overseer, metrics, spawn_handle, + approval_voting_parallel_enabled, )), } } @@ -230,6 +232,7 @@ pub struct SelectRelayChainInner { overseer: OH, metrics: Metrics, spawn_handle: Option, + approval_voting_parallel_enabled: bool, } impl SelectRelayChainInner @@ -244,8 +247,15 @@ where overseer: OH, metrics: Metrics, spawn_handle: Option, + approval_voting_parallel_enabled: bool, ) -> Self { - SelectRelayChainInner { backend, overseer, metrics, spawn_handle } + SelectRelayChainInner { + backend, + overseer, + metrics, + spawn_handle, + approval_voting_parallel_enabled, + } } fn block_header(&self, hash: Hash) -> Result { @@ -284,6 +294,7 @@ where overseer: self.overseer.clone(), metrics: self.metrics.clone(), spawn_handle: self.spawn_handle.clone(), + approval_voting_parallel_enabled: self.approval_voting_parallel_enabled, } } } @@ -448,13 +459,25 @@ where // 2. Constrain according to `ApprovedAncestor`. let (subchain_head, subchain_number, subchain_block_descriptions) = { let (tx, rx) = oneshot::channel(); - overseer - .send_msg( - ApprovalVotingMessage::ApprovedAncestor(subchain_head, target_number, tx), - std::any::type_name::(), - ) - .await; - + if self.approval_voting_parallel_enabled { + overseer + .send_msg( + ApprovalVotingParallelMessage::ApprovedAncestor( + subchain_head, + target_number, + tx, + ), + std::any::type_name::(), + ) + .await; + } else { + overseer + .send_msg( + ApprovalVotingMessage::ApprovedAncestor(subchain_head, target_number, tx), + std::any::type_name::(), + ) + .await; + } match rx .await .map_err(Error::ApprovedAncestorCanceled) @@ -476,13 +499,23 @@ where // task for sending the message to not block here and delay finality. if let Some(spawn_handle) = &self.spawn_handle { let mut overseer_handle = self.overseer.clone(); + let approval_voting_parallel_enabled = self.approval_voting_parallel_enabled; let lag_update_task = async move { - overseer_handle - .send_msg( - ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag), - std::any::type_name::(), - ) - .await; + if approval_voting_parallel_enabled { + overseer_handle + .send_msg( + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag), + std::any::type_name::(), + ) + .await; + } else { + overseer_handle + .send_msg( + ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag), + std::any::type_name::(), + ) + .await; + } }; spawn_handle.spawn( diff --git a/polkadot/node/service/src/tests.rs b/polkadot/node/service/src/tests.rs index 195432bcb75d..78bbfcd5444f 100644 --- a/polkadot/node/service/src/tests.rs +++ b/polkadot/node/service/src/tests.rs @@ -63,9 +63,6 @@ struct TestHarness { finality_target_rx: Receiver>, } -#[derive(Default)] -struct HarnessConfig; - fn test_harness>( case_vars: CaseVars, test: impl FnOnce(TestHarness) -> T, @@ -83,6 +80,7 @@ fn test_harness>( context.sender().clone(), Default::default(), None, + false, ); let target_hash = case_vars.target_block; diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index ae798cf2640a..293df9f6e6d5 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -80,6 +80,7 @@ serde_yaml = { workspace = true } serde_json = { workspace = true } polkadot-node-core-approval-voting = { workspace = true, default-features = true } +polkadot-node-core-approval-voting-parallel = { workspace = true, default-features = true } polkadot-approval-distribution = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } sp-runtime = { workspace = true } diff --git a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml index cae1a30914da..1423d324df3f 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml @@ -9,6 +9,7 @@ TestConfiguration: coalesce_tranche_diff: 12 num_no_shows_per_candidate: 10 workdir_prefix: "/tmp/" + approval_voting_parallel_enabled: false n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml index 7edb48e302a4..87c6103a5d0a 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml @@ -9,6 +9,7 @@ TestConfiguration: coalesce_tranche_diff: 12 num_no_shows_per_candidate: 0 workdir_prefix: "/tmp" + approval_voting_parallel_enabled: true n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml index 7c24f50e6af5..5e2ea3817d17 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml @@ -8,6 +8,7 @@ TestConfiguration: stop_when_approved: true coalesce_tranche_diff: 12 num_no_shows_per_candidate: 0 + approval_voting_parallel_enabled: false workdir_prefix: "/tmp/" n_validators: 500 n_cores: 100 diff --git a/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs index 4b2b91696824..a3a475ac6b98 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs @@ -21,8 +21,11 @@ use polkadot_node_network_protocol::{ View, }; use polkadot_node_primitives::approval::time::{Clock, SystemClock, Tick}; +use polkadot_node_subsystem::messages::{ + ApprovalDistributionMessage, ApprovalVotingParallelMessage, +}; use polkadot_node_subsystem_types::messages::{ - network_bridge_event::NewGossipTopology, ApprovalDistributionMessage, NetworkBridgeEvent, + network_bridge_event::NewGossipTopology, NetworkBridgeEvent, }; use polkadot_overseer::AllMessages; use polkadot_primitives::{ @@ -121,6 +124,7 @@ pub fn generate_topology(test_authorities: &TestAuthorities) -> SessionGridTopol pub fn generate_new_session_topology( test_authorities: &TestAuthorities, test_node: ValidatorIndex, + approval_voting_parallel_enabled: bool, ) -> Vec { let topology = generate_topology(test_authorities); @@ -129,14 +133,29 @@ pub fn generate_new_session_topology( topology, local_index: Some(test_node), }); - vec![AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(event))] + vec![if approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel(ApprovalVotingParallelMessage::NetworkBridgeUpdate( + event, + )) + } else { + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(event)) + }] } /// Generates a peer view change for the passed `block_hash` -pub fn generate_peer_view_change_for(block_hash: Hash, peer_id: PeerId) -> AllMessages { +pub fn generate_peer_view_change_for( + block_hash: Hash, + peer_id: PeerId, + approval_voting_parallel_enabled: bool, +) -> AllMessages { let network = NetworkBridgeEvent::PeerViewChange(peer_id, View::new([block_hash], 0)); - - AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(network)) + if approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel(ApprovalVotingParallelMessage::NetworkBridgeUpdate( + network, + )) + } else { + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(network)) + } } /// Helper function to create a a signature for the block header. diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index da25a3bf3b79..807afb0438c9 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -401,7 +401,7 @@ impl PeerMessagesGenerator { /// We can not sample every time for all the messages because that would be too expensive to /// perform, so pre-generate a list of samples for a given network size. /// - result[i] give us as a list of random nodes that would send a given message to the node under -/// test. +/// test. fn random_samplings_to_node( node_under_test: ValidatorIndex, num_validators: usize, @@ -474,8 +474,7 @@ fn issue_approvals( coalesce_approvals_len(options.coalesce_mean, options.coalesce_std_dev, rand_chacha); let result = assignments .iter() - .enumerate() - .map(|(_index, message)| match &message.msg { + .map(|message| match &message.msg { protocol_v3::ApprovalDistributionMessage::Assignments(assignments) => { let mut approvals_to_create = Vec::new(); diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 9d85039b8880..29ebc4a419ae 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs @@ -49,20 +49,21 @@ use itertools::Itertools; use orchestra::TimeoutExt; use overseer::{metrics::Metrics as OverseerMetrics, MetricsTrait}; use polkadot_approval_distribution::ApprovalDistribution; +use polkadot_node_core_approval_voting_parallel::ApprovalVotingParallelSubsystem; use polkadot_node_primitives::approval::time::{ slot_number_to_tick, tick_to_slot_number, Clock, ClockExt, SystemClock, }; use polkadot_node_core_approval_voting::{ - ApprovalVotingSubsystem, Config as ApprovalVotingConfig, Metrics as ApprovalVotingMetrics, - RealAssignmentCriteria, + ApprovalVotingSubsystem, Config as ApprovalVotingConfig, RealAssignmentCriteria, }; use polkadot_node_network_protocol::v3 as protocol_v3; use polkadot_node_primitives::approval::{self, v1::RelayVRFStory}; -use polkadot_node_subsystem::{overseer, AllMessages, Overseer, OverseerConnector, SpawnGlue}; +use polkadot_node_subsystem::{ + messages::{ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage}, + overseer, AllMessages, Overseer, OverseerConnector, SpawnGlue, +}; use polkadot_node_subsystem_test_helpers::mock::new_block_import_info; -use polkadot_node_subsystem_types::messages::{ApprovalDistributionMessage, ApprovalVotingMessage}; -use polkadot_node_subsystem_util::metrics::Metrics; use polkadot_overseer::Handle as OverseerHandleReal; use polkadot_primitives::{ BlockNumber, CandidateEvent, CandidateIndex, CandidateReceipt, Hash, Header, Slot, ValidatorId, @@ -138,6 +139,9 @@ pub struct ApprovalsOptions { /// The number of no shows per candidate #[clap(short, long, default_value_t = 0)] pub num_no_shows_per_candidate: u32, + /// Enable approval voting parallel. + #[clap(short, long, default_value_t = true)] + pub approval_voting_parallel_enabled: bool, } impl ApprovalsOptions { @@ -272,7 +276,7 @@ pub struct ApprovalTestState { /// Total unique sent messages. total_unique_messages: Arc, /// Approval voting metrics. - approval_voting_metrics: ApprovalVotingMetrics, + approval_voting_parallel_metrics: polkadot_node_core_approval_voting_parallel::Metrics, /// The delta ticks from the tick the messages were generated to the the time we start this /// message. delta_tick_from_generated: Arc, @@ -330,7 +334,10 @@ impl ApprovalTestState { total_sent_messages_from_node: Arc::new(AtomicU64::new(0)), total_unique_messages: Arc::new(AtomicU64::new(0)), options, - approval_voting_metrics: ApprovalVotingMetrics::try_register(&dependencies.registry) + approval_voting_parallel_metrics: + polkadot_node_core_approval_voting_parallel::Metrics::try_register( + &dependencies.registry, + ) .unwrap(), delta_tick_from_generated: Arc::new(AtomicU64::new(630720000)), configuration: configuration.clone(), @@ -456,6 +463,14 @@ impl ApprovalTestState { }) .collect() } + + fn subsystem_name(&self) -> &'static str { + if self.options.approval_voting_parallel_enabled { + "approval-voting-parallel-subsystem" + } else { + "approval-distribution-subsystem" + } + } } impl ApprovalTestState { @@ -597,13 +612,16 @@ impl PeerMessageProducer { // so when the approval-distribution answered to it, we know it doesn't have anything // else to process. let (tx, rx) = oneshot::channel(); - let msg = ApprovalDistributionMessage::GetApprovalSignatures(HashSet::new(), tx); - self.send_overseer_message( - AllMessages::ApprovalDistribution(msg), - ValidatorIndex(0), - None, - ) - .await; + let msg = if self.options.approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel( + ApprovalVotingParallelMessage::GetApprovalSignatures(HashSet::new(), tx), + ) + } else { + AllMessages::ApprovalDistribution( + ApprovalDistributionMessage::GetApprovalSignatures(HashSet::new(), tx), + ) + }; + self.send_overseer_message(msg, ValidatorIndex(0), None).await; rx.await.expect("Failed to get signatures"); self.notify_done.send(()).expect("Failed to notify main loop"); gum::info!("All messages processed "); @@ -743,7 +761,11 @@ impl PeerMessageProducer { for validator in 1..self.state.test_authorities.validator_authority_id.len() as u32 { let peer_id = self.state.test_authorities.peer_ids.get(validator as usize).unwrap(); let validator = ValidatorIndex(validator); - let view_update = generate_peer_view_change_for(block_info.hash, *peer_id); + let view_update = generate_peer_view_change_for( + block_info.hash, + *peer_id, + self.state.options.approval_voting_parallel_enabled, + ); self.send_overseer_message(view_update, validator, None).await; } @@ -808,24 +830,12 @@ fn build_overseer( let system_clock = PastSystemClock::new(SystemClock {}, state.delta_tick_from_generated.clone()); - let approval_voting = ApprovalVotingSubsystem::with_config_and_clock( - TEST_CONFIG, - Arc::new(db), - Arc::new(keystore), - Box::new(TestSyncOracle {}), - state.approval_voting_metrics.clone(), - Arc::new(system_clock.clone()), - Arc::new(SpawnGlue(spawn_task_handle.clone())), - ); + let keystore = Arc::new(keystore); + let db = Arc::new(db); - let approval_distribution = ApprovalDistribution::new_with_clock( - Metrics::register(Some(&dependencies.registry)).unwrap(), - SLOT_DURATION_MILLIS, - Box::new(system_clock.clone()), - Arc::new(RealAssignmentCriteria {}), - ); let mock_chain_api = MockChainApi::new(state.build_chain_api_state()); - let mock_chain_selection = MockChainSelection { state: state.clone(), clock: system_clock }; + let mock_chain_selection = + MockChainSelection { state: state.clone(), clock: system_clock.clone() }; let mock_runtime_api = MockRuntimeApi::new( config.clone(), state.test_authorities.clone(), @@ -840,11 +850,14 @@ fn build_overseer( network_interface.subsystem_sender(), state.test_authorities.clone(), ); - let mock_rx_bridge = MockNetworkBridgeRx::new(network_receiver, None); + let mock_rx_bridge = MockNetworkBridgeRx::new( + network_receiver, + None, + state.options.approval_voting_parallel_enabled, + ); let overseer_metrics = OverseerMetrics::try_register(&dependencies.registry).unwrap(); - let dummy = dummy_builder!(spawn_task_handle, overseer_metrics) - .replace_approval_distribution(|_| approval_distribution) - .replace_approval_voting(|_| approval_voting) + let task_handle = spawn_task_handle.clone(); + let dummy = dummy_builder!(task_handle, overseer_metrics) .replace_chain_api(|_| mock_chain_api) .replace_chain_selection(|_| mock_chain_selection) .replace_runtime_api(|_| mock_runtime_api) @@ -853,8 +866,45 @@ fn build_overseer( .replace_availability_recovery(|_| MockAvailabilityRecovery::new()) .replace_candidate_validation(|_| MockCandidateValidation::new()); - let (overseer, raw_handle) = - dummy.build_with_connector(overseer_connector).expect("Should not fail"); + let (overseer, raw_handle) = if state.options.approval_voting_parallel_enabled { + let approval_voting_parallel = ApprovalVotingParallelSubsystem::with_config_and_clock( + TEST_CONFIG, + db.clone(), + keystore.clone(), + Box::new(TestSyncOracle {}), + state.approval_voting_parallel_metrics.clone(), + Arc::new(system_clock.clone()), + SpawnGlue(spawn_task_handle.clone()), + None, + ); + dummy + .replace_approval_voting_parallel(|_| approval_voting_parallel) + .build_with_connector(overseer_connector) + .expect("Should not fail") + } else { + let approval_voting = ApprovalVotingSubsystem::with_config_and_clock( + TEST_CONFIG, + db.clone(), + keystore.clone(), + Box::new(TestSyncOracle {}), + state.approval_voting_parallel_metrics.approval_voting_metrics(), + Arc::new(system_clock.clone()), + Arc::new(SpawnGlue(spawn_task_handle.clone())), + ); + + let approval_distribution = ApprovalDistribution::new_with_clock( + state.approval_voting_parallel_metrics.approval_distribution_metrics(), + TEST_CONFIG.slot_duration_millis, + Arc::new(system_clock.clone()), + Arc::new(RealAssignmentCriteria {}), + ); + + dummy + .replace_approval_voting(|_| approval_voting) + .replace_approval_distribution(|_| approval_distribution) + .build_with_connector(overseer_connector) + .expect("Should not fail") + }; let overseer_handle = OverseerHandleReal::new(raw_handle); (overseer, overseer_handle) @@ -943,11 +993,18 @@ pub async fn bench_approvals_run( // First create the initialization messages that make sure that then node under // tests receives notifications about the topology used and the connected peers. let mut initialization_messages = env.network().generate_peer_connected(|e| { - AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(e)) + if state.options.approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel(ApprovalVotingParallelMessage::NetworkBridgeUpdate( + e, + )) + } else { + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(e)) + } }); initialization_messages.extend(generate_new_session_topology( &state.test_authorities, ValidatorIndex(NODE_UNDER_TEST), + state.options.approval_voting_parallel_enabled, )); for message in initialization_messages { env.send_message(message).await; @@ -1012,7 +1069,14 @@ pub async fn bench_approvals_run( state.total_sent_messages_to_node.load(std::sync::atomic::Ordering::SeqCst) as usize; env.wait_until_metric( "polkadot_parachain_subsystem_bounded_received", - Some(("subsystem_name", "approval-distribution-subsystem")), + Some(( + "subsystem_name", + if state.options.approval_voting_parallel_enabled { + "approval-voting-parallel-subsystem" + } else { + "approval-distribution-subsystem" + }, + )), |value| { gum::debug!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); value >= at_least_messages as f64 @@ -1029,11 +1093,22 @@ pub async fn bench_approvals_run( CandidateEvent::CandidateIncluded(receipt_fetch, _head, _, _) => { let (tx, rx) = oneshot::channel(); - let msg = ApprovalVotingMessage::GetApprovalSignaturesForCandidate( - receipt_fetch.hash(), - tx, - ); - env.send_message(AllMessages::ApprovalVoting(msg)).await; + let msg = if state.options.approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel( + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate( + receipt_fetch.hash(), + tx, + ), + ) + } else { + AllMessages::ApprovalVoting( + ApprovalVotingMessage::GetApprovalSignaturesForCandidate( + receipt_fetch.hash(), + tx, + ), + ) + }; + env.send_message(msg).await; let result = rx.await.unwrap(); @@ -1057,7 +1132,7 @@ pub async fn bench_approvals_run( state.total_sent_messages_to_node.load(std::sync::atomic::Ordering::SeqCst) as usize; env.wait_until_metric( "polkadot_parachain_subsystem_bounded_received", - Some(("subsystem_name", "approval-distribution-subsystem")), + Some(("subsystem_name", state.subsystem_name())), |value| { gum::debug!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); value >= at_least_messages as f64 @@ -1098,5 +1173,8 @@ pub async fn bench_approvals_run( state.total_unique_messages.load(std::sync::atomic::Ordering::SeqCst) ); - env.collect_resource_usage(&["approval-distribution", "approval-voting"]) + env.collect_resource_usage( + &["approval-distribution", "approval-voting", "approval-voting-parallel"], + true, + ) } diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index 32dc8ae2c8dc..f28adff315f8 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -210,7 +210,7 @@ pub fn prepare_test( state.test_authorities.clone(), ); let network_bridge_rx = - network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_v2_cfg)); + network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_v2_cfg), false); let runtime_api = MockRuntimeApi::new( state.config.clone(), @@ -372,7 +372,7 @@ pub async fn benchmark_availability_read( ); env.stop().await; - env.collect_resource_usage(&["availability-recovery"]) + env.collect_resource_usage(&["availability-recovery"], false) } pub async fn benchmark_availability_write( @@ -506,9 +506,8 @@ pub async fn benchmark_availability_write( ); env.stop().await; - env.collect_resource_usage(&[ - "availability-distribution", - "bitfield-distribution", - "availability-store", - ]) + env.collect_resource_usage( + &["availability-distribution", "bitfield-distribution", "availability-store"], + false, + ) } diff --git a/polkadot/node/subsystem-bench/src/lib/display.rs b/polkadot/node/subsystem-bench/src/lib/display.rs index b153d54a7c36..c47dd9a07900 100644 --- a/polkadot/node/subsystem-bench/src/lib/display.rs +++ b/polkadot/node/subsystem-bench/src/lib/display.rs @@ -96,6 +96,23 @@ pub struct TestMetric { value: f64, } +impl TestMetric { + pub fn name(&self) -> &str { + &self.name + } + + pub fn value(&self) -> f64 { + self.value + } + + pub fn label_value(&self, label_name: &str) -> Option<&str> { + self.label_names + .iter() + .position(|name| name == label_name) + .and_then(|index| self.label_values.get(index).map(|s| s.as_str())) + } +} + impl Display for TestMetric { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( diff --git a/polkadot/node/subsystem-bench/src/lib/environment.rs b/polkadot/node/subsystem-bench/src/lib/environment.rs index a63f90da50b3..4de683ad6487 100644 --- a/polkadot/node/subsystem-bench/src/lib/environment.rs +++ b/polkadot/node/subsystem-bench/src/lib/environment.rs @@ -351,10 +351,14 @@ impl TestEnvironment { } } - pub fn collect_resource_usage(&self, subsystems_under_test: &[&str]) -> BenchmarkUsage { + pub fn collect_resource_usage( + &self, + subsystems_under_test: &[&str], + break_down_cpu_usage_per_task: bool, + ) -> BenchmarkUsage { BenchmarkUsage { network_usage: self.network_usage(), - cpu_usage: self.cpu_usage(subsystems_under_test), + cpu_usage: self.cpu_usage(subsystems_under_test, break_down_cpu_usage_per_task), } } @@ -378,7 +382,11 @@ impl TestEnvironment { ] } - fn cpu_usage(&self, subsystems_under_test: &[&str]) -> Vec { + fn cpu_usage( + &self, + subsystems_under_test: &[&str], + break_down_per_task: bool, + ) -> Vec { let test_metrics = super::display::parse_metrics(self.registry()); let mut usage = vec![]; let num_blocks = self.config().num_blocks as f64; @@ -392,6 +400,22 @@ impl TestEnvironment { total: total_cpu, per_block: total_cpu / num_blocks, }); + + if break_down_per_task { + for metric in subsystem_cpu_metrics.all() { + if metric.name() != "substrate_tasks_polling_duration_sum" { + continue; + } + + if let Some(task_name) = metric.label_value("task_name") { + usage.push(ResourceUsage { + resource_name: format!("{}/{}", subsystem, task_name), + total: metric.value(), + per_block: metric.value() / num_blocks, + }); + } + } + } } let test_env_cpu_metrics = diff --git a/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs b/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs index 8783b35f1c04..092a8fc5f4c1 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs @@ -96,5 +96,6 @@ mock!(NetworkBridgeTx); mock!(ChainApi); mock!(ChainSelection); mock!(ApprovalVoting); +mock!(ApprovalVotingParallel); mock!(ApprovalDistribution); mock!(RuntimeApi); diff --git a/polkadot/node/subsystem-bench/src/lib/mock/mod.rs b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs index da4ac05e33b7..2ca47d9fc082 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs @@ -47,6 +47,7 @@ macro_rules! dummy_builder { // All subsystem except approval_voting and approval_distribution are mock subsystems. Overseer::builder() .approval_voting(MockApprovalVoting {}) + .approval_voting_parallel(MockApprovalVotingParallel {}) .approval_distribution(MockApprovalDistribution {}) .availability_recovery(MockAvailabilityRecovery {}) .candidate_validation(MockCandidateValidation {}) diff --git a/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs index d70953926d13..f5474a61e3dc 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs @@ -24,13 +24,13 @@ use crate::{ use futures::{channel::mpsc::UnboundedSender, FutureExt, StreamExt}; use polkadot_node_network_protocol::Versioned; use polkadot_node_subsystem::{ - messages::NetworkBridgeTxMessage, overseer, SpawnedSubsystem, SubsystemError, -}; -use polkadot_node_subsystem_types::{ messages::{ - ApprovalDistributionMessage, BitfieldDistributionMessage, NetworkBridgeEvent, - StatementDistributionMessage, + ApprovalDistributionMessage, ApprovalVotingParallelMessage, NetworkBridgeTxMessage, }, + overseer, SpawnedSubsystem, SubsystemError, +}; +use polkadot_node_subsystem_types::{ + messages::{BitfieldDistributionMessage, NetworkBridgeEvent, StatementDistributionMessage}, OverseerSignal, }; use sc_network::{request_responses::ProtocolConfig, RequestFailure}; @@ -57,6 +57,8 @@ pub struct MockNetworkBridgeRx { network_receiver: NetworkInterfaceReceiver, /// Chunk request sender chunk_request_sender: Option, + /// Approval voting parallel enabled. + approval_voting_parallel_enabled: bool, } impl MockNetworkBridgeTx { @@ -73,8 +75,9 @@ impl MockNetworkBridgeRx { pub fn new( network_receiver: NetworkInterfaceReceiver, chunk_request_sender: Option, + approval_voting_parallel_enabled: bool, ) -> MockNetworkBridgeRx { - Self { network_receiver, chunk_request_sender } + Self { network_receiver, chunk_request_sender, approval_voting_parallel_enabled } } } @@ -199,9 +202,15 @@ impl MockNetworkBridgeRx { Versioned::V3( polkadot_node_network_protocol::v3::ValidationProtocol::ApprovalDistribution(msg) ) => { - ctx.send_message( - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(peer_id, polkadot_node_network_protocol::Versioned::V3(msg))) - ).await; + if self.approval_voting_parallel_enabled { + ctx.send_message( + ApprovalVotingParallelMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(peer_id, polkadot_node_network_protocol::Versioned::V3(msg))) + ).await; + } else { + ctx.send_message( + ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(peer_id, polkadot_node_network_protocol::Versioned::V3(msg))) + ).await; + } } Versioned::V3( polkadot_node_network_protocol::v3::ValidationProtocol::StatementDistribution(msg) diff --git a/polkadot/node/subsystem-bench/src/lib/statement/mod.rs b/polkadot/node/subsystem-bench/src/lib/statement/mod.rs index bd47505f56ae..dd7095d3b00c 100644 --- a/polkadot/node/subsystem-bench/src/lib/statement/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/statement/mod.rs @@ -114,14 +114,14 @@ fn build_overseer( state.pvd.clone(), state.own_backing_group.clone(), ); - let (statement_req_receiver, statement_req_cfg) = IncomingRequest::get_config_receiver::< - Block, - sc_network::NetworkWorker, - >(&ReqProtocolNames::new(GENESIS_HASH, None)); - let (candidate_req_receiver, candidate_req_cfg) = IncomingRequest::get_config_receiver::< - Block, - sc_network::NetworkWorker, - >(&ReqProtocolNames::new(GENESIS_HASH, None)); + let (statement_req_receiver, statement_req_cfg) = + IncomingRequest::get_config_receiver::>( + &ReqProtocolNames::new(GENESIS_HASH, None), + ); + let (candidate_req_receiver, candidate_req_cfg) = + IncomingRequest::get_config_receiver::>( + &ReqProtocolNames::new(GENESIS_HASH, None), + ); let keystore = make_keystore(); let subsystem = StatementDistributionSubsystem::new( keystore.clone(), @@ -135,7 +135,8 @@ fn build_overseer( network_interface.subsystem_sender(), state.test_authorities.clone(), ); - let network_bridge_rx = MockNetworkBridgeRx::new(network_receiver, Some(candidate_req_cfg)); + let network_bridge_rx = + MockNetworkBridgeRx::new(network_receiver, Some(candidate_req_cfg), false); let dummy = dummy_builder!(spawn_task_handle, overseer_metrics) .replace_runtime_api(|_| mock_runtime_api) @@ -445,5 +446,5 @@ pub async fn benchmark_statement_distribution( ); env.stop().await; - env.collect_resource_usage(&["statement-distribution"]) + env.collect_resource_usage(&["statement-distribution"], false) } diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs index 883e9aa7ad0a..5f691ae2db39 100644 --- a/polkadot/node/subsystem-bench/src/lib/usage.rs +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -32,14 +32,14 @@ impl std::fmt::Display for BenchmarkUsage { write!( f, "\n{}\n{}\n\n{}\n{}\n", - format!("{:<32}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(), + format!("{:<64}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(), self.network_usage .iter() .map(|v| v.to_string()) .sorted() .collect::>() .join("\n"), - format!("{:<32}{:>12}{:>12}", "CPU usage, seconds", "total", "per block").blue(), + format!("{:<64}{:>12}{:>12}", "CPU usage, seconds", "total", "per block").blue(), self.cpu_usage .iter() .map(|v| v.to_string()) @@ -134,7 +134,7 @@ pub struct ResourceUsage { impl std::fmt::Display for ResourceUsage { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:<32}{:>12.4}{:>12.4}", self.resource_name.cyan(), self.total, self.per_block) + write!(f, "{:<64}{:>12.4}{:>12.4}", self.resource_name.cyan(), self.total, self.per_block) } } diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index 854a9da158be..a520e85f52a9 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -142,28 +142,6 @@ pub enum PreCheckOutcome { /// or `Ok(ValidationResult::Invalid)`. #[derive(Debug)] pub enum CandidateValidationMessage { - /// Validate a candidate with provided parameters using relay-chain state. - /// - /// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode` - /// from the runtime API of the chain, based on the `relay_parent` - /// of the `CandidateReceipt`. - /// - /// This will also perform checking of validation outputs against the acceptance criteria. - /// - /// If there is no state available which can provide this data or the core for - /// the para is not free at the relay-parent, an error is returned. - ValidateFromChainState { - /// The candidate receipt - candidate_receipt: CandidateReceipt, - /// The proof-of-validity - pov: Arc, - /// Session's executor parameters - executor_params: ExecutorParams, - /// Execution kind, used for timeouts and retries (backing/approvals) - exec_kind: PvfExecKind, - /// The sending side of the response channel - response_sender: oneshot::Sender>, - }, /// Validate a candidate with provided, exhaustive parameters for validation. /// /// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full @@ -955,6 +933,103 @@ pub struct BlockDescription { pub candidates: Vec, } +/// Message to the approval voting parallel subsystem running both approval-distribution and +/// approval-voting logic in parallel. This is a combination of all the messages ApprovalVoting and +/// ApprovalDistribution subsystems can receive. +/// +/// The reason this exists is, so that we can keep both modes of running in the same polkadot +/// binary, based on the value of `--approval-voting-parallel-enabled`, we decide if we run with two +/// different subsystems for approval-distribution and approval-voting or run the approval-voting +/// parallel which has several parallel workers for the approval-distribution and a worker for +/// approval-voting. +/// +/// This is meant to be a temporary state until we can safely remove running the two subsystems +/// individually. +#[derive(Debug, derive_more::From)] +pub enum ApprovalVotingParallelMessage { + /// Gets mapped into `ApprovalVotingMessage::ApprovedAncestor` + ApprovedAncestor(Hash, BlockNumber, oneshot::Sender>), + + /// Gets mapped into `ApprovalVotingMessage::GetApprovalSignaturesForCandidate` + GetApprovalSignaturesForCandidate( + CandidateHash, + oneshot::Sender, ValidatorSignature)>>, + ), + /// Gets mapped into `ApprovalDistributionMessage::NewBlocks` + NewBlocks(Vec), + /// Gets mapped into `ApprovalDistributionMessage::DistributeAssignment` + DistributeAssignment(IndirectAssignmentCertV2, CandidateBitfield), + /// Gets mapped into `ApprovalDistributionMessage::DistributeApproval` + DistributeApproval(IndirectSignedApprovalVoteV2), + /// An update from the network bridge, gets mapped into + /// `ApprovalDistributionMessage::NetworkBridgeUpdate` + #[from] + NetworkBridgeUpdate(NetworkBridgeEvent), + + /// Gets mapped into `ApprovalDistributionMessage::GetApprovalSignatures` + GetApprovalSignatures( + HashSet<(Hash, CandidateIndex)>, + oneshot::Sender, ValidatorSignature)>>, + ), + /// Gets mapped into `ApprovalDistributionMessage::ApprovalCheckingLagUpdate` + ApprovalCheckingLagUpdate(BlockNumber), +} + +impl TryFrom for ApprovalVotingMessage { + type Error = (); + + fn try_from(msg: ApprovalVotingParallelMessage) -> Result { + match msg { + ApprovalVotingParallelMessage::ApprovedAncestor(hash, number, tx) => + Ok(ApprovalVotingMessage::ApprovedAncestor(hash, number, tx)), + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate(candidate, tx) => + Ok(ApprovalVotingMessage::GetApprovalSignaturesForCandidate(candidate, tx)), + _ => Err(()), + } + } +} + +impl TryFrom for ApprovalDistributionMessage { + type Error = (); + + fn try_from(msg: ApprovalVotingParallelMessage) -> Result { + match msg { + ApprovalVotingParallelMessage::NewBlocks(blocks) => + Ok(ApprovalDistributionMessage::NewBlocks(blocks)), + ApprovalVotingParallelMessage::DistributeAssignment(assignment, claimed_cores) => + Ok(ApprovalDistributionMessage::DistributeAssignment(assignment, claimed_cores)), + ApprovalVotingParallelMessage::DistributeApproval(vote) => + Ok(ApprovalDistributionMessage::DistributeApproval(vote)), + ApprovalVotingParallelMessage::NetworkBridgeUpdate(msg) => + Ok(ApprovalDistributionMessage::NetworkBridgeUpdate(msg)), + ApprovalVotingParallelMessage::GetApprovalSignatures(candidate_indicies, tx) => + Ok(ApprovalDistributionMessage::GetApprovalSignatures(candidate_indicies, tx)), + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag) => + Ok(ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag)), + _ => Err(()), + } + } +} + +impl From for ApprovalVotingParallelMessage { + fn from(msg: ApprovalDistributionMessage) -> Self { + match msg { + ApprovalDistributionMessage::NewBlocks(blocks) => + ApprovalVotingParallelMessage::NewBlocks(blocks), + ApprovalDistributionMessage::DistributeAssignment(cert, bitfield) => + ApprovalVotingParallelMessage::DistributeAssignment(cert, bitfield), + ApprovalDistributionMessage::DistributeApproval(vote) => + ApprovalVotingParallelMessage::DistributeApproval(vote), + ApprovalDistributionMessage::NetworkBridgeUpdate(msg) => + ApprovalVotingParallelMessage::NetworkBridgeUpdate(msg), + ApprovalDistributionMessage::GetApprovalSignatures(candidate_indicies, tx) => + ApprovalVotingParallelMessage::GetApprovalSignatures(candidate_indicies, tx), + ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag) => + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag), + } + } +} + /// Response type to `ApprovalVotingMessage::ApprovedAncestor`. #[derive(Clone, Debug)] pub struct HighestApprovedAncestorBlock { diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 7938223df23b..a8af8b7996f9 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -665,7 +665,8 @@ where fn number( &self, hash: Block::Hash, - ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> { + ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> + { self.client.number(hash) } diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index a7157d1b5b7f..3bd3892ba605 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -48,7 +48,6 @@ assert_matches = { workspace = true } futures = { features = ["thread-pool"], workspace = true } log = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { workspace = true } -lazy_static = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } kvdb-shared-tests = { workspace = true } tempfile = { workspace = true } diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index b12387884861..f879aa93df9f 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -101,6 +101,7 @@ pub fn new_full( execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ), sc_network::config::NetworkBackendType::Litep2p => @@ -123,6 +124,7 @@ pub fn new_full( execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ), } diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index a9bf1f5ef093..56c49a1ec305 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -16,7 +16,6 @@ tokio = { features = ["macros", "net", "rt-multi-thread", "sync"], workspace = t url = { workspace = true } tokio-tungstenite = { workspace = true } futures-util = { workspace = true, default-features = true } -lazy_static = { workspace = true } codec = { features = ["derive"], workspace = true, default-features = true } reqwest = { features = ["rustls-tls"], workspace = true } thiserror = { workspace = true } diff --git a/polkadot/node/zombienet-backchannel/src/lib.rs b/polkadot/node/zombienet-backchannel/src/lib.rs index 9068b03399ca..080dcf1c2b75 100644 --- a/polkadot/node/zombienet-backchannel/src/lib.rs +++ b/polkadot/node/zombienet-backchannel/src/lib.rs @@ -21,7 +21,6 @@ use codec; use futures_util::{SinkExt, StreamExt}; -use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use std::{env, sync::Mutex}; use tokio::sync::broadcast; @@ -30,9 +29,7 @@ use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; mod errors; use errors::BackchannelError; -lazy_static! { - pub static ref ZOMBIENET_BACKCHANNEL: Mutex> = Mutex::new(None); -} +pub static ZOMBIENET_BACKCHANNEL: Mutex> = Mutex::new(None); #[derive(Debug)] pub struct ZombienetBackchannel { diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs index e8588274df27..4660b4d38f7c 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs @@ -98,6 +98,7 @@ fn main() -> Result<()> { execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ) .map_err(|e| e.to_string())?; diff --git a/polkadot/parachain/test-parachains/undying/collator/src/main.rs b/polkadot/parachain/test-parachains/undying/collator/src/main.rs index 7198a831a477..3dfa714e6d16 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/main.rs @@ -100,6 +100,7 @@ fn main() -> Result<()> { execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ) .map_err(|e| e.to_string())?; diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index ddebe99e6214..3c90c050baed 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -36,7 +36,7 @@ //! //! Let's see a quick example: //! -//! ```rust(ignore) +//! ```nocompile //! sp_api::decl_runtime_apis! { //! #[api_version(2)] //! pub trait MyApi { diff --git a/polkadot/primitives/src/v8/metrics.rs b/polkadot/primitives/src/v8/metrics.rs index 1d66c9848a7c..409efc86bc9b 100644 --- a/polkadot/primitives/src/v8/metrics.rs +++ b/polkadot/primitives/src/v8/metrics.rs @@ -91,18 +91,6 @@ pub type RuntimeMetricLabelValue = RuntimeMetricLabel; /// A set of metric label values. pub type RuntimeMetricLabelValues = RuntimeMetricLabels; -/// Trait for converting Vec to `&str`. -pub trait AsStr { - /// Return a str reference. - fn as_str(&self) -> Option<&str>; -} - -impl AsStr for RuntimeMetricLabel { - fn as_str(&self) -> Option<&str> { - alloc::str::from_utf8(&self.0).ok() - } -} - impl From<&'static str> for RuntimeMetricLabel { fn from(s: &'static str) -> Self { Self(s.as_bytes().to_vec()) diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting-parallel.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting-parallel.md new file mode 100644 index 000000000000..84661b7bf9b3 --- /dev/null +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting-parallel.md @@ -0,0 +1,30 @@ +# Approval voting parallel + +The approval-voting-parallel subsystem acts as an orchestrator for the tasks handled by the [Approval Voting](approval-voting.md) +and [Approval Distribution](approval-distribution.md) subsystems. Initially, these two systems operated separately and interacted +with each other and other subsystems through orchestra. + +With approval-voting-parallel, we have a single subsystem that creates two types of workers: +- Four approval-distribution workers that operate in parallel, each handling tasks based on the validator_index of the message + originator. +- One approval-voting worker that performs the tasks previously managed by the standalone approval-voting subsystem. + +This subsystem does not maintain any state. Instead, it functions as an orchestrator that: +- Spawns and initializes each workers. +- Forwards each message and signal to the appropriate worker. +- Aggregates results for messages that require input from more than one worker, such as GetApprovalSignatures. + +## Forwarding logic + +The messages received and forwarded by approval-voting-parallel split in three categories: +- Signals which need to be forwarded to all workers. +- Messages that only the `approval-voting` worker needs to handle, `ApprovalVotingParallelMessage::ApprovedAncestor` + and `ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate` +- Control messages that all `approval-distribution` workers need to receive `ApprovalVotingParallelMessage::NewBlocks`, + `ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate` and all network bridge variants `ApprovalVotingParallelMessage::NetworkBridgeUpdate` + except `ApprovalVotingParallelMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage)` +- Data messages `ApprovalVotingParallelMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage)` which need to be sent + just to a single `approval-distribution` worker based on the ValidatorIndex. The logic for assigning the work is: + ``` + assigned_worker_index = validator_index % number_of_workers; + ``` diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index 317f339ddd4e..6e24d969dde4 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -901,22 +901,6 @@ const APPROVAL_EXECUTION_TIMEOUT: Duration = 6 seconds; /// or `Ok(ValidationResult::Invalid)`. #[derive(Debug)] pub enum CandidateValidationMessage { - /// Validate a candidate with provided parameters using relay-chain state. - /// - /// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode` - /// from the runtime API of the chain, based on the `relay_parent` - /// of the `CandidateDescriptor`. - /// - /// This will also perform checking of validation outputs against the acceptance criteria. - /// - /// If there is no state available which can provide this data or the core for - /// the para is not free at the relay-parent, an error is returned. - ValidateFromChainState( - CandidateDescriptor, - Arc, - Duration, // Execution timeout. - oneshot::Sender>, - ), /// Validate a candidate with provided, exhaustive parameters for validation. /// /// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 30fe95883e77..36888247580e 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -29,7 +29,7 @@ use polkadot_parachain_primitives::primitives::{ use polkadot_primitives::{ ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, - MAX_POV_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, + ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill, Percent}; @@ -46,6 +46,10 @@ use polkadot_primitives::SchedulerParams; const LOG_TARGET: &str = "runtime::configuration"; +// This value is derived from network layer limits. See `sc_network::MAX_RESPONSE_SIZE` and +// `polkadot_node_network_protocol::POV_RESPONSE_SIZE`. +const POV_SIZE_HARD_LIMIT: u32 = 16 * 1024 * 1024; + /// All configuration of the runtime with respect to paras. #[derive( Clone, @@ -310,7 +314,7 @@ pub enum InconsistentError { MaxCodeSizeExceedHardLimit { max_code_size: u32 }, /// `max_head_data_size` exceeds the hard limit of `MAX_HEAD_DATA_SIZE`. MaxHeadDataSizeExceedHardLimit { max_head_data_size: u32 }, - /// `max_pov_size` exceeds the hard limit of `MAX_POV_SIZE`. + /// `max_pov_size` exceeds the hard limit of `POV_SIZE_HARD_LIMIT`. MaxPovSizeExceedHardLimit { max_pov_size: u32 }, /// `minimum_validation_upgrade_delay` is less than `paras_availability_period`. MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod { @@ -377,7 +381,7 @@ where }) } - if self.max_pov_size > MAX_POV_SIZE { + if self.max_pov_size > POV_SIZE_HARD_LIMIT { return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size }) } diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index dad8b6458e10..0d20399e471b 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -210,7 +210,7 @@ fn invariants() { ); assert_err!( - Configuration::set_max_pov_size(RuntimeOrigin::root(), MAX_POV_SIZE + 1), + Configuration::set_max_pov_size(RuntimeOrigin::root(), POV_SIZE_HARD_LIMIT + 1), Error::::InvalidNewValue ); diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index b149404b41b8..220543f00ec3 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -945,7 +945,7 @@ impl Pallet { outgoing_paras.len() as u32 )) .saturating_add(::WeightInfo::force_process_hrmp_close( - outgoing_paras.len() as u32 + outgoing_paras.len() as u32, )) } diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index ba0f7392f6b7..36f874b8db1e 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -1025,9 +1025,8 @@ impl Pallet { .take_while(|message| !message.is_empty()) .filter_map(|d| { BoundedSlice::try_from(&d[..]) - .map_err(|e| { + .inspect_err(|_| { defensive!("Accepted candidate contains too long msg, len=", d.len()); - e }) .ok() }) diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index a581d31d8a85..2aca0f2c728a 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -1297,18 +1297,19 @@ fn filter_backed_statements_from_disabled_validators< // Get relay parent block number of the candidate. We need this to get the group index // assigned to this core at this block number - let relay_parent_block_number = - match allowed_relay_parents.acquire_info(bc.descriptor().relay_parent(), None) { - Some((_, block_num)) => block_num, - None => { - log::debug!( - target: LOG_TARGET, - "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", - bc.descriptor().relay_parent() - ); - return false - }, - }; + let relay_parent_block_number = match allowed_relay_parents + .acquire_info(bc.descriptor().relay_parent(), None) + { + Some((_, block_num)) => block_num, + None => { + log::debug!( + target: LOG_TARGET, + "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", + bc.descriptor().relay_parent() + ); + return false + }, + }; // Get the group index for the core let group_idx = match scheduler::Pallet::::group_assigned_to_core( diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs index ed2e95b3cfa9..ad80856e2393 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs @@ -26,5 +26,5 @@ //! 2. Move methods from `vstaging` to `v3`. The new stable version should include all methods from //! `vstaging` tagged with the new version number (e.g. all `v3` methods). -pub mod v10; +pub mod v11; pub mod vstaging; diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs similarity index 92% rename from polkadot/runtime/parachains/src/runtime_api_impl/v10.rs rename to polkadot/runtime/parachains/src/runtime_api_impl/v11.rs index 0310b66ea54b..a0996d5df0ee 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs @@ -14,7 +14,7 @@ //! A module exporting runtime API implementation functions for all runtime APIs using `v5` //! primitives. //! -//! Runtimes implementing the v10 runtime API are recommended to forward directly to these +//! Runtimes implementing the v11 runtime API are recommended to forward directly to these //! functions. use crate::{ @@ -22,7 +22,11 @@ use crate::{ scheduler::{self, CoreOccupied}, session_info, shared, }; -use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; +use alloc::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + vec, + vec::Vec, +}; use frame_support::traits::{GetStorageVersion, StorageVersion}; use frame_system::pallet_prelude::*; use polkadot_primitives::{ @@ -561,3 +565,38 @@ pub fn node_features() -> NodeFeatures { pub fn approval_voting_params() -> ApprovalVotingParams { configuration::ActiveConfig::::get().approval_voting_params } + +/// Returns the claimqueue from the scheduler +pub fn claim_queue() -> BTreeMap> { + let now = >::block_number() + One::one(); + + // This is needed so that the claim queue always has the right size (equal to + // scheduling_lookahead). Otherwise, if a candidate is backed in the same block where the + // previous candidate is included, the claim queue will have already pop()-ed the next item + // from the queue and the length would be `scheduling_lookahead - 1`. + >::free_cores_and_fill_claim_queue(Vec::new(), now); + let config = configuration::ActiveConfig::::get(); + // Extra sanity, config should already never be smaller than 1: + let n_lookahead = config.scheduler_params.lookahead.max(1); + + scheduler::ClaimQueue::::get() + .into_iter() + .map(|(core_index, entries)| { + // on cores timing out internal claim queue size may be temporarily longer than it + // should be as the timed out assignment might got pushed back to an already full claim + // queue: + ( + core_index, + entries.into_iter().map(|e| e.para_id()).take(n_lookahead as usize).collect(), + ) + }) + .collect() +} + +/// Returns all the candidates that are pending availability for a given `ParaId`. +/// Deprecates `candidate_pending_availability` in favor of supporting elastic scaling. +pub fn candidates_pending_availability( + para_id: ParaId, +) -> Vec> { + >::candidates_pending_availability(para_id) +} diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index a3440f686e94..d01b543630c3 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -15,48 +15,3 @@ // along with Polkadot. If not, see . //! Put implementations of functions from staging APIs here. - -use crate::{configuration, inclusion, initializer, scheduler}; -use alloc::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - vec::Vec, -}; -use polkadot_primitives::{ - vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreIndex, Id as ParaId, -}; -use sp_runtime::traits::One; - -/// Returns the claimqueue from the scheduler -pub fn claim_queue() -> BTreeMap> { - let now = >::block_number() + One::one(); - - // This is needed so that the claim queue always has the right size (equal to - // scheduling_lookahead). Otherwise, if a candidate is backed in the same block where the - // previous candidate is included, the claim queue will have already pop()-ed the next item - // from the queue and the length would be `scheduling_lookahead - 1`. - >::free_cores_and_fill_claim_queue(Vec::new(), now); - let config = configuration::ActiveConfig::::get(); - // Extra sanity, config should already never be smaller than 1: - let n_lookahead = config.scheduler_params.lookahead.max(1); - - scheduler::ClaimQueue::::get() - .into_iter() - .map(|(core_index, entries)| { - // on cores timing out internal claim queue size may be temporarily longer than it - // should be as the timed out assignment might got pushed back to an already full claim - // queue: - ( - core_index, - entries.into_iter().map(|e| e.para_id()).take(n_lookahead as usize).collect(), - ) - }) - .collect() -} - -/// Returns all the candidates that are pending availability for a given `ParaId`. -/// Deprecates `candidate_pending_availability` in favor of supporting elastic scaling. -pub fn candidates_pending_availability( - para_id: ParaId, -) -> Vec> { - >::candidates_pending_availability(para_id) -} diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index d6cef850fb6a..cd7951ac9aa9 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -465,10 +465,11 @@ fn verify_relay_dispatch_queue_size_is_externally_accessible() { fn assert_queue_size(para: ParaId, count: u32, size: u32) { #[allow(deprecated)] - let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(para)).expect( - "enqueuing a message should create the dispatch queue\ + let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(para)) + .expect( + "enqueuing a message should create the dispatch queue\ and it should be accessible via the well known keys", - ); + ); let (c, s) = <(u32, u32)>::decode(&mut &raw_queue_size[..]) .expect("the dispatch queue size should be decodable into (u32, u32)"); assert_eq!((c, s), (count, size)); diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 67b8712dfe01..b333a9f141ff 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -66,9 +66,7 @@ use polkadot_runtime_parachains::{ initializer as parachains_initializer, on_demand as parachains_on_demand, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, - runtime_api_impl::{ - v10 as parachains_runtime_api_impl, vstaging as vstaging_parachains_runtime_api_impl, - }, + runtime_api_impl::v11 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -170,7 +168,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -2058,11 +2056,11 @@ sp_api::impl_runtime_apis! { } fn claim_queue() -> BTreeMap> { - vstaging_parachains_runtime_api_impl::claim_queue::() + parachains_runtime_api_impl::claim_queue::() } fn candidates_pending_availability(para_id: ParaId) -> Vec> { - vstaging_parachains_runtime_api_impl::candidates_pending_availability::(para_id) + parachains_runtime_api_impl::candidates_pending_availability::(para_id) } } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index b03231569113..30ef2de31651 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -33,13 +33,11 @@ use pallet_transaction_payment::FungibleAdapter; use polkadot_runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, - configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, - disputes as parachains_disputes, - disputes::slashing as parachains_slashing, - dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, - runtime_api_impl::{v10 as runtime_impl, vstaging as vstaging_parachains_runtime_api_impl}, + configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, disputes as parachains_disputes, + disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, + inclusion as parachains_inclusion, initializer as parachains_initializer, + origin as parachains_origin, paras as parachains_paras, + paras_inherent as parachains_paras_inherent, runtime_api_impl::v11 as runtime_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -1003,11 +1001,11 @@ sp_api::impl_runtime_apis! { } fn claim_queue() -> BTreeMap> { - vstaging_parachains_runtime_api_impl::claim_queue::() + runtime_impl::claim_queue::() } fn candidates_pending_availability(para_id: ParaId) -> Vec> { - vstaging_parachains_runtime_api_impl::candidates_pending_availability::(para_id) + runtime_impl::candidates_pending_availability::(para_id) } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 3afb254fcdfc..a43b85504dca 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -83,9 +83,7 @@ use polkadot_runtime_parachains::{ initializer as parachains_initializer, on_demand as parachains_on_demand, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, - runtime_api_impl::{ - v10 as parachains_runtime_api_impl, vstaging as vstaging_parachains_runtime_api_impl, - }, + runtime_api_impl::v11 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -170,7 +168,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_015_000, + spec_version: 1_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, @@ -1112,7 +1110,8 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | + RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) @@ -2089,11 +2088,11 @@ sp_api::impl_runtime_apis! { } fn claim_queue() -> BTreeMap> { - vstaging_parachains_runtime_api_impl::claim_queue::() + parachains_runtime_api_impl::claim_queue::() } fn candidates_pending_availability(para_id: ParaId) -> Vec> { - vstaging_parachains_runtime_api_impl::candidates_pending_availability::(para_id) + parachains_runtime_api_impl::candidates_pending_availability::(para_id) } } @@ -2764,49 +2763,3 @@ sp_api::impl_runtime_apis! { } } } - -mod clean_state_migration { - use super::Runtime; - #[cfg(feature = "try-runtime")] - use super::Vec; - use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade}; - use pallet_state_trie_migration::MigrationLimits; - - #[storage_alias] - type AutoLimits = StorageValue, ValueQuery>; - - // Actual type of value is `MigrationTask`, putting a dummy - // one to avoid the trait constraint on T. - // Since we only use `kill` it is fine. - #[storage_alias] - type MigrationProcess = StorageValue; - - #[storage_alias] - type SignedMigrationMaxLimits = StorageValue; - - /// Initialize an automatic migration process. - pub struct CleanMigrate; - - impl OnRuntimeUpgrade for CleanMigrate { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - Ok(Default::default()) - } - - fn on_runtime_upgrade() -> frame_support::weights::Weight { - MigrationProcess::kill(); - AutoLimits::kill(); - SignedMigrationMaxLimits::kill(); - ::DbWeight::get().writes(3) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - frame_support::ensure!( - !AutoLimits::exists() && !SignedMigrationMaxLimits::exists(), - "State migration clean.", - ); - Ok(()) - } - } -} diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 1e7b01bc472b..ae11f6ccba41 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -33,7 +33,6 @@ pub mod pallet_nomination_pools; pub mod pallet_parameters; pub mod pallet_preimage; pub mod pallet_proxy; -pub mod pallet_referenda_fellowship_referenda; pub mod pallet_referenda_referenda; pub mod pallet_scheduler; pub mod pallet_session; diff --git a/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs deleted file mode 100644 index a4ac06679116..000000000000 --- a/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. - -// Polkadot 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. - -// Polkadot 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 Polkadot. If not, see . - -//! Autogenerated weights for `pallet_referenda` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_referenda -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_referenda`. -pub struct WeightInfo(PhantomData); -impl pallet_referenda::WeightInfo for WeightInfo { - /// Storage: FellowshipCollective Members (r:1 w:0) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumCount (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:0 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn submit() -> Weight { - // Proof Size summary in bytes: - // Measured: `327` - // Estimated: `42428` - // Minimum execution time: 28_969_000 picoseconds. - Weight::from_parts(30_902_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `404` - // Estimated: `83866` - // Minimum execution time: 53_500_000 picoseconds. - Weight::from_parts(54_447_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `2042` - // Estimated: `42428` - // Minimum execution time: 114_321_000 picoseconds. - Weight::from_parts(122_607_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `2083` - // Estimated: `42428` - // Minimum execution time: 113_476_000 picoseconds. - Weight::from_parts(120_078_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `774` - // Estimated: `83866` - // Minimum execution time: 194_798_000 picoseconds. - Weight::from_parts(208_378_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `639` - // Estimated: `83866` - // Minimum execution time: 69_502_000 picoseconds. - Weight::from_parts(71_500_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn refund_decision_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `317` - // Estimated: `4365` - // Minimum execution time: 30_561_000 picoseconds. - Weight::from_parts(31_427_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn refund_submission_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `167` - // Estimated: `4365` - // Minimum execution time: 14_535_000 picoseconds. - Weight::from_parts(14_999_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `349` - // Estimated: `83866` - // Minimum execution time: 38_532_000 picoseconds. - Weight::from_parts(39_361_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda MetadataOf (r:1 w:0) - /// Proof: FellowshipReferenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn kill() -> Weight { - // Proof Size summary in bytes: - // Measured: `450` - // Estimated: `83866` - // Minimum execution time: 78_956_000 picoseconds. - Weight::from_parts(80_594_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda TrackQueue (r:1 w:0) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - fn one_fewer_deciding_queue_empty() -> Weight { - // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `4277` - // Minimum execution time: 9_450_000 picoseconds. - Weight::from_parts(9_881_000, 0) - .saturating_add(Weight::from_parts(0, 4277)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn one_fewer_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `2376` - // Estimated: `42428` - // Minimum execution time: 98_126_000 picoseconds. - Weight::from_parts(102_511_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn one_fewer_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `2362` - // Estimated: `42428` - // Minimum execution time: 99_398_000 picoseconds. - Weight::from_parts(104_045_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_requeued_insertion() -> Weight { - // Proof Size summary in bytes: - // Measured: `1807` - // Estimated: `4365` - // Minimum execution time: 43_734_000 picoseconds. - Weight::from_parts(46_962_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_requeued_slide() -> Weight { - // Proof Size summary in bytes: - // Measured: `1774` - // Estimated: `4365` - // Minimum execution time: 42_863_000 picoseconds. - Weight::from_parts(46_241_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `1790` - // Estimated: `4365` - // Minimum execution time: 57_511_000 picoseconds. - Weight::from_parts(64_027_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `1831` - // Estimated: `4365` - // Minimum execution time: 56_726_000 picoseconds. - Weight::from_parts(61_962_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_no_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `301` - // Estimated: `42428` - // Minimum execution time: 24_870_000 picoseconds. - Weight::from_parts(25_837_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `349` - // Estimated: `42428` - // Minimum execution time: 25_297_000 picoseconds. - Weight::from_parts(26_086_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn nudge_referendum_timed_out() -> Weight { - // Proof Size summary in bytes: - // Measured: `208` - // Estimated: `4365` - // Minimum execution time: 16_776_000 picoseconds. - Weight::from_parts(17_396_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `584` - // Estimated: `42428` - // Minimum execution time: 37_780_000 picoseconds. - Weight::from_parts(38_626_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `719` - // Estimated: `42428` - // Minimum execution time: 85_265_000 picoseconds. - Weight::from_parts(89_986_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `770` - // Estimated: `42428` - // Minimum execution time: 143_283_000 picoseconds. - Weight::from_parts(158_540_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_end_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `755` - // Estimated: `42428` - // Minimum execution time: 143_736_000 picoseconds. - Weight::from_parts(162_755_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_continue_not_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `770` - // Estimated: `42428` - // Minimum execution time: 139_021_000 picoseconds. - Weight::from_parts(157_398_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_continue_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `776` - // Estimated: `42428` - // Minimum execution time: 78_530_000 picoseconds. - Weight::from_parts(83_556_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - fn nudge_referendum_approved() -> Weight { - // Proof Size summary in bytes: - // Measured: `776` - // Estimated: `83866` - // Minimum execution time: 174_165_000 picoseconds. - Weight::from_parts(188_496_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_rejected() -> Weight { - // Proof Size summary in bytes: - // Measured: `772` - // Estimated: `42428` - // Minimum execution time: 142_964_000 picoseconds. - Weight::from_parts(157_257_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda MetadataOf (r:0 w:1) - /// Proof: FellowshipReferenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn set_some_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `352` - // Estimated: `4365` - // Minimum execution time: 20_126_000 picoseconds. - Weight::from_parts(20_635_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda MetadataOf (r:1 w:1) - /// Proof: FellowshipReferenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn clear_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `285` - // Estimated: `4365` - // Minimum execution time: 17_716_000 picoseconds. - Weight::from_parts(18_324_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/scripts/list-syscalls/execute-worker-syscalls b/polkadot/scripts/list-syscalls/execute-worker-syscalls index 349af783cf1a..4b22f6787864 100644 --- a/polkadot/scripts/list-syscalls/execute-worker-syscalls +++ b/polkadot/scripts/list-syscalls/execute-worker-syscalls @@ -20,6 +20,7 @@ 24 (sched_yield) 25 (mremap) 28 (madvise) +34 (pause) 39 (getpid) 41 (socket) 42 (connect) diff --git a/polkadot/scripts/list-syscalls/prepare-worker-syscalls b/polkadot/scripts/list-syscalls/prepare-worker-syscalls index 05281b61591a..fd46a788537d 100644 --- a/polkadot/scripts/list-syscalls/prepare-worker-syscalls +++ b/polkadot/scripts/list-syscalls/prepare-worker-syscalls @@ -20,6 +20,7 @@ 24 (sched_yield) 25 (mremap) 28 (madvise) +34 (pause) 39 (getpid) 41 (socket) 42 (connect) diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs index 1e90338a0f18..e3c470fcdeec 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -245,7 +245,8 @@ impl CandidateData { pub fn attested( &self, validity_threshold: usize, - ) -> Option> { + ) -> Option> + { let valid_votes = self.validity_votes.len(); if valid_votes < validity_threshold { return None @@ -321,7 +322,8 @@ impl Table { digest: &Ctx::Digest, context: &Ctx, minimum_backing_votes: u32, - ) -> Option> { + ) -> Option> + { self.candidate_votes.get(digest).and_then(|data| { let v_threshold = context.get_group_size(&data.group_id).map_or(usize::MAX, |len| { effective_minimum_backing_votes(len, minimum_backing_votes) diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs index 99f17693093e..7cb230f6e006 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs @@ -152,7 +152,7 @@ impl pallet_xcm::Config for Runtime { // We turn off sending for these tests type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = super::super::network::ParachainXcmRouter; // Provided by xcm-simulator - // Anyone can execute XCM programs + // Anyone can execute XCM programs type ExecuteXcmOrigin = EnsureXcmOrigin; // We execute any type of program type XcmExecuteFilter = Everything; diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs index 987bb3f9ab66..a31e664d8216 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs @@ -125,7 +125,7 @@ impl pallet_xcm::Config for Runtime { // No one can call `send` type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = super::super::network::RelayChainXcmRouter; // Provided by xcm-simulator - // Anyone can execute XCM programs + // Anyone can execute XCM programs type ExecuteXcmOrigin = EnsureXcmOrigin; // We execute any type of program type XcmExecuteFilter = Everything; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index 4a12bb7f47c6..210b8f656377 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -72,7 +72,7 @@ pub fn generate_holding_assets(max_assets: u32) -> Assets { let fungibles_amount: u128 = 100; let holding_fungibles = max_assets / 2; let holding_non_fungibles = max_assets - holding_fungibles - 1; // -1 because of adding `Here` asset - // add count of `holding_fungibles` + // add count of `holding_fungibles` (0..holding_fungibles) .map(|i| { Asset { diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 05d9046ab192..ee448c3df606 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -1939,6 +1939,10 @@ impl Pallet { ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let value = (origin, vec![fees.clone()]); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + ensure!( + ::IsReserve::contains(&fees, &dest), + Error::::InvalidAssetUnsupportedReserve + ); let context = T::UniversalLocation::get(); let reanchored_fees = fees @@ -1973,6 +1977,12 @@ impl Pallet { let value = (origin, assets); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); let (_, assets) = value; + for asset in assets.iter() { + ensure!( + ::IsReserve::contains(&asset, &dest), + Error::::InvalidAssetUnsupportedReserve + ); + } // max assets is `assets` (+ potentially separately handled fee) let max_assets = @@ -2079,6 +2089,10 @@ impl Pallet { ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let value = (origin, vec![fees.clone()]); ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); + ensure!( + ::IsTeleporter::contains(&fees, &dest), + Error::::Filtered + ); let context = T::UniversalLocation::get(); let reanchored_fees = fees @@ -2134,6 +2148,12 @@ impl Pallet { let value = (origin, assets); ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); let (_, assets) = value; + for asset in assets.iter() { + ensure!( + ::IsTeleporter::contains(&asset, &dest), + Error::::Filtered + ); + } // max assets is `assets` (+ potentially separately handled fee) let max_assets = diff --git a/polkadot/xcm/procedural/tests/ui.rs b/polkadot/xcm/procedural/tests/ui.rs index b3469b520eb7..4d0c8af45005 100644 --- a/polkadot/xcm/procedural/tests/ui.rs +++ b/polkadot/xcm/procedural/tests/ui.rs @@ -16,7 +16,6 @@ //! UI tests for XCM procedural macros -#[cfg(not(feature = "disable-ui-tests"))] #[test] fn ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. diff --git a/polkadot/xcm/xcm-builder/src/asset_conversion.rs b/polkadot/xcm/xcm-builder/src/asset_conversion.rs index 16ae05c20795..6d090b04886c 100644 --- a/polkadot/xcm/xcm-builder/src/asset_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/asset_conversion.rs @@ -137,7 +137,13 @@ impl< ConvertClassId: MaybeEquivalence, ConvertInstanceId: MaybeEquivalence, > MatchesNonFungibles - for MatchedConvertedConcreteId + for MatchedConvertedConcreteId< + ClassId, + InstanceId, + MatchClassId, + ConvertClassId, + ConvertInstanceId, + > { fn matches_nonfungibles(a: &Asset) -> result::Result<(ClassId, InstanceId), MatchError> { let (instance, class) = match (&a.fun, &a.id) { diff --git a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs index b111a05a4f1f..006c28954bce 100644 --- a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs @@ -270,7 +270,14 @@ impl< CheckAsset: AssetChecking, CheckingAccount: Get>, > TransactAsset - for NonFungiblesAdapter + for NonFungiblesAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + > { fn can_check_in(origin: &Location, what: &Asset, context: &XcmContext) -> XcmResult { NonFungiblesMutateAdapter::< diff --git a/polkadot/xcm/xcm-builder/tests/scenarios.rs b/polkadot/xcm/xcm-builder/tests/scenarios.rs index ee1aeffbb4e7..99c14f5bba1b 100644 --- a/polkadot/xcm/xcm-builder/tests/scenarios.rs +++ b/polkadot/xcm/xcm-builder/tests/scenarios.rs @@ -22,7 +22,7 @@ use mock::{ }; use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_runtime::traits::AccountIdConversion; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, Error::UntrustedTeleportLocation}; use xcm_executor::XcmExecutor; pub const ALICE: AccountId = AccountId::new([0u8; 32]); @@ -217,7 +217,7 @@ fn teleport_to_asset_hub_works() { ]; let weight = BaseXcmWeight::get() * 3; - // teleports are allowed to community chains, even in the absence of trust from their side. + // teleports are not allowed to other chains, in the absence of trust from their side let message = Xcm(vec![ WithdrawAsset((Here, amount).into()), buy_execution(), @@ -235,16 +235,7 @@ fn teleport_to_asset_hub_works() { weight, Weight::zero(), ); - assert_eq!(r, Outcome::Complete { used: weight }); - let expected_msg = Xcm(vec![ReceiveTeleportedAsset((Parent, amount).into()), ClearOrigin] - .into_iter() - .chain(teleport_effects.clone().into_iter()) - .collect()); - let expected_hash = fake_message_hash(&expected_msg); - assert_eq!( - mock::sent_xcm(), - vec![(Parachain(other_para_id).into(), expected_msg, expected_hash,)] - ); + assert_eq!(r, Outcome::Incomplete { used: weight, error: UntrustedTeleportLocation }); // teleports are allowed from asset hub to kusama. let message = Xcm(vec![ @@ -274,10 +265,7 @@ fn teleport_to_asset_hub_works() { let expected_hash = fake_message_hash(&expected_msg); assert_eq!( mock::sent_xcm(), - vec![ - (Parachain(other_para_id).into(), expected_msg.clone(), expected_hash,), - (Parachain(asset_hub_id).into(), expected_msg, expected_hash,) - ] + vec![(Parachain(asset_hub_id).into(), expected_msg, expected_hash,)] ); }); } diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index a8110ca3d19f..14920f36445b 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -1002,13 +1002,18 @@ impl XcmExecutor { InitiateReserveWithdraw { assets, reserve, xcm } => { let old_holding = self.holding.clone(); let result = Config::TransactionalProcessor::process(|| { + let assets = self.holding.saturating_take(assets); + // Must ensure that we recognise the assets as being managed by the destination. + #[cfg(not(feature = "runtime-benchmarks"))] + for asset in assets.assets_iter() { + ensure!( + Config::IsReserve::contains(&asset, &reserve), + XcmError::UntrustedReserveLocation + ); + } // Note that here we are able to place any assets which could not be reanchored // back into Holding. - let assets = Self::reanchored( - self.holding.saturating_take(assets), - &reserve, - Some(&mut self.holding), - ); + let assets = Self::reanchored(assets, &reserve, Some(&mut self.holding)); let mut message = vec![WithdrawAsset(assets), ClearOrigin]; message.extend(xcm.0.into_iter()); self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?; @@ -1024,6 +1029,14 @@ impl XcmExecutor { let result = (|| -> Result<(), XcmError> { // We must do this first in order to resolve wildcards. let assets = self.holding.saturating_take(assets); + // Must ensure that we have teleport trust with destination for these assets. + #[cfg(not(feature = "runtime-benchmarks"))] + for asset in assets.assets_iter() { + ensure!( + Config::IsTeleporter::contains(&asset, &dest), + XcmError::UntrustedTeleportLocation + ); + } for asset in assets.assets_iter() { // We should check that the asset can actually be teleported out (for this // to be in error, there would need to be an accounting violation by diff --git a/polkadot/xcm/xcm-executor/src/traits/export.rs b/polkadot/xcm/xcm-executor/src/traits/export.rs index 78aa68ce2644..b356e0da7df7 100644 --- a/polkadot/xcm/xcm-executor/src/traits/export.rs +++ b/polkadot/xcm/xcm-executor/src/traits/export.rs @@ -20,7 +20,7 @@ use xcm::latest::prelude::*; /// spoofed origin. This essentially defines the behaviour of the `ExportMessage` XCM instruction. /// /// This is quite different to `SendXcm`; `SendXcm` assumes that the local side's location will be -/// preserved to be represented as the value of the Origin register in the messages execution. +/// preserved to be represented as the value of the Origin register during the message's execution. /// /// This trait on the other hand assumes that we do not necessarily want the Origin register to /// contain the local (i.e. the caller chain's) location, since it will generally be exporting a @@ -44,8 +44,8 @@ pub trait ExportXcm { /// The `destination` and `message` must be `Some` (or else an error will be returned) and they /// may only be consumed if the `Err` is not `NotApplicable`. /// - /// If it is not a destination which can be reached with this type but possibly could by others, - /// then this *MUST* return `NotApplicable`. Any other error will cause the tuple + /// If it is not a destination that can be reached with this type, but possibly could be with + /// others, then this *MUST* return `NotApplicable`. Any other error will cause the tuple /// implementation (used to compose routing systems from different delivery agents) to exit /// early without trying alternative means of delivery. fn validate( diff --git a/polkadot/xcm/xcm-executor/src/traits/weight.rs b/polkadot/xcm/xcm-executor/src/traits/weight.rs index 72de3e0f433b..61545c330621 100644 --- a/polkadot/xcm/xcm-executor/src/traits/weight.rs +++ b/polkadot/xcm/xcm-executor/src/traits/weight.rs @@ -29,13 +29,6 @@ pub trait WeightBounds { fn instr_weight(instruction: &Instruction) -> Result; } -/// A means of getting approximate weight consumption for a given destination message executor and a -/// message. -pub trait UniversalWeigher { - /// Get the upper limit of weight required for `dest` to execute `message`. - fn weigh(dest: impl Into, message: Xcm<()>) -> Result; -} - /// Charge for weight in order to execute XCM. /// /// A `WeightTrader` may also be put into a tuple, in which case the default behavior of diff --git a/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs b/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs index c51a4a5376a3..f0a70b0dacfe 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs @@ -57,7 +57,12 @@ sp_api::decl_runtime_apis! { /// Calls or XCMs might fail when executed, this doesn't mean the result of these calls will be an `Err`. /// In those cases, there might still be a valid result, with the execution error inside it. /// The only reasons why these calls might return an error are listed in the [`Error`] enum. - pub trait DryRunApi { + pub trait DryRunApi + where + Call: Encode, + Event: Decode, + OriginCaller: Encode + { /// Dry run call. fn dry_run_call(origin: OriginCaller, call: Call) -> Result, Error>; diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index 889a50a2bab9..2d14b4e571c6 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -197,7 +197,7 @@ fn fee_estimation_for_teleport() { fn dry_run_reserve_asset_transfer() { sp_tracing::init_for_tests(); let who = 1; // AccountId = u64. - // Native token used for fees. + // Native token used for fees. let balances = vec![(who, DeliveryFees::get() + ExistentialDeposit::get())]; // Relay token is the one we want to transfer. let assets = vec![(1, who, 100)]; // id, account_id, balance. diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs index c5d5fa66732b..6218915cd12d 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs @@ -19,6 +19,7 @@ pub mod barrier; pub mod constants; pub mod location_converter; pub mod origin_converter; +pub mod teleporter; pub mod weigher; use crate::relay_chain::{RuntimeCall, XcmPallet}; @@ -36,7 +37,7 @@ impl Config for XcmConfig { type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = origin_converter::OriginConverter; type IsReserve = (); - type IsTeleporter = (); + type IsTeleporter = teleporter::TrustedTeleporters; type UniversalLocation = constants::UniversalLocation; type Barrier = barrier::Barrier; type Weigher = weigher::Weigher; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/teleporter.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/teleporter.rs new file mode 100644 index 000000000000..92e5065044e6 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/teleporter.rs @@ -0,0 +1,26 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub NftCollectionOnRelay: AssetFilter + = Wild(AllOf { fun: WildNonFungible, id: AssetId(GeneralIndex(1).into()) }); + pub NftCollectionForChild: (AssetFilter, Location) + = (NftCollectionOnRelay::get(), Parachain(1).into()); +} +pub type TrustedTeleporters = xcm_builder::Case; diff --git a/polkadot/zombienet-sdk-tests/Cargo.toml b/polkadot/zombienet-sdk-tests/Cargo.toml index 3374ad572b9f..4eac7af49f8a 100644 --- a/polkadot/zombienet-sdk-tests/Cargo.toml +++ b/polkadot/zombienet-sdk-tests/Cargo.toml @@ -8,16 +8,16 @@ license.workspace = true publish = false [dependencies] -env_logger = "0.11.2" -log = "0.4" -subxt = { version = "0.37", features = ["substrate-compat"] } -subxt-signer = { version = "0.37" } -tokio = { version = "1.36.0", features = ["rt-multi-thread"] } -anyhow = "1.0.81" -zombienet-sdk = "0.2.6" -serde = "1.0.197" -serde_json = "1.0.114" -parity-scale-codec = { version = "3.6.9", features = ["derive"] } +env_logger = { workspace = true } +log = { workspace = true } +subxt = { workspace = true, features = ["substrate-compat"] } +subxt-signer = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } +anyhow = { workspace = true } +zombienet-sdk = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +codec = { workspace = true, features = ["derive"] } [features] zombie-metadata = [] diff --git a/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml index 19c7015403d7..113de0e73aa1 100644 --- a/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml +++ b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml @@ -18,7 +18,7 @@ requests = { memory = "2G", cpu = "1" } [[relaychain.node_groups]] name = "alice" - args = [ "-lparachain=trace,runtime=debug" ] + args = [ "-lparachain=debug,runtime=debug" ] count = 13 [[parachains]] diff --git a/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.toml b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.toml new file mode 100644 index 000000000000..c035e23639c1 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.toml @@ -0,0 +1,120 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + needed_approvals = 4 + relay_vrf_modulo_samples = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + max_approval_coalesce_count = 5 + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "alice" + args = ["-lparachain=debug,runtime=debug", "--enable-approval-voting-parallel"] + count = 8 + + [[relaychain.node_groups]] + name = "bob" + args = ["-lparachain=debug,runtime=debug"] + count = 7 + +[[parachains]] +id = 2000 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=1" + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=1", "--parachain-id=2000"] + +[[parachains]] +id = 2001 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=10" + + [parachains.collator] + name = "collator02" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2001", "--pvf-complexity=10"] + +[[parachains]] +id = 2002 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=100" + + [parachains.collator] + name = "collator03" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2002", "--pvf-complexity=100"] + +[[parachains]] +id = 2003 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=300" + + [parachains.collator] + name = "collator04" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--parachain-id=2003", "--pvf-complexity=300"] + +[[parachains]] +id = 2004 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator05" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2004", "--pvf-complexity=300"] + +[[parachains]] +id = 2005 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=400" + + [parachains.collator] + name = "collator06" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--pvf-complexity=400", "--parachain-id=2005"] + +[[parachains]] +id = 2006 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator07" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=300", "--parachain-id=2006"] + +[[parachains]] +id = 2007 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator08" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=300", "--parachain-id=2007"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" \ No newline at end of file diff --git a/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.zndsl b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.zndsl new file mode 100644 index 000000000000..d70707747474 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.zndsl @@ -0,0 +1,35 @@ +Description: Check finality works with approval voting parallel enabled +Network: ./0016-approval-voting-parallel.toml +Creds: config + +# Check authority status. +alice: reports node_roles is 4 + +# Ensure parachains are registered. +alice: parachain 2000 is registered within 60 seconds +alice: parachain 2001 is registered within 60 seconds +alice: parachain 2002 is registered within 60 seconds +alice: parachain 2003 is registered within 60 seconds +alice: parachain 2004 is registered within 60 seconds +alice: parachain 2005 is registered within 60 seconds +alice: parachain 2006 is registered within 60 seconds +alice: parachain 2007 is registered within 60 seconds + +# Ensure parachains made progress. +alice: parachain 2000 block height is at least 10 within 300 seconds +alice: parachain 2001 block height is at least 10 within 300 seconds +alice: parachain 2002 block height is at least 10 within 300 seconds +alice: parachain 2003 block height is at least 10 within 300 seconds +alice: parachain 2004 block height is at least 10 within 300 seconds +alice: parachain 2005 block height is at least 10 within 300 seconds +alice: parachain 2006 block height is at least 10 within 300 seconds +alice: parachain 2007 block height is at least 10 within 300 seconds + +alice: reports substrate_block_height{status="finalized"} is at least 30 within 180 seconds +bob: reports substrate_block_height{status="finalized"} is at least 30 within 180 seconds + +alice: reports polkadot_parachain_approval_checking_finality_lag < 3 +bob: reports polkadot_parachain_approval_checking_finality_lag < 3 + +alice: reports polkadot_parachain_approvals_no_shows_total < 3 within 10 seconds +bob: reports polkadot_parachain_approvals_no_shows_total < 3 within 10 seconds diff --git a/prdoc/pr_2923.prdoc b/prdoc/1.16.0/pr_2923.prdoc similarity index 100% rename from prdoc/pr_2923.prdoc rename to prdoc/1.16.0/pr_2923.prdoc diff --git a/prdoc/pr_3049.prdoc b/prdoc/1.16.0/pr_3049.prdoc similarity index 100% rename from prdoc/pr_3049.prdoc rename to prdoc/1.16.0/pr_3049.prdoc diff --git a/prdoc/pr_3786.prdoc b/prdoc/1.16.0/pr_3786.prdoc similarity index 100% rename from prdoc/pr_3786.prdoc rename to prdoc/1.16.0/pr_3786.prdoc diff --git a/prdoc/pr_3996.prdoc b/prdoc/1.16.0/pr_3996.prdoc similarity index 100% rename from prdoc/pr_3996.prdoc rename to prdoc/1.16.0/pr_3996.prdoc diff --git a/prdoc/pr_4129.prdoc b/prdoc/1.16.0/pr_4129.prdoc similarity index 100% rename from prdoc/pr_4129.prdoc rename to prdoc/1.16.0/pr_4129.prdoc diff --git a/prdoc/pr_4424.prdoc b/prdoc/1.16.0/pr_4424.prdoc similarity index 100% rename from prdoc/pr_4424.prdoc rename to prdoc/1.16.0/pr_4424.prdoc diff --git a/prdoc/pr_4460.prdoc b/prdoc/1.16.0/pr_4460.prdoc similarity index 100% rename from prdoc/pr_4460.prdoc rename to prdoc/1.16.0/pr_4460.prdoc diff --git a/prdoc/pr_4487.prdoc b/prdoc/1.16.0/pr_4487.prdoc similarity index 100% rename from prdoc/pr_4487.prdoc rename to prdoc/1.16.0/pr_4487.prdoc diff --git a/prdoc/pr_4488.prdoc b/prdoc/1.16.0/pr_4488.prdoc similarity index 100% rename from prdoc/pr_4488.prdoc rename to prdoc/1.16.0/pr_4488.prdoc diff --git a/prdoc/pr_4527.prdoc b/prdoc/1.16.0/pr_4527.prdoc similarity index 100% rename from prdoc/pr_4527.prdoc rename to prdoc/1.16.0/pr_4527.prdoc diff --git a/prdoc/pr_4564.prdoc b/prdoc/1.16.0/pr_4564.prdoc similarity index 100% rename from prdoc/pr_4564.prdoc rename to prdoc/1.16.0/pr_4564.prdoc diff --git a/prdoc/pr_4586.prdoc b/prdoc/1.16.0/pr_4586.prdoc similarity index 100% rename from prdoc/pr_4586.prdoc rename to prdoc/1.16.0/pr_4586.prdoc diff --git a/prdoc/pr_4613.prdoc b/prdoc/1.16.0/pr_4613.prdoc similarity index 100% rename from prdoc/pr_4613.prdoc rename to prdoc/1.16.0/pr_4613.prdoc diff --git a/prdoc/pr_4640.prdoc b/prdoc/1.16.0/pr_4640.prdoc similarity index 100% rename from prdoc/pr_4640.prdoc rename to prdoc/1.16.0/pr_4640.prdoc diff --git a/prdoc/pr_4665.prdoc b/prdoc/1.16.0/pr_4665.prdoc similarity index 100% rename from prdoc/pr_4665.prdoc rename to prdoc/1.16.0/pr_4665.prdoc diff --git a/prdoc/pr_4706.prdoc b/prdoc/1.16.0/pr_4706.prdoc similarity index 100% rename from prdoc/pr_4706.prdoc rename to prdoc/1.16.0/pr_4706.prdoc diff --git a/prdoc/pr_4739.prdoc b/prdoc/1.16.0/pr_4739.prdoc similarity index 100% rename from prdoc/pr_4739.prdoc rename to prdoc/1.16.0/pr_4739.prdoc diff --git a/prdoc/pr_4751.prdoc b/prdoc/1.16.0/pr_4751.prdoc similarity index 100% rename from prdoc/pr_4751.prdoc rename to prdoc/1.16.0/pr_4751.prdoc diff --git a/prdoc/pr_4792.prdoc b/prdoc/1.16.0/pr_4792.prdoc similarity index 100% rename from prdoc/pr_4792.prdoc rename to prdoc/1.16.0/pr_4792.prdoc diff --git a/prdoc/pr_4822.prdoc b/prdoc/1.16.0/pr_4822.prdoc similarity index 100% rename from prdoc/pr_4822.prdoc rename to prdoc/1.16.0/pr_4822.prdoc diff --git a/prdoc/pr_4845.prdoc b/prdoc/1.16.0/pr_4845.prdoc similarity index 100% rename from prdoc/pr_4845.prdoc rename to prdoc/1.16.0/pr_4845.prdoc diff --git a/prdoc/pr_4928.prdoc b/prdoc/1.16.0/pr_4928.prdoc similarity index 100% rename from prdoc/pr_4928.prdoc rename to prdoc/1.16.0/pr_4928.prdoc diff --git a/prdoc/pr_4930.prdoc b/prdoc/1.16.0/pr_4930.prdoc similarity index 100% rename from prdoc/pr_4930.prdoc rename to prdoc/1.16.0/pr_4930.prdoc diff --git a/prdoc/pr_4936.prdoc b/prdoc/1.16.0/pr_4936.prdoc similarity index 100% rename from prdoc/pr_4936.prdoc rename to prdoc/1.16.0/pr_4936.prdoc diff --git a/prdoc/pr_4938.prdoc b/prdoc/1.16.0/pr_4938.prdoc similarity index 100% rename from prdoc/pr_4938.prdoc rename to prdoc/1.16.0/pr_4938.prdoc diff --git a/prdoc/pr_4949.prdoc b/prdoc/1.16.0/pr_4949.prdoc similarity index 100% rename from prdoc/pr_4949.prdoc rename to prdoc/1.16.0/pr_4949.prdoc diff --git a/prdoc/pr_4956.prdoc b/prdoc/1.16.0/pr_4956.prdoc similarity index 100% rename from prdoc/pr_4956.prdoc rename to prdoc/1.16.0/pr_4956.prdoc diff --git a/prdoc/pr_4959.prdoc b/prdoc/1.16.0/pr_4959.prdoc similarity index 100% rename from prdoc/pr_4959.prdoc rename to prdoc/1.16.0/pr_4959.prdoc diff --git a/prdoc/pr_4962.prdoc b/prdoc/1.16.0/pr_4962.prdoc similarity index 100% rename from prdoc/pr_4962.prdoc rename to prdoc/1.16.0/pr_4962.prdoc diff --git a/prdoc/pr_4963.prdoc b/prdoc/1.16.0/pr_4963.prdoc similarity index 100% rename from prdoc/pr_4963.prdoc rename to prdoc/1.16.0/pr_4963.prdoc diff --git a/prdoc/pr_4967.prdoc b/prdoc/1.16.0/pr_4967.prdoc similarity index 100% rename from prdoc/pr_4967.prdoc rename to prdoc/1.16.0/pr_4967.prdoc diff --git a/prdoc/pr_4970.prdoc b/prdoc/1.16.0/pr_4970.prdoc similarity index 100% rename from prdoc/pr_4970.prdoc rename to prdoc/1.16.0/pr_4970.prdoc diff --git a/prdoc/pr_4973.prdoc b/prdoc/1.16.0/pr_4973.prdoc similarity index 100% rename from prdoc/pr_4973.prdoc rename to prdoc/1.16.0/pr_4973.prdoc diff --git a/prdoc/pr_4976.prdoc b/prdoc/1.16.0/pr_4976.prdoc similarity index 100% rename from prdoc/pr_4976.prdoc rename to prdoc/1.16.0/pr_4976.prdoc diff --git a/prdoc/pr_4993.prdoc b/prdoc/1.16.0/pr_4993.prdoc similarity index 100% rename from prdoc/pr_4993.prdoc rename to prdoc/1.16.0/pr_4993.prdoc diff --git a/prdoc/pr_4998.prdoc b/prdoc/1.16.0/pr_4998.prdoc similarity index 100% rename from prdoc/pr_4998.prdoc rename to prdoc/1.16.0/pr_4998.prdoc diff --git a/prdoc/pr_4999.prdoc b/prdoc/1.16.0/pr_4999.prdoc similarity index 100% rename from prdoc/pr_4999.prdoc rename to prdoc/1.16.0/pr_4999.prdoc diff --git a/prdoc/pr_5029.prdoc b/prdoc/1.16.0/pr_5029.prdoc similarity index 100% rename from prdoc/pr_5029.prdoc rename to prdoc/1.16.0/pr_5029.prdoc diff --git a/prdoc/pr_5036.prdoc b/prdoc/1.16.0/pr_5036.prdoc similarity index 100% rename from prdoc/pr_5036.prdoc rename to prdoc/1.16.0/pr_5036.prdoc diff --git a/prdoc/pr_5055.prdoc b/prdoc/1.16.0/pr_5055.prdoc similarity index 100% rename from prdoc/pr_5055.prdoc rename to prdoc/1.16.0/pr_5055.prdoc diff --git a/prdoc/pr_5065.prdoc b/prdoc/1.16.0/pr_5065.prdoc similarity index 100% rename from prdoc/pr_5065.prdoc rename to prdoc/1.16.0/pr_5065.prdoc diff --git a/prdoc/pr_5067.prdoc b/prdoc/1.16.0/pr_5067.prdoc similarity index 100% rename from prdoc/pr_5067.prdoc rename to prdoc/1.16.0/pr_5067.prdoc diff --git a/prdoc/pr_5074.prdoc b/prdoc/1.16.0/pr_5074.prdoc similarity index 100% rename from prdoc/pr_5074.prdoc rename to prdoc/1.16.0/pr_5074.prdoc diff --git a/prdoc/pr_5078.prdoc b/prdoc/1.16.0/pr_5078.prdoc similarity index 100% rename from prdoc/pr_5078.prdoc rename to prdoc/1.16.0/pr_5078.prdoc diff --git a/prdoc/pr_5082.prdoc b/prdoc/1.16.0/pr_5082.prdoc similarity index 100% rename from prdoc/pr_5082.prdoc rename to prdoc/1.16.0/pr_5082.prdoc diff --git a/prdoc/pr_5113.prdoc b/prdoc/1.16.0/pr_5113.prdoc similarity index 100% rename from prdoc/pr_5113.prdoc rename to prdoc/1.16.0/pr_5113.prdoc diff --git a/prdoc/pr_5114.prdoc b/prdoc/1.16.0/pr_5114.prdoc similarity index 100% rename from prdoc/pr_5114.prdoc rename to prdoc/1.16.0/pr_5114.prdoc diff --git a/prdoc/pr_5124.prdoc b/prdoc/1.16.0/pr_5124.prdoc similarity index 100% rename from prdoc/pr_5124.prdoc rename to prdoc/1.16.0/pr_5124.prdoc diff --git a/prdoc/pr_5127.prdoc b/prdoc/1.16.0/pr_5127.prdoc similarity index 100% rename from prdoc/pr_5127.prdoc rename to prdoc/1.16.0/pr_5127.prdoc diff --git a/prdoc/pr_5129.prdoc b/prdoc/1.16.0/pr_5129.prdoc similarity index 100% rename from prdoc/pr_5129.prdoc rename to prdoc/1.16.0/pr_5129.prdoc diff --git a/prdoc/pr_5130.prdoc b/prdoc/1.16.0/pr_5130.prdoc similarity index 100% rename from prdoc/pr_5130.prdoc rename to prdoc/1.16.0/pr_5130.prdoc diff --git a/prdoc/pr_5131.prdoc b/prdoc/1.16.0/pr_5131.prdoc similarity index 100% rename from prdoc/pr_5131.prdoc rename to prdoc/1.16.0/pr_5131.prdoc diff --git a/prdoc/pr_5132.prdoc b/prdoc/1.16.0/pr_5132.prdoc similarity index 100% rename from prdoc/pr_5132.prdoc rename to prdoc/1.16.0/pr_5132.prdoc diff --git a/prdoc/pr_5142.prdoc b/prdoc/1.16.0/pr_5142.prdoc similarity index 100% rename from prdoc/pr_5142.prdoc rename to prdoc/1.16.0/pr_5142.prdoc diff --git a/prdoc/pr_5155.prdoc b/prdoc/1.16.0/pr_5155.prdoc similarity index 100% rename from prdoc/pr_5155.prdoc rename to prdoc/1.16.0/pr_5155.prdoc diff --git a/prdoc/pr_5173.prdoc b/prdoc/1.16.0/pr_5173.prdoc similarity index 100% rename from prdoc/pr_5173.prdoc rename to prdoc/1.16.0/pr_5173.prdoc diff --git a/prdoc/pr_5174.prdoc b/prdoc/1.16.0/pr_5174.prdoc similarity index 100% rename from prdoc/pr_5174.prdoc rename to prdoc/1.16.0/pr_5174.prdoc diff --git a/prdoc/pr_5188.prdoc b/prdoc/1.16.0/pr_5188.prdoc similarity index 100% rename from prdoc/pr_5188.prdoc rename to prdoc/1.16.0/pr_5188.prdoc diff --git a/prdoc/pr_5195.prdoc b/prdoc/1.16.0/pr_5195.prdoc similarity index 100% rename from prdoc/pr_5195.prdoc rename to prdoc/1.16.0/pr_5195.prdoc diff --git a/prdoc/pr_5196.prdoc b/prdoc/1.16.0/pr_5196.prdoc similarity index 100% rename from prdoc/pr_5196.prdoc rename to prdoc/1.16.0/pr_5196.prdoc diff --git a/prdoc/pr_5197.prdoc b/prdoc/1.16.0/pr_5197.prdoc similarity index 100% rename from prdoc/pr_5197.prdoc rename to prdoc/1.16.0/pr_5197.prdoc diff --git a/prdoc/pr_5204.prdoc b/prdoc/1.16.0/pr_5204.prdoc similarity index 100% rename from prdoc/pr_5204.prdoc rename to prdoc/1.16.0/pr_5204.prdoc diff --git a/prdoc/pr_5205.prdoc b/prdoc/1.16.0/pr_5205.prdoc similarity index 100% rename from prdoc/pr_5205.prdoc rename to prdoc/1.16.0/pr_5205.prdoc diff --git a/prdoc/pr_5214.prdoc b/prdoc/1.16.0/pr_5214.prdoc similarity index 100% rename from prdoc/pr_5214.prdoc rename to prdoc/1.16.0/pr_5214.prdoc diff --git a/prdoc/pr_5240.prdoc b/prdoc/1.16.0/pr_5240.prdoc similarity index 100% rename from prdoc/pr_5240.prdoc rename to prdoc/1.16.0/pr_5240.prdoc diff --git a/prdoc/pr_5250.prdoc b/prdoc/1.16.0/pr_5250.prdoc similarity index 100% rename from prdoc/pr_5250.prdoc rename to prdoc/1.16.0/pr_5250.prdoc diff --git a/prdoc/pr_5252.prdoc b/prdoc/1.16.0/pr_5252.prdoc similarity index 100% rename from prdoc/pr_5252.prdoc rename to prdoc/1.16.0/pr_5252.prdoc diff --git a/prdoc/pr_5257.prdoc b/prdoc/1.16.0/pr_5257.prdoc similarity index 100% rename from prdoc/pr_5257.prdoc rename to prdoc/1.16.0/pr_5257.prdoc diff --git a/prdoc/pr_5262.prdoc b/prdoc/1.16.0/pr_5262.prdoc similarity index 100% rename from prdoc/pr_5262.prdoc rename to prdoc/1.16.0/pr_5262.prdoc diff --git a/prdoc/pr_5269.prdoc b/prdoc/1.16.0/pr_5269.prdoc similarity index 100% rename from prdoc/pr_5269.prdoc rename to prdoc/1.16.0/pr_5269.prdoc diff --git a/prdoc/pr_5270.prdoc b/prdoc/1.16.0/pr_5270.prdoc similarity index 100% rename from prdoc/pr_5270.prdoc rename to prdoc/1.16.0/pr_5270.prdoc diff --git a/prdoc/pr_5284.prdoc b/prdoc/1.16.0/pr_5284.prdoc similarity index 100% rename from prdoc/pr_5284.prdoc rename to prdoc/1.16.0/pr_5284.prdoc diff --git a/prdoc/pr_5288.prdoc b/prdoc/1.16.0/pr_5288.prdoc similarity index 100% rename from prdoc/pr_5288.prdoc rename to prdoc/1.16.0/pr_5288.prdoc diff --git a/prdoc/pr_5293.prdoc b/prdoc/1.16.0/pr_5293.prdoc similarity index 100% rename from prdoc/pr_5293.prdoc rename to prdoc/1.16.0/pr_5293.prdoc diff --git a/prdoc/pr_5316.prdoc b/prdoc/1.16.0/pr_5316.prdoc similarity index 100% rename from prdoc/pr_5316.prdoc rename to prdoc/1.16.0/pr_5316.prdoc diff --git a/prdoc/pr_5326.prdoc b/prdoc/1.16.0/pr_5326.prdoc similarity index 100% rename from prdoc/pr_5326.prdoc rename to prdoc/1.16.0/pr_5326.prdoc diff --git a/prdoc/pr_5327.prdoc b/prdoc/1.16.0/pr_5327.prdoc similarity index 100% rename from prdoc/pr_5327.prdoc rename to prdoc/1.16.0/pr_5327.prdoc diff --git a/prdoc/pr_5339.prdoc b/prdoc/1.16.0/pr_5339.prdoc similarity index 100% rename from prdoc/pr_5339.prdoc rename to prdoc/1.16.0/pr_5339.prdoc diff --git a/prdoc/pr_5344.prdoc b/prdoc/1.16.0/pr_5344.prdoc similarity index 100% rename from prdoc/pr_5344.prdoc rename to prdoc/1.16.0/pr_5344.prdoc diff --git a/prdoc/pr_5348.prdoc b/prdoc/1.16.0/pr_5348.prdoc similarity index 100% rename from prdoc/pr_5348.prdoc rename to prdoc/1.16.0/pr_5348.prdoc diff --git a/prdoc/pr_5352.prdoc b/prdoc/1.16.0/pr_5352.prdoc similarity index 100% rename from prdoc/pr_5352.prdoc rename to prdoc/1.16.0/pr_5352.prdoc diff --git a/prdoc/pr_5354.prdoc b/prdoc/1.16.0/pr_5354.prdoc similarity index 100% rename from prdoc/pr_5354.prdoc rename to prdoc/1.16.0/pr_5354.prdoc diff --git a/prdoc/pr_5356.prdoc b/prdoc/1.16.0/pr_5356.prdoc similarity index 100% rename from prdoc/pr_5356.prdoc rename to prdoc/1.16.0/pr_5356.prdoc diff --git a/prdoc/pr_5359.prdoc b/prdoc/1.16.0/pr_5359.prdoc similarity index 100% rename from prdoc/pr_5359.prdoc rename to prdoc/1.16.0/pr_5359.prdoc diff --git a/prdoc/pr_5360.prdoc b/prdoc/1.16.0/pr_5360.prdoc similarity index 100% rename from prdoc/pr_5360.prdoc rename to prdoc/1.16.0/pr_5360.prdoc diff --git a/prdoc/pr_5364.prdoc b/prdoc/1.16.0/pr_5364.prdoc similarity index 100% rename from prdoc/pr_5364.prdoc rename to prdoc/1.16.0/pr_5364.prdoc diff --git a/prdoc/pr_5369.prdoc b/prdoc/1.16.0/pr_5369.prdoc similarity index 100% rename from prdoc/pr_5369.prdoc rename to prdoc/1.16.0/pr_5369.prdoc diff --git a/prdoc/pr_5376.prdoc b/prdoc/1.16.0/pr_5376.prdoc similarity index 100% rename from prdoc/pr_5376.prdoc rename to prdoc/1.16.0/pr_5376.prdoc diff --git a/prdoc/pr_5380.prdoc b/prdoc/1.16.0/pr_5380.prdoc similarity index 100% rename from prdoc/pr_5380.prdoc rename to prdoc/1.16.0/pr_5380.prdoc diff --git a/prdoc/pr_5384.prdoc b/prdoc/1.16.0/pr_5384.prdoc similarity index 100% rename from prdoc/pr_5384.prdoc rename to prdoc/1.16.0/pr_5384.prdoc diff --git a/prdoc/pr_5392.prdoc b/prdoc/1.16.0/pr_5392.prdoc similarity index 100% rename from prdoc/pr_5392.prdoc rename to prdoc/1.16.0/pr_5392.prdoc diff --git a/prdoc/pr_5393.prdoc b/prdoc/1.16.0/pr_5393.prdoc similarity index 100% rename from prdoc/pr_5393.prdoc rename to prdoc/1.16.0/pr_5393.prdoc diff --git a/prdoc/pr_5396.prdoc b/prdoc/1.16.0/pr_5396.prdoc similarity index 100% rename from prdoc/pr_5396.prdoc rename to prdoc/1.16.0/pr_5396.prdoc diff --git a/prdoc/pr_5407.prdoc b/prdoc/1.16.0/pr_5407.prdoc similarity index 100% rename from prdoc/pr_5407.prdoc rename to prdoc/1.16.0/pr_5407.prdoc diff --git a/prdoc/pr_5410.prdoc b/prdoc/1.16.0/pr_5410.prdoc similarity index 100% rename from prdoc/pr_5410.prdoc rename to prdoc/1.16.0/pr_5410.prdoc diff --git a/prdoc/pr_5411.prdoc b/prdoc/1.16.0/pr_5411.prdoc similarity index 100% rename from prdoc/pr_5411.prdoc rename to prdoc/1.16.0/pr_5411.prdoc diff --git a/prdoc/pr_5424.prdoc b/prdoc/1.16.0/pr_5424.prdoc similarity index 100% rename from prdoc/pr_5424.prdoc rename to prdoc/1.16.0/pr_5424.prdoc diff --git a/prdoc/pr_5430.prdoc b/prdoc/1.16.0/pr_5430.prdoc similarity index 100% rename from prdoc/pr_5430.prdoc rename to prdoc/1.16.0/pr_5430.prdoc diff --git a/prdoc/pr_5431.prdoc b/prdoc/1.16.0/pr_5431.prdoc similarity index 100% rename from prdoc/pr_5431.prdoc rename to prdoc/1.16.0/pr_5431.prdoc diff --git a/prdoc/pr_5436.prdoc b/prdoc/1.16.0/pr_5436.prdoc similarity index 100% rename from prdoc/pr_5436.prdoc rename to prdoc/1.16.0/pr_5436.prdoc diff --git a/prdoc/pr_5439.prdoc b/prdoc/1.16.0/pr_5439.prdoc similarity index 100% rename from prdoc/pr_5439.prdoc rename to prdoc/1.16.0/pr_5439.prdoc diff --git a/prdoc/pr_5442.prdoc b/prdoc/1.16.0/pr_5442.prdoc similarity index 100% rename from prdoc/pr_5442.prdoc rename to prdoc/1.16.0/pr_5442.prdoc diff --git a/prdoc/pr_5443.prdoc b/prdoc/1.16.0/pr_5443.prdoc similarity index 100% rename from prdoc/pr_5443.prdoc rename to prdoc/1.16.0/pr_5443.prdoc diff --git a/prdoc/pr_5450.prdoc b/prdoc/1.16.0/pr_5450.prdoc similarity index 100% rename from prdoc/pr_5450.prdoc rename to prdoc/1.16.0/pr_5450.prdoc diff --git a/prdoc/pr_5465.prdoc b/prdoc/1.16.0/pr_5465.prdoc similarity index 100% rename from prdoc/pr_5465.prdoc rename to prdoc/1.16.0/pr_5465.prdoc diff --git a/prdoc/pr_5466.prdoc b/prdoc/1.16.0/pr_5466.prdoc similarity index 100% rename from prdoc/pr_5466.prdoc rename to prdoc/1.16.0/pr_5466.prdoc diff --git a/prdoc/pr_5467.prdoc b/prdoc/1.16.0/pr_5467.prdoc similarity index 100% rename from prdoc/pr_5467.prdoc rename to prdoc/1.16.0/pr_5467.prdoc diff --git a/prdoc/pr_5509.prdoc b/prdoc/1.16.0/pr_5509.prdoc similarity index 100% rename from prdoc/pr_5509.prdoc rename to prdoc/1.16.0/pr_5509.prdoc diff --git a/prdoc/pr_5513.prdoc b/prdoc/1.16.0/pr_5513.prdoc similarity index 100% rename from prdoc/pr_5513.prdoc rename to prdoc/1.16.0/pr_5513.prdoc diff --git a/prdoc/pr_5527.prdoc b/prdoc/1.16.0/pr_5527.prdoc similarity index 100% rename from prdoc/pr_5527.prdoc rename to prdoc/1.16.0/pr_5527.prdoc diff --git a/prdoc/pr_5538.prdoc b/prdoc/1.16.0/pr_5538.prdoc similarity index 100% rename from prdoc/pr_5538.prdoc rename to prdoc/1.16.0/pr_5538.prdoc diff --git a/prdoc/pr_5546.prdoc b/prdoc/1.16.0/pr_5546.prdoc similarity index 100% rename from prdoc/pr_5546.prdoc rename to prdoc/1.16.0/pr_5546.prdoc diff --git a/prdoc/pr_5563.prdoc b/prdoc/1.16.0/pr_5563.prdoc similarity index 100% rename from prdoc/pr_5563.prdoc rename to prdoc/1.16.0/pr_5563.prdoc diff --git a/prdoc/pr_5580.prdoc b/prdoc/1.16.0/pr_5580.prdoc similarity index 100% rename from prdoc/pr_5580.prdoc rename to prdoc/1.16.0/pr_5580.prdoc diff --git a/prdoc/pr_5581.prdoc b/prdoc/1.16.0/pr_5581.prdoc similarity index 100% rename from prdoc/pr_5581.prdoc rename to prdoc/1.16.0/pr_5581.prdoc diff --git a/prdoc/pr_5594.prdoc b/prdoc/1.16.0/pr_5594.prdoc similarity index 100% rename from prdoc/pr_5594.prdoc rename to prdoc/1.16.0/pr_5594.prdoc diff --git a/prdoc/pr_5632.prdoc b/prdoc/1.16.0/pr_5632.prdoc similarity index 100% rename from prdoc/pr_5632.prdoc rename to prdoc/1.16.0/pr_5632.prdoc diff --git a/prdoc/pr_5644.prdoc b/prdoc/1.16.0/pr_5644.prdoc similarity index 100% rename from prdoc/pr_5644.prdoc rename to prdoc/1.16.0/pr_5644.prdoc diff --git a/prdoc/1.16.0/pr_5649.prdoc b/prdoc/1.16.0/pr_5649.prdoc new file mode 100644 index 000000000000..1f4c97aa1753 --- /dev/null +++ b/prdoc/1.16.0/pr_5649.prdoc @@ -0,0 +1,49 @@ +title: "Bridges lane id agnostic for backwards compatibility" + +doc: +- audience: Runtime Dev + description: | + This PR improves support for handling `LaneId` backwards compatibility with the previously merged [PR](https://github.com/paritytech/polkadot-sdk/pull/4949). + If `pallet_bridge_messages` or `pallet_bridge_relayers` used `LaneId([u8; 4])` previously, they should now set `type LaneId = LegacyLaneId;`. + +crates: +- name: bridge-runtime-common + bump: patch +- name: bp-runtime + bump: patch +- name: staging-xcm-executor + bump: none +- name: parachains-runtimes-test-utils + bump: patch +- name: bp-messages + bump: major +- name: bp-relayers + bump: major +- name: bp-xcm-bridge-hub + bump: major +- name: pallet-bridge-messages + bump: patch +- name: pallet-bridge-relayers + bump: patch +- name: pallet-xcm-bridge-hub + bump: major +- name: emulated-integration-tests-common + bump: patch +- name: bp-bridge-hub-kusama + bump: patch +- name: bp-bridge-hub-polkadot + bump: patch +- name: bp-bridge-hub-rococo + bump: patch +- name: bp-bridge-hub-westend + bump: patch +- name: bp-polkadot-bulletin + bump: patch +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: patch +- name: polkadot-parachain-bin + bump: none +- name: bridge-hub-test-utils + bump: major diff --git a/prdoc/pr_5655.prdoc b/prdoc/1.16.0/pr_5655.prdoc similarity index 100% rename from prdoc/pr_5655.prdoc rename to prdoc/1.16.0/pr_5655.prdoc diff --git a/prdoc/1.16.0/pr_5660.prdoc b/prdoc/1.16.0/pr_5660.prdoc new file mode 100644 index 000000000000..fce791cebb65 --- /dev/null +++ b/prdoc/1.16.0/pr_5660.prdoc @@ -0,0 +1,30 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "xcm-executor: validate destinations for ReserveWithdraw and Teleport transfers" + +doc: + - audience: + - Runtime User + - Runtime Dev + description: | + This change adds the required validation for stronger UX guarantees when using + `InitiateReserveWithdraw` or `InitiateTeleport` XCM instructions. Execution of + the instructions will fail if the local chain is not configured to trust the + "destination" or "reserve" chain as a reserve/trusted-teleporter for the provided + "assets". + With this change, misuse of `InitiateReserveWithdraw`/`InitiateTeleport` fails on + origin with no overall side-effects, rather than failing on destination (with + side-effects to origin's assets issuance). + The commit also makes the same validations for pallet-xcm transfers, and adds + regression tests. + +crates: + - name: staging-xcm-executor + bump: patch + - name: staging-xcm-builder + bump: patch + - name: pallet-xcm + bump: patch + - name: xcm-simulator-example + bump: patch diff --git a/prdoc/pr_5671.prdoc b/prdoc/1.16.0/pr_5671.prdoc similarity index 100% rename from prdoc/pr_5671.prdoc rename to prdoc/1.16.0/pr_5671.prdoc diff --git a/prdoc/pr_5678.prdoc b/prdoc/1.16.0/pr_5678.prdoc similarity index 94% rename from prdoc/pr_5678.prdoc rename to prdoc/1.16.0/pr_5678.prdoc index af1fac31c560..ebb5e5a0d79f 100644 --- a/prdoc/pr_5678.prdoc +++ b/prdoc/1.16.0/pr_5678.prdoc @@ -1,6 +1,6 @@ title: 'rpc server: fix deny unsafe on RpcMethods::Auto' doc: -- audience: Node User +- audience: Node Operator description: |- Close #5677 diff --git a/prdoc/pr_5688.prdoc b/prdoc/1.16.0/pr_5688.prdoc similarity index 100% rename from prdoc/pr_5688.prdoc rename to prdoc/1.16.0/pr_5688.prdoc diff --git a/prdoc/pr_5695.prdoc b/prdoc/1.16.0/pr_5695.prdoc similarity index 100% rename from prdoc/pr_5695.prdoc rename to prdoc/1.16.0/pr_5695.prdoc diff --git a/prdoc/pr_5712.prdoc b/prdoc/1.16.0/pr_5712.prdoc similarity index 100% rename from prdoc/pr_5712.prdoc rename to prdoc/1.16.0/pr_5712.prdoc diff --git a/prdoc/pr_5713.prdoc b/prdoc/1.16.0/pr_5713.prdoc similarity index 100% rename from prdoc/pr_5713.prdoc rename to prdoc/1.16.0/pr_5713.prdoc diff --git a/prdoc/pr_5747.prdoc b/prdoc/1.16.0/pr_5747.prdoc similarity index 100% rename from prdoc/pr_5747.prdoc rename to prdoc/1.16.0/pr_5747.prdoc diff --git a/prdoc/pr_4251.prdoc b/prdoc/pr_4251.prdoc new file mode 100644 index 000000000000..4d4fcd734692 --- /dev/null +++ b/prdoc/pr_4251.prdoc @@ -0,0 +1,79 @@ +title: MBM `try-runtime` support +doc: +- audience: Runtime Dev + description: | + # MBM try-runtime support + + This MR adds support to the try-runtime + trait such that the try-runtime-CLI will be able to support MBM testing [here](https://github.com/paritytech/try-runtime-cli/pull/90). + It mainly adds two feature-gated hooks to the `SteppedMigration` hook to facilitate + testing. These hooks are named `pre_upgrade` and `post_upgrade` and have the + same signature and implications as for single-block migrations. + + ## Integration + + To make use of this in your Multi-Block-Migration, just implement the two new hooks and test pre- and post-conditions in them: + + ```rust + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, frame_support::sp_runtime::TryRuntimeError> + { + // ... + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev: Vec) -> Result<(), frame_support::sp_runtime::TryRuntimeError> { + // ... + } + ``` + + You may return an error or panic in these functions to indicate failure. + This will then show up in the try-runtime-CLI and can be used in CI for testing. + + + Changes: + - Adds `try-runtime` gated methods `pre_upgrade` and `post_upgrade` + on `SteppedMigration` + - Adds `try-runtime` gated methods `nth_pre_upgrade` + and `nth_post_upgrade` on `SteppedMigrations` + - Modifies `pallet_migrations` + implementation to run pre_upgrade and post_upgrade steps at the appropriate times, and panic in the event of migration failure. +crates: +- name: asset-hub-rococo-runtime + bump: minor +- name: asset-hub-westend-runtime + bump: minor +- name: bridge-hub-rococo-runtime + bump: minor +- name: bridge-hub-westend-runtime + bump: minor +- name: collectives-westend-runtime + bump: minor +- name: contracts-rococo-runtime + bump: minor +- name: coretime-rococo-runtime + bump: minor +- name: coretime-westend-runtime + bump: minor +- name: people-rococo-runtime + bump: minor +- name: people-westend-runtime + bump: minor +- name: penpal-runtime + bump: minor +- name: polkadot-parachain-bin + bump: minor +- name: rococo-runtime + bump: minor +- name: westend-runtime + bump: minor +- name: frame-executive + bump: minor +- name: pallet-migrations + bump: minor +- name: frame-support + bump: minor +- name: frame-system + bump: minor +- name: frame-try-runtime + bump: minor diff --git a/prdoc/pr_4849.prdoc b/prdoc/pr_4849.prdoc new file mode 100644 index 000000000000..185295151068 --- /dev/null +++ b/prdoc/pr_4849.prdoc @@ -0,0 +1,47 @@ +title: Introduce approval-voting-parallel subsystem + +doc: + - audience: Node Dev + description: | + This introduces a new subsystem called approval-voting-parallel. It combines the tasks + previously handled by the approval-voting and approval-distribution subsystems. + + The new subsystem is enabled by default on all test networks. On production networks + like Polkadot and Kusama, the legacy system with two separate subsystems is still in use. + However, there is a CLI option --enable-approval-voting-parallel to gradually roll out + the new subsystem on specific nodes. Once we are confident that it works as expected, + it will be enabled by default on all networks. + + The approval-voting-parallel subsystem coordinates two groups of workers: + - Four approval-distribution workers that operate in parallel, each handling tasks based + on the validator_index of the message originator. + - One approval-voting worker that performs the tasks previously managed by the standalone + approval-voting subsystem. + +crates: + - name: polkadot-overseer + bump: major + - name: polkadot-node-primitives + bump: major + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-service + bump: major + - name: polkadot-approval-distribution + bump: major + - name: polkadot-node-core-approval-voting + bump: major + - name: polkadot-node-core-approval-voting-parallel + bump: major + - name: polkadot-network-bridge + bump: major + - name: polkadot-node-core-dispute-coordinator + bump: major + - name: cumulus-relay-chain-inprocess-interface + bump: major + - name: polkadot-cli + bump: major + - name: polkadot + bump: major + - name: polkadot-sdk + bump: minor diff --git a/prdoc/pr_4851.prdoc b/prdoc/pr_4851.prdoc index 923ca4bfff5d..2110a68d401c 100644 --- a/prdoc/pr_4851.prdoc +++ b/prdoc/pr_4851.prdoc @@ -5,8 +5,8 @@ title: Add support for deprecation metadata in `RuntimeMetadataIr` entries. doc: - audience: - - Runtime dev - - Runtime user + - Runtime Dev + - Runtime User description: | Changes introduced are listed below. Adds `DeprecationStatusIR` enum to sp_metadata_ir. diff --git a/prdoc/pr_5676.prdoc b/prdoc/pr_5676.prdoc new file mode 100644 index 000000000000..dfe23e120b4b --- /dev/null +++ b/prdoc/pr_5676.prdoc @@ -0,0 +1,174 @@ +title: '[ci] Update CI image with rust 1.81.0 and 2024-09-11' +doc: +- audience: [Runtime Dev, Node Dev, Node Operator] + description: |- + cc https://github.com/paritytech/ci_cd/issues/1035 + + close https://github.com/paritytech/ci_cd/issues/1023 +crates: +- name: pallet-xcm-bridge-hub + bump: patch +- name: snowbridge-router-primitives + bump: patch +- name: snowbridge-runtime-common + bump: patch +- name: cumulus-pallet-parachain-system + bump: patch +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: asset-test-utils + bump: patch +- name: bridge-hub-test-utils + bump: patch +- name: cumulus-primitives-utility + bump: patch +- name: polkadot-node-core-approval-voting + bump: patch +- name: polkadot-node-core-pvf-common + bump: patch +- name: polkadot-approval-distribution + bump: patch +- name: polkadot-availability-recovery + bump: patch +- name: polkadot-node-subsystem-types + bump: patch +- name: polkadot-runtime-parachains + bump: patch +- name: westend-runtime + bump: patch +- name: polkadot-statement-table + bump: patch +- name: pallet-xcm-benchmarks + bump: patch +- name: staging-xcm-builder + bump: patch +- name: xcm-runtime-apis + bump: patch +- name: sc-cli + bump: patch +- name: sc-consensus-grandpa + bump: patch +- name: sc-network + bump: patch +- name: sc-network-sync + bump: patch +- name: sc-rpc-spec-v2 + bump: patch +- name: pallet-bags-list + bump: patch +- name: pallet-balances + bump: patch +- name: pallet-bounties + bump: patch +- name: pallet-child-bounties + bump: patch +- name: pallet-nis + bump: patch +- name: pallet-referenda + bump: patch +- name: pallet-revive-proc-macro + bump: patch +- name: pallet-society + bump: patch +- name: pallet-staking + bump: patch +- name: frame-support-procedural + bump: patch +- name: frame-support + bump: patch +- name: pallet-transaction-payment + bump: patch +- name: pallet-utility + bump: patch +- name: pallet-vesting + bump: patch +- name: substrate-wasm-builder + bump: patch +- name: snowbridge-outbound-queue-merkle-tree + bump: patch +- name: shell-runtime + bump: patch +- name: polkadot-parachain-lib + bump: patch +- name: polkadot-cli + bump: patch +- name: polkadot-node-core-pvf + bump: patch +- name: polkadot-service + bump: patch +- name: polkadot-primitives + bump: patch +- name: staging-xcm-executor + bump: patch +- name: sc-consensus-beefy + bump: patch +- name: sc-consensus-slots + bump: patch +- name: frame-benchmarking-pallet-pov + bump: patch +- name: pallet-contracts + bump: patch +- name: frame-election-provider-support + bump: patch +- name: pallet-revive-mock-network + bump: patch +- name: frame-benchmarking-cli + bump: patch +- name: sc-utils + bump: patch +- name: pallet-beefy-mmr + bump: patch +- name: sp-state-machine + bump: patch +- name: fork-tree + bump: patch +- name: sc-transaction-pool + bump: patch +- name: pallet-delegated-staking + bump: patch +- name: sc-executor-wasmtime + bump: patch +- name: cumulus-pallet-xcmp-queue + bump: patch +- name: xcm-procedural + bump: patch +- name: sp-application-crypto + bump: patch +- name: sp-core + bump: patch +- name: sp-keyring + bump: patch +- name: polkadot-availability-distribution + bump: patch +- name: sp-runtime + bump: patch +- name: sc-authority-discovery + bump: patch +- name: frame-system + bump: patch +- name: sc-network-gossip + bump: patch +- name: pallet-authorship + bump: patch +- name: pallet-election-provider-multi-phase + bump: patch +- name: sp-runtime-interface + bump: patch +- name: pallet-bridge-grandpa + bump: patch +- name: pallet-elections-phragmen + bump: patch +- name: frame-executive + bump: patch +- name: bp-header-chain + bump: patch +- name: polkadot-overseer + bump: patch +- name: polkadot + bump: patch +- name: bridge-hub-westend-runtime + bump: major +- name: bp-messages + bump: patch diff --git a/prdoc/pr_5684.prdoc b/prdoc/pr_5684.prdoc index a17bacd2fb94..9800c85de2ae 100644 --- a/prdoc/pr_5684.prdoc +++ b/prdoc/pr_5684.prdoc @@ -4,7 +4,7 @@ title: "[pallet-revive]" doc: - - audience: Runtime Devs + - audience: Runtime Dev description: | Update xcm runtime api, and fix pallet-revive xcm tests diff --git a/prdoc/pr_5707.prdoc b/prdoc/pr_5707.prdoc new file mode 100644 index 000000000000..11136b3c3626 --- /dev/null +++ b/prdoc/pr_5707.prdoc @@ -0,0 +1,19 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove ValidateFromChainState + +doc: + - audience: Node Dev + description: | + Removed the `CandidateValidationMessage::ValidateFromChainState`, which was previously used by backing, but is no longer relevant since initial async backing implementation + +crates: + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-node-core-candidate-validation + bump: major + - name: polkadot + bump: patch + - name: polkadot-overseer + bump: patch diff --git a/prdoc/pr_5716.prdoc b/prdoc/pr_5716.prdoc new file mode 100644 index 000000000000..a98666233729 --- /dev/null +++ b/prdoc/pr_5716.prdoc @@ -0,0 +1,37 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Replace `lazy_static` with `LazyLock` + +doc: + - audience: Node Dev + description: | + Replace all lazy_static usages with LazyLock from the Rust standard library. This will bring us less dependencies. + +crates: + - name: sp-core + bump: patch + - name: sp-panic-handler + bump: patch + - name: sp-trie + bump: patch + - name: sc-utils + bump: major + - name: cumulus-pallet-parachain-system + bump: patch + - name: sp-consensus-beefy + bump: patch + - name: polkadot-node-primitives + bump: patch + - name: polkadot-node-jaeger + bump: patch + - name: frame-benchmarking-cli + bump: major + - name: sc-offchain + bump: patch + - name: polkadot-dispute-distribution + bump: patch + - name: polkadot-gossip-support + bump: patch + - name: xcm-emulator + bump: patch diff --git a/prdoc/pr_5756.prdoc b/prdoc/pr_5756.prdoc new file mode 100644 index 000000000000..525f955d3ac1 --- /dev/null +++ b/prdoc/pr_5756.prdoc @@ -0,0 +1,16 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Improve APIs for Tries in Runtime + +doc: + - audience: Runtime Dev + description: | + This PR introduces a trait `ProvingTrie` which has all the function you need to use tries in the runtime. + This trait includes the ability to create, query, and prove data in a trie. Another trait `ProofToHashes` + allows developers to express the computational complexity of proof verification using the proof data. +crates: + - name: sp-runtime + bump: major + - name: frame-support + bump: major diff --git a/prdoc/pr_5779.prdoc b/prdoc/pr_5779.prdoc new file mode 100644 index 000000000000..659a3a19f695 --- /dev/null +++ b/prdoc/pr_5779.prdoc @@ -0,0 +1,38 @@ +title: "[pallet-revive] last call return data API" + +doc: + - audience: Runtime Dev + description: | + This PR introduces 2 new syscall: `return_data_size` and `return_data_copy`, + resembling the semantics of the EVM `RETURNDATASIZE` and `RETURNDATACOPY` opcodes. + + The ownership of `ExecReturnValue` (the return data) has moved to the `Frame`. + This allows implementing the new contract API surface functionality in ext with no additional copies. + Returned data is passed via contract memory, memory is (will be) metered, + hence the amount of returned data can not be statically known, + so we should avoid storing copies of the returned data if we can. + By moving the ownership of the exectuables return value into the `Frame` struct we achieve this. + + A zero-copy implementation of those APIs would be technically possible without that internal change by making + the callsite in the runtime responsible for moving the returned data into the frame after any call. + However, resetting the stored output needs to be handled in ext, since plain transfers will _not_ affect the + stored return data (and we don't want to handle this special call case inside the `runtime` API). + This has drawbacks: + - It can not be tested easily in the mock. + - It introduces an inconsistency where resetting the stored output is handled in ext, + but the runtime API is responsible to store it back correctly after any calls made. + Instead, with ownership of the data in `Frame`, both can be handled in a single place. + Handling both in `fn run()` is more natural and leaves less room for runtime API bugs. + + The returned output is reset each time _before_ running any executable in a nested stack. + This change should not incur any overhead to the overall memory usage as _only_ the returned data from the last + executed frame will be kept around at any time. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: minor + - name: pallet-revive-uapi + bump: minor + \ No newline at end of file diff --git a/prdoc/pr_5811.prdoc b/prdoc/pr_5811.prdoc new file mode 100644 index 000000000000..103fef4bb8b0 --- /dev/null +++ b/prdoc/pr_5811.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Improve `import_notification_stream` documentation" + +doc: + - audience: Node Dev + description: | + "Updates the doc comment on the `import_notification_stream` to make its behaviour clearer. Now it specifically states that this notification stream is fired on every import notification after the initial sync, and only when there are re-orgs in the initial sync." + +crates: + - name: sc-client-api + bump: patch diff --git a/prdoc/pr_5824.prdoc b/prdoc/pr_5824.prdoc new file mode 100644 index 000000000000..136cd6bfee84 --- /dev/null +++ b/prdoc/pr_5824.prdoc @@ -0,0 +1,17 @@ +title: "Bump parachains runtime API to v11" + +doc: + - audience: [ Node Dev, Runtime Dev ] + description: | + This PR promotes all staging methods in v10 to stable and releases v11 stable runtime + APIs. + +crates: + - name: polkadot-runtime-parachains + bump: major + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: polkadot-test-runtime + bump: patch diff --git a/prdoc/pr_5830.prdoc b/prdoc/pr_5830.prdoc new file mode 100644 index 000000000000..10b586e4a4af --- /dev/null +++ b/prdoc/pr_5830.prdoc @@ -0,0 +1,13 @@ +title: "Remove jaeger from approval-voting and approval-distribution" + +doc: + - audience: Node Dev + description: | + Jaeger was remove from approval-voting and approval-distribution because + it did not prove to improve the debugging and it wasted precious cpu cycles. + +crates: + - name: polkadot-approval-distribution + bump: none + - name: polkadot-node-core-approval-voting + bump: none diff --git a/prdoc/pr_5838.prdoc b/prdoc/pr_5838.prdoc new file mode 100644 index 000000000000..f6ce091a12de --- /dev/null +++ b/prdoc/pr_5838.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: enable wasm builder diagnostics propagation + +doc: + - audience: Runtime Dev + description: | + `substrate-wasm-builder` is used as a build dependency by crates that implement FRAME runtimes. + Errors that occur in these crates can not be detected by IDEs that use rust-analyzer as a language + server because rust-analyzer needs the errors to be reported as diagnostic message in json format to + be able to publish them to language server clients. This PR adds `WASM_BUILD_CARGO_ARGS` environment + variable, which can hold a space separated list of args that will be parsed and passed to the `cargo` + command that it is used for building against wasm target. It can be used for the stated initial case, + but it is also flexible enough to allow passing other arguments or formatting the messages using another + available type. +crates: + - name: substrate-wasm-builder + bump: patch + diff --git a/prdoc/pr_5839.prdoc b/prdoc/pr_5839.prdoc new file mode 100644 index 000000000000..1dc95fe5c333 --- /dev/null +++ b/prdoc/pr_5839.prdoc @@ -0,0 +1,21 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove internal workaround for compiler bug + +doc: + - audience: + - Runtime Dev + - Node Dev + description: | + Remove a workaround we had in the `impl_runtime_apis` macro for a compiler bug that has been long fixed. + No impact on downstream users is expected, except relaxed trait bounds in a few places where the compiler + is now able to deduce more type info itself. + +crates: + - name: sp-api-proc-macro + bump: patch + - name: frame-support-procedural + bump: patch + - name: polkadot-parachain-lib + bump: patch diff --git a/prdoc/pr_5857.prdoc b/prdoc/pr_5857.prdoc new file mode 100644 index 000000000000..00ee0a8cc704 --- /dev/null +++ b/prdoc/pr_5857.prdoc @@ -0,0 +1,19 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Beefy equivocation: check all the MMR roots" + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + This PR adjusts the logic for `report_fork_voting` exposed by `pallet-beefy`. + Normally, the BEEFY protocol only accepts a single MMR Root entry in a commitment's payload. But, in order to + be extra careful, now, when validating equivocation reports, we check all the MMR roots, if there are more. + +crates: + - name: sp-consensus-beefy + bump: patch + - name: pallet-beefy-mmr + bump: patch diff --git a/prdoc/pr_5880.prdoc b/prdoc/pr_5880.prdoc new file mode 100644 index 000000000000..b246bff11f8d --- /dev/null +++ b/prdoc/pr_5880.prdoc @@ -0,0 +1,11 @@ +title: Fix prospective parachains test to use shuffled candidate list + +doc: + - audience: Node Dev + description: | + Fix prospective parachains test to use shuffled candidate list. + Resolves https://github.com/paritytech/polkadot-sdk/issues/5617. + +crates: + - name: polkadot-node-core-prospective-parachains + bump: none diff --git a/prdoc/pr_5887.prdoc b/prdoc/pr_5887.prdoc new file mode 100644 index 000000000000..3ee6ac05a11a --- /dev/null +++ b/prdoc/pr_5887.prdoc @@ -0,0 +1,17 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Set reasonable hard limit for PoV size config value" + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + Sets the hard limit of the `max_pov_size` host configuration parameter to correspond to the + actual network-related limit rather than to a random constant. + +crates: + - name: polkadot-runtime-parachains + bump: patch + diff --git a/scripts/update-ui-tests.sh b/scripts/update-ui-tests.sh index a1f380c4712d..c25b22fa7f75 100755 --- a/scripts/update-ui-tests.sh +++ b/scripts/update-ui-tests.sh @@ -32,10 +32,12 @@ export RUN_UI_TESTS=1 export SKIP_WASM_BUILD=1 # Let trybuild overwrite the .stderr files export TRYBUILD=overwrite +# Warnings are part of our UI and the CI also sets this. +export RUSTFLAGS="-C debug-assertions -D warnings" # ./substrate -$RUSTUP_RUN cargo test --manifest-path substrate/primitives/runtime-interface/Cargo.toml ui -$RUSTUP_RUN cargo test -p sp-api-test ui -$RUSTUP_RUN cargo test -p frame-election-provider-solution-type ui -$RUSTUP_RUN cargo test -p frame-support-test --features=no-metadata-docs,try-runtime,experimental ui -$RUSTUP_RUN cargo test -p xcm-procedural ui \ No newline at end of file +$RUSTUP_RUN cargo test -q --locked --manifest-path substrate/primitives/runtime-interface/Cargo.toml ui +$RUSTUP_RUN cargo test -q --locked -p sp-api-test ui +$RUSTUP_RUN cargo test -q --locked -p frame-election-provider-solution-type ui +$RUSTUP_RUN cargo test -q --locked -p frame-support-test --features=no-metadata-docs,try-runtime,experimental ui +$RUSTUP_RUN cargo test -q --locked -p xcm-procedural ui diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 88ea908abc23..8c6556da682c 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -40,7 +40,6 @@ hash-db = { workspace = true, default-features = true } tempfile = { workspace = true } fs_extra = { workspace = true } rand = { features = ["small_rng"], workspace = true, default-features = true } -lazy_static = { workspace = true } parity-db = { workspace = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } diff --git a/substrate/bin/node/bench/src/trie.rs b/substrate/bin/node/bench/src/trie.rs index 09ab405c03b2..402a186767ee 100644 --- a/substrate/bin/node/bench/src/trie.rs +++ b/substrate/bin/node/bench/src/trie.rs @@ -20,11 +20,14 @@ use hash_db::Prefix; use kvdb::KeyValueDB; -use lazy_static::lazy_static; use rand::Rng; use sp_state_machine::Backend as _; use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _}; -use std::{borrow::Cow, collections::HashMap, sync::Arc}; +use std::{ + borrow::Cow, + collections::HashMap, + sync::{Arc, LazyLock}, +}; use node_primitives::Hash; @@ -57,10 +60,8 @@ pub enum DatabaseSize { Huge, } -lazy_static! { - static ref KUSAMA_STATE_DISTRIBUTION: SizePool = - SizePool::from_histogram(crate::state_sizes::KUSAMA_STATE_DISTRIBUTION); -} +static KUSAMA_STATE_DISTRIBUTION: LazyLock = + LazyLock::new(|| SizePool::from_histogram(crate::state_sizes::KUSAMA_STATE_DISTRIBUTION)); impl DatabaseSize { /// Should be multiple of SAMPLE_SIZE! diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 9f82338b4fb0..b49af4c1055c 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -188,135 +188,3 @@ fn transaction_fee_is_correct() { assert_eq!(Balances::total_balance(&alice()), balance_alice); }); } - -#[test] -#[should_panic] -#[cfg(feature = "stress-test")] -fn block_weight_capacity_report() { - // Just report how many transfer calls you could fit into a block. The number should at least - // be a few hundred (250 at the time of writing but can change over time). Runs until panic. - use node_primitives::Nonce; - - // execution ext. - let mut t = new_test_ext(compact_code_unwrap()); - // setup ext. - let mut tt = new_test_ext(compact_code_unwrap()); - - let factor = 50; - let mut time = 10; - let mut nonce: Nonce = 0; - let mut block_number = 1; - let mut previous_hash: node_primitives::Hash = GENESIS_HASH.into(); - - loop { - let num_transfers = block_number * factor; - let mut xts = (0..num_transfers) - .map(|i| CheckedExtrinsic { - signed: Some((charlie(), signed_extra(nonce + i as Nonce, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { - dest: bob().into(), - value: 0, - }), - }) - .collect::>(); - - xts.insert( - 0, - CheckedExtrinsic { - signed: None, - function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), - }, - ); - - // NOTE: this is super slow. Can probably be improved. - let block = construct_block( - &mut tt, - block_number, - previous_hash, - xts, - (time * 1000 / SLOT_DURATION).into(), - ); - - let len = block.0.len(); - print!( - "++ Executing block with {} transfers. Block size = {} bytes / {} kb / {} mb", - num_transfers, - len, - len / 1024, - len / 1024 / 1024, - ); - - let r = executor_call(&mut t, "Core_execute_block", &block.0).0; - - println!(" || Result = {:?}", r); - assert!(r.is_ok()); - - previous_hash = block.1; - nonce += num_transfers; - time += 10; - block_number += 1; - } -} - -#[test] -#[should_panic] -#[cfg(feature = "stress-test")] -fn block_length_capacity_report() { - // Just report how big a block can get. Executes until panic. Should be ignored unless if - // manually inspected. The number should at least be a few megabytes (5 at the time of - // writing but can change over time). - use node_primitives::Nonce; - - // execution ext. - let mut t = new_test_ext(compact_code_unwrap()); - // setup ext. - let mut tt = new_test_ext(compact_code_unwrap()); - - let factor = 256 * 1024; - let mut time = 10; - let mut nonce: Nonce = 0; - let mut block_number = 1; - let mut previous_hash: node_primitives::Hash = GENESIS_HASH.into(); - - loop { - // NOTE: this is super slow. Can probably be improved. - let block = construct_block( - &mut tt, - block_number, - previous_hash, - vec![ - CheckedExtrinsic { - signed: None, - function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { - now: time * 1000, - }), - }, - CheckedExtrinsic { - signed: Some((charlie(), signed_extra(nonce, 0))), - function: RuntimeCall::System(frame_system::Call::remark { - remark: vec![0u8; (block_number * factor) as usize], - }), - }, - ], - (time * 1000 / SLOT_DURATION).into(), - ); - - let len = block.0.len(); - print!( - "++ Executing block with big remark. Block size = {} bytes / {} kb / {} mb", - len, - len / 1024, - len / 1024 / 1024, - ); - - let r = executor_call(&mut t, "Core_execute_block", &block.0).0; - - println!(" || Result = {:?}", r); - assert!(r.is_ok()); - - previous_hash = block.1; - nonce += 1; - time += 10; - block_number += 1; - } -} diff --git a/substrate/client/api/src/client.rs b/substrate/client/api/src/client.rs index 45cfafb25846..764930984ed7 100644 --- a/substrate/client/api/src/client.rs +++ b/substrate/client/api/src/client.rs @@ -65,9 +65,16 @@ pub trait BlockOf { pub trait BlockchainEvents { /// Get block import event stream. /// - /// Not guaranteed to be fired for every imported block, only fired when the node - /// has synced to the tip or there is a re-org. Use `every_import_notification_stream()` - /// if you want a notification of every imported block regardless. + /// Not guaranteed to be fired for every imported block. Use + /// `every_import_notification_stream()` if you want a notification of every imported block + /// regardless. + /// + /// The events for this notification stream are emitted: + /// - During initial sync process: if there is a re-org while importing blocks. See + /// [here](https://github.com/paritytech/substrate/pull/7118#issuecomment-694091901) for the + /// rationale behind this. + /// - After initial sync process: on every imported block, regardless of whether it is + /// the new best block or not, causes a re-org or not. fn import_notification_stream(&self) -> ImportNotifications; /// Get a stream of every imported block. diff --git a/substrate/client/authority-discovery/src/worker/tests.rs b/substrate/client/authority-discovery/src/worker/tests.rs index b49615382b8a..d71a85db8b81 100644 --- a/substrate/client/authority-discovery/src/worker/tests.rs +++ b/substrate/client/authority-discovery/src/worker/tests.rs @@ -117,10 +117,10 @@ sp_api::mock_impl_runtime_apis! { #[derive(Debug)] pub enum TestNetworkEvent { - GetCalled(KademliaKey), - PutCalled(KademliaKey, Vec), - PutToCalled(Record, HashSet, bool), - StoreRecordCalled(KademliaKey, Vec, Option, Option), + GetCalled, + PutCalled, + PutToCalled, + StoreRecordCalled, } pub struct TestNetwork { @@ -190,17 +190,11 @@ impl NetworkSigner for TestNetwork { impl NetworkDHTProvider for TestNetwork { fn put_value(&self, key: KademliaKey, value: Vec) { self.put_value_call.lock().unwrap().push((key.clone(), value.clone())); - self.event_sender - .clone() - .unbounded_send(TestNetworkEvent::PutCalled(key, value)) - .unwrap(); + self.event_sender.clone().unbounded_send(TestNetworkEvent::PutCalled).unwrap(); } fn get_value(&self, key: &KademliaKey) { self.get_value_call.lock().unwrap().push(key.clone()); - self.event_sender - .clone() - .unbounded_send(TestNetworkEvent::GetCalled(key.clone())) - .unwrap(); + self.event_sender.clone().unbounded_send(TestNetworkEvent::GetCalled).unwrap(); } fn put_record_to( @@ -214,10 +208,7 @@ impl NetworkDHTProvider for TestNetwork { peers.clone(), update_local_storage, )); - self.event_sender - .clone() - .unbounded_send(TestNetworkEvent::PutToCalled(record, peers, update_local_storage)) - .unwrap(); + self.event_sender.clone().unbounded_send(TestNetworkEvent::PutToCalled).unwrap(); } fn store_record( @@ -235,7 +226,7 @@ impl NetworkDHTProvider for TestNetwork { )); self.event_sender .clone() - .unbounded_send(TestNetworkEvent::StoreRecordCalled(key, value, publisher, expires)) + .unbounded_send(TestNetworkEvent::StoreRecordCalled) .unwrap(); } } @@ -536,7 +527,7 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { pool.run_until(async { // Assert worker to trigger a lookup for the one and only authority. - assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled))); // Send an event that should generate an error dht_event_tx @@ -1137,7 +1128,7 @@ fn lookup_throttling() { async { // Assert worker to trigger MAX_IN_FLIGHT_LOOKUPS lookups. for _ in 0..MAX_IN_FLIGHT_LOOKUPS { - assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled))); } assert_eq!( metrics.requests_pending.get(), @@ -1168,7 +1159,7 @@ fn lookup_throttling() { } // Assert worker to trigger another lookup. - assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled))); assert_eq!( metrics.requests_pending.get(), (remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 1) as u64 @@ -1181,7 +1172,7 @@ fn lookup_throttling() { dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); // Assert worker to trigger another lookup. - assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled))); assert_eq!( metrics.requests_pending.get(), (remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 2) as u64 diff --git a/substrate/client/cli/src/commands/import_blocks_cmd.rs b/substrate/client/cli/src/commands/import_blocks_cmd.rs index 815c6ab18aa6..6bd607901e38 100644 --- a/substrate/client/cli/src/commands/import_blocks_cmd.rs +++ b/substrate/client/cli/src/commands/import_blocks_cmd.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::Block as BlockT; use std::{ fmt::Debug, fs, - io::{self, Read, Seek}, + io::{self, Read}, path::PathBuf, sync::Arc, }; @@ -58,11 +58,6 @@ pub struct ImportBlocksCmd { pub import_params: ImportParams, } -/// Internal trait used to cast to a dynamic type that implements Read and Seek. -trait ReadPlusSeek: Read + Seek {} - -impl ReadPlusSeek for T {} - impl ImportBlocksCmd { /// Run the import-blocks command pub async fn run(&self, client: Arc, import_queue: IQ) -> error::Result<()> diff --git a/substrate/client/cli/src/commands/vanity.rs b/substrate/client/cli/src/commands/vanity.rs index 330a59493efc..9acacb4b15b2 100644 --- a/substrate/client/cli/src/commands/vanity.rs +++ b/substrate/client/cli/src/commands/vanity.rs @@ -166,8 +166,6 @@ mod tests { crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec}, sr25519, Pair, }; - #[cfg(feature = "bench")] - use test::Bencher; #[test] fn vanity() { @@ -225,16 +223,4 @@ mod tests { 0 ); } - - #[cfg(feature = "bench")] - #[bench] - fn bench_paranoiac(b: &mut Bencher) { - b.iter(|| generate_key("polk")); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_not_paranoiac(b: &mut Bencher) { - b.iter(|| generate_key("polk")); - } } diff --git a/substrate/client/cli/src/params/node_key_params.rs b/substrate/client/cli/src/params/node_key_params.rs index cdd637888114..70671bff8c05 100644 --- a/substrate/client/cli/src/params/node_key_params.rs +++ b/substrate/client/cli/src/params/node_key_params.rs @@ -116,8 +116,8 @@ impl NodeKeyParams { .clone() .unwrap_or_else(|| net_config_dir.join(NODE_KEY_ED25519_FILE)); if !self.unsafe_force_node_key_generation && - role.is_authority() && !is_dev && - !key_path.exists() + role.is_authority() && + !is_dev && !key_path.exists() { return Err(Error::NetworkKeyNotFound(key_path)) } diff --git a/substrate/client/consensus/beefy/src/fisherman.rs b/substrate/client/consensus/beefy/src/fisherman.rs index faa4d34eff5a..2b2683b35f0a 100644 --- a/substrate/client/consensus/beefy/src/fisherman.rs +++ b/substrate/client/consensus/beefy/src/fisherman.rs @@ -32,9 +32,8 @@ use sp_runtime::{ }; use std::{marker::PhantomData, sync::Arc}; -/// Helper struct containing the id and the key ownership proof for a validator. -pub struct ProvedValidator<'a, AuthorityId: AuthorityIdBound> { - pub id: &'a AuthorityId, +/// Helper struct containing the key ownership proof for a validator. +pub struct ProvedValidator { pub key_owner_proof: OpaqueKeyOwnershipProof, } @@ -66,7 +65,7 @@ where at: BlockId, offender_ids: impl Iterator, validator_set_id: ValidatorSetId, - ) -> Result>, Error> { + ) -> Result, Error> { let hash = match at { BlockId::Hash(hash) => hash, BlockId::Number(number) => self @@ -91,7 +90,7 @@ where offender_id.clone(), ) { Ok(Some(key_owner_proof)) => { - proved_offenders.push(ProvedValidator { id: offender_id, key_owner_proof }); + proved_offenders.push(ProvedValidator { key_owner_proof }); }, Ok(None) => { debug!( diff --git a/substrate/client/consensus/grandpa/src/aux_schema.rs b/substrate/client/consensus/grandpa/src/aux_schema.rs index 8ec882591be9..c42310dcd72c 100644 --- a/substrate/client/consensus/grandpa/src/aux_schema.rs +++ b/substrate/client/consensus/grandpa/src/aux_schema.rs @@ -743,7 +743,9 @@ mod test { substrate_test_runtime_client::runtime::Block, _, _, - >(&client, H256::random(), 0, || unreachable!()) + >( + &client, H256::random(), 0, || unreachable!() + ) .unwrap(); assert_eq!( diff --git a/substrate/client/consensus/grandpa/src/voting_rule.rs b/substrate/client/consensus/grandpa/src/voting_rule.rs index c1d3cd2fbd6a..6072f1895fd0 100644 --- a/substrate/client/consensus/grandpa/src/voting_rule.rs +++ b/substrate/client/consensus/grandpa/src/voting_rule.rs @@ -82,7 +82,7 @@ where /// /// In the best case our vote is exactly N blocks /// behind the best block, but if there is a scenario where either -/// >34% of validators run without this rule or the fork-choice rule +/// \>34% of validators run without this rule or the fork-choice rule /// can prioritize shorter chains over longer ones, the vote may be /// closer to the best block than N. #[derive(Clone)] diff --git a/substrate/client/consensus/slots/build.rs b/substrate/client/consensus/slots/build.rs index a68cb706e8fb..c63f0b8b6674 100644 --- a/substrate/client/consensus/slots/build.rs +++ b/substrate/client/consensus/slots/build.rs @@ -20,6 +20,6 @@ use std::env; fn main() { if let Ok(profile) = env::var("PROFILE") { - println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + println!("cargo:rustc-cfg=build_profile=\"{}\"", profile); } } diff --git a/substrate/client/consensus/slots/src/lib.rs b/substrate/client/consensus/slots/src/lib.rs index 06e0756fc968..4f7e85541777 100644 --- a/substrate/client/consensus/slots/src/lib.rs +++ b/substrate/client/consensus/slots/src/lib.rs @@ -227,7 +227,7 @@ pub trait SimpleSlotWorker { "⌛️ Discarding proposal for slot {}; block production took too long", slot, ); // If the node was compiled with debug, tell the user to use release optimizations. - #[cfg(build_type = "debug")] + #[cfg(build_profile = "debug")] info!( target: log_target, "👉 Recompile your node in `--release` mode to mitigate this problem.", diff --git a/substrate/client/executor/wasmtime/build.rs b/substrate/client/executor/wasmtime/build.rs index a68cb706e8fb..c63f0b8b6674 100644 --- a/substrate/client/executor/wasmtime/build.rs +++ b/substrate/client/executor/wasmtime/build.rs @@ -20,6 +20,6 @@ use std::env; fn main() { if let Ok(profile) = env::var("PROFILE") { - println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + println!("cargo:rustc-cfg=build_profile=\"{}\"", profile); } } diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index f86a42757694..abf2b9509c2b 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -455,7 +455,7 @@ fn test_max_memory_pages( // This test takes quite a while to execute in a debug build (over 6 minutes on a TR 3970x) // so it's ignored by default unless it was compiled with `--release`. -#[cfg_attr(build_type = "debug", ignore)] +#[cfg_attr(build_profile = "debug", ignore)] #[test] fn test_instances_without_reuse_are_not_leaked() { let runtime = crate::create_runtime::( diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index 414da9b2a589..a4bd922a76d5 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -377,9 +377,6 @@ mod tests { #[derive(Clone, Default)] struct TestNetwork {} - #[derive(Clone, Default)] - struct TestNetworkInner {} - #[async_trait::async_trait] impl NetworkPeers for TestNetwork { fn set_authorized_peers(&self, _peers: HashSet) { diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 9a6324dafd37..5ecbec52d507 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -76,8 +76,6 @@ pub enum BehaviourOut { /// /// This event is generated for statistics purposes. InboundRequest { - /// Peer which sent us a request. - peer: PeerId, /// Protocol name of the request. protocol: ProtocolName, /// If `Ok`, contains the time elapsed between when we received the request and when we @@ -89,8 +87,6 @@ pub enum BehaviourOut { /// /// This event is generated for statistics purposes. RequestFinished { - /// Peer that we send a request to. - peer: PeerId, /// Name of the protocol in question. protocol: ProtocolName, /// Duration the request took. @@ -350,10 +346,10 @@ impl From for BehaviourOut { impl From for BehaviourOut { fn from(event: request_responses::Event) -> Self { match event { - request_responses::Event::InboundRequest { peer, protocol, result } => - BehaviourOut::InboundRequest { peer, protocol, result }, - request_responses::Event::RequestFinished { peer, protocol, duration, result } => - BehaviourOut::RequestFinished { peer, protocol, duration, result }, + request_responses::Event::InboundRequest { protocol, result, .. } => + BehaviourOut::InboundRequest { protocol, result }, + request_responses::Event::RequestFinished { protocol, duration, result, .. } => + BehaviourOut::RequestFinished { protocol, duration, result }, request_responses::Event::ReputationChanges { peer, changes } => BehaviourOut::ReputationChanges { peer, changes }, } diff --git a/substrate/client/network/src/litep2p/discovery.rs b/substrate/client/network/src/litep2p/discovery.rs index bf2005df34d7..5fe944cadc0b 100644 --- a/substrate/client/network/src/litep2p/discovery.rs +++ b/substrate/client/network/src/litep2p/discovery.rs @@ -95,15 +95,6 @@ pub enum DiscoveryEvent { /// Peer ID. peer: PeerId, - /// Identify protocol version. - protocol_version: Option, - - /// Identify user agent version. - user_agent: Option, - - /// Observed address. - observed_address: Multiaddr, - /// Listen addresses. listen_addresses: Vec, @@ -561,11 +552,10 @@ impl Stream for Discovery { Poll::Ready(None) => return Poll::Ready(None), Poll::Ready(Some(IdentifyEvent::PeerIdentified { peer, - protocol_version, - user_agent, listen_addresses, supported_protocols, observed_address, + .. })) => { if this.is_new_external_address(&observed_address, peer) { this.pending_events.push_back(DiscoveryEvent::ExternalAddressDiscovered { @@ -575,10 +565,7 @@ impl Stream for Discovery { return Poll::Ready(Some(DiscoveryEvent::Identified { peer, - protocol_version, - user_agent, listen_addresses, - observed_address, supported_protocols, })); }, diff --git a/substrate/client/network/src/protocol/notifications/behaviour.rs b/substrate/client/network/src/protocol/notifications/behaviour.rs index cb4f089995e3..a562546145c8 100644 --- a/substrate/client/network/src/protocol/notifications/behaviour.rs +++ b/substrate/client/network/src/protocol/notifications/behaviour.rs @@ -33,7 +33,7 @@ use bytes::BytesMut; use fnv::FnvHashMap; use futures::{future::BoxFuture, prelude::*, stream::FuturesUnordered}; use libp2p::{ - core::{ConnectedPoint, Endpoint, Multiaddr}, + core::{Endpoint, Multiaddr}, swarm::{ behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}, ConnectionDenied, ConnectionId, DialError, NetworkBehaviour, NotifyHandler, PollParameters, @@ -362,8 +362,6 @@ pub enum NotificationsOut { received_handshake: Vec, /// Object that permits sending notifications to the peer. notifications_sink: NotificationsSink, - /// Is the connection inbound. - inbound: bool, }, /// The [`NotificationsSink`] object used to send notifications with the given peer must be @@ -1223,33 +1221,20 @@ impl NetworkBehaviour for Notifications { &mut self, _connection_id: ConnectionId, peer: PeerId, - local_addr: &Multiaddr, - remote_addr: &Multiaddr, + _local_addr: &Multiaddr, + _remote_addr: &Multiaddr, ) -> Result, ConnectionDenied> { - Ok(NotifsHandler::new( - peer, - ConnectedPoint::Listener { - local_addr: local_addr.clone(), - send_back_addr: remote_addr.clone(), - }, - self.notif_protocols.clone(), - Some(self.metrics.clone()), - )) + Ok(NotifsHandler::new(peer, self.notif_protocols.clone(), Some(self.metrics.clone()))) } fn handle_established_outbound_connection( &mut self, _connection_id: ConnectionId, peer: PeerId, - addr: &Multiaddr, - role_override: Endpoint, + _addr: &Multiaddr, + _role_override: Endpoint, ) -> Result, ConnectionDenied> { - Ok(NotifsHandler::new( - peer, - ConnectedPoint::Dialer { address: addr.clone(), role_override }, - self.notif_protocols.clone(), - Some(self.metrics.clone()), - )) + Ok(NotifsHandler::new(peer, self.notif_protocols.clone(), Some(self.metrics.clone()))) } fn on_swarm_event(&mut self, event: FromSwarm) { @@ -2061,7 +2046,6 @@ impl NetworkBehaviour for Notifications { let event = NotificationsOut::CustomProtocolOpen { peer_id, set_id, - inbound, direction: if inbound { Direction::Inbound } else { @@ -2383,6 +2367,7 @@ mod tests { protocol::notifications::handler::tests::*, protocol_controller::{IncomingIndex, ProtoSetConfig, ProtocolController}, }; + use libp2p::core::ConnectedPoint; use sc_utils::mpsc::tracing_unbounded; use std::{collections::HashSet, iter}; @@ -2413,7 +2398,8 @@ mod tests { } fn development_notifs( - ) -> (Notifications, ProtocolController, Box) { + ) -> (Notifications, ProtocolController, Box) + { let (protocol_handle_pair, notif_service) = crate::protocol::notifications::service::notification_service("/proto/1".into()); let (to_notifications, from_controller) = @@ -2668,7 +2654,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -2868,7 +2854,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3021,7 +3007,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3065,7 +3051,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3135,7 +3121,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3188,7 +3174,7 @@ mod tests { assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); // open new substream - let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + let event = conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]); notif.on_connection_handler_event(peer, conn, event); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); @@ -3261,7 +3247,7 @@ mod tests { notif.on_connection_handler_event( peer, *conn, - conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]), ); } @@ -3283,7 +3269,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3354,7 +3340,7 @@ mod tests { notif.on_connection_handler_event( peer, conn, - conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]), + conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]), ); if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { @@ -3409,7 +3395,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3483,7 +3469,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3546,7 +3532,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected.clone(), vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3560,7 +3546,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3614,7 +3600,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3672,7 +3658,7 @@ mod tests { peer_id: peer, connection_id: conn2, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3733,7 +3719,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3786,7 +3772,7 @@ mod tests { notif.on_connection_handler_event( peer, conn1, - conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]), ); if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { @@ -3802,7 +3788,7 @@ mod tests { peer_id: peer, connection_id: conn1, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3843,7 +3829,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -3966,7 +3952,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4015,10 +4001,6 @@ mod tests { let peer = PeerId::random(); let conn = ConnectionId::new_unchecked(0); let set_id = SetId::from(0); - let connected = ConnectedPoint::Listener { - local_addr: Multiaddr::empty(), - send_back_addr: Multiaddr::empty(), - }; let mut conn_yielder = ConnectionYielder::new(); // move the peer to `Enabled` state @@ -4052,7 +4034,7 @@ mod tests { notif.protocol_report_accept(IncomingIndex(0)); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); - let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + let event = conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]); notif.on_connection_handler_event(peer, conn, event); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); @@ -4167,7 +4149,7 @@ mod tests { notif.peerset_report_connect(peer, set_id); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); - let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + let event = conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]); notif.on_connection_handler_event(peer, conn, event); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); @@ -4280,7 +4262,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4521,7 +4503,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4623,7 +4605,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4681,7 +4663,7 @@ mod tests { notif.peerset_report_connect(peer, set_id); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); - let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + let event = conn_yielder.open_substream(peer, 0, vec![1, 2, 3, 4]); notif.on_connection_handler_event(peer, conn, event); assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); @@ -4705,7 +4687,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(0), endpoint: &endpoint.clone(), - handler: NotifsHandler::new(peer, endpoint, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4822,7 +4804,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4857,7 +4839,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4908,7 +4890,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -4955,7 +4937,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -5005,7 +4987,7 @@ mod tests { peer_id: peer, connection_id: ConnectionId::new_unchecked(1337), endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -5048,7 +5030,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected.clone(), vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -5059,7 +5041,7 @@ mod tests { peer_id: peer, connection_id: conn, endpoint: &connected.clone(), - handler: NotifsHandler::new(peer, connected, vec![], None), + handler: NotifsHandler::new(peer, vec![], None), remaining_established: 0usize, }, )); @@ -5071,16 +5053,12 @@ mod tests { fn open_result_ok_non_existent_peer() { let (mut notif, _controller, _notif_service) = development_notifs(); let conn = ConnectionId::new_unchecked(0); - let connected = ConnectedPoint::Listener { - local_addr: Multiaddr::empty(), - send_back_addr: Multiaddr::empty(), - }; let mut conn_yielder = ConnectionYielder::new(); notif.on_connection_handler_event( PeerId::random(), conn, - conn_yielder.open_substream(PeerId::random(), 0, connected, vec![1, 2, 3, 4]), + conn_yielder.open_substream(PeerId::random(), 0, vec![1, 2, 3, 4]), ); } } diff --git a/substrate/client/network/src/protocol/notifications/handler.rs b/substrate/client/network/src/protocol/notifications/handler.rs index 967ef614c556..bff60ba1125f 100644 --- a/substrate/client/network/src/protocol/notifications/handler.rs +++ b/substrate/client/network/src/protocol/notifications/handler.rs @@ -73,7 +73,6 @@ use futures::{ prelude::*, }; use libp2p::{ - core::ConnectedPoint, swarm::{ handler::ConnectionEvent, ConnectionHandler, ConnectionHandlerEvent, KeepAlive, Stream, SubstreamProtocol, @@ -117,9 +116,6 @@ pub struct NotifsHandler { /// When the connection with the remote has been successfully established. when_connection_open: Instant, - /// Whether we are the connection dialer or listener. - endpoint: ConnectedPoint, - /// Remote we are connected to. peer_id: PeerId, @@ -136,7 +132,6 @@ impl NotifsHandler { /// Creates new [`NotifsHandler`]. pub fn new( peer_id: PeerId, - endpoint: ConnectedPoint, protocols: Vec, metrics: Option, ) -> Self { @@ -154,7 +149,6 @@ impl NotifsHandler { }) .collect(), peer_id, - endpoint, when_connection_open: Instant::now(), events_queue: VecDeque::with_capacity(16), metrics: metrics.map_or(None, |metrics| Some(Arc::new(metrics))), @@ -281,8 +275,6 @@ pub enum NotifsHandlerOut { protocol_index: usize, /// Name of the protocol that was actually negotiated, if the default one wasn't available. negotiated_fallback: Option, - /// The endpoint of the connection that is open for custom protocols. - endpoint: ConnectedPoint, /// Handshake that was sent to us. /// This is normally a "Status" message, but this out of the concern of this code. received_handshake: Vec, @@ -590,7 +582,6 @@ impl ConnectionHandler for NotifsHandler { NotifsHandlerOut::OpenResultOk { protocol_index, negotiated_fallback: new_open.negotiated_fallback, - endpoint: self.endpoint.clone(), received_handshake: new_open.handshake, notifications_sink, inbound, @@ -889,7 +880,6 @@ pub mod tests { use libp2p::{ core::muxing::SubstreamBox, swarm::handler::{self, StreamUpgradeError}, - Multiaddr, Stream, }; use multistream_select::{dialer_select_proto, listener_select_proto, Negotiated, Version}; use std::{ @@ -925,7 +915,6 @@ pub mod tests { &mut self, peer: PeerId, protocol_index: usize, - endpoint: ConnectedPoint, received_handshake: Vec, ) -> NotifsHandlerOut { let (async_tx, async_rx) = @@ -954,7 +943,6 @@ pub mod tests { NotifsHandlerOut::OpenResultOk { protocol_index, negotiated_fallback: None, - endpoint, received_handshake, notifications_sink, inbound: false, @@ -1110,10 +1098,6 @@ pub mod tests { NotifsHandler { protocols: vec![proto], when_connection_open: Instant::now(), - endpoint: ConnectedPoint::Listener { - local_addr: Multiaddr::empty(), - send_back_addr: Multiaddr::empty(), - }, peer_id: PeerId::random(), events_queue: VecDeque::new(), metrics: None, @@ -1131,7 +1115,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1158,7 +1141,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1191,7 +1173,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1225,7 +1206,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1265,7 +1245,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1316,7 +1295,6 @@ pub mod tests { codec.set_max_len(usize::MAX); let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1355,7 +1333,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1415,7 +1392,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1452,7 +1428,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1498,7 +1473,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1547,7 +1521,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1583,7 +1556,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::NotSent, @@ -1658,7 +1630,6 @@ pub mod tests { let notif_in = NotificationsInOpen { handshake: b"hello, world".to_vec(), - negotiated_fallback: None, substream: NotificationsInSubstream::new( Framed::new(io, codec), NotificationsInSubstreamHandshake::PendingSend(vec![1, 2, 3, 4]), diff --git a/substrate/client/network/src/protocol/notifications/service/mod.rs b/substrate/client/network/src/protocol/notifications/service/mod.rs index 4f6d32ae3b35..a7eb31fc5795 100644 --- a/substrate/client/network/src/protocol/notifications/service/mod.rs +++ b/substrate/client/network/src/protocol/notifications/service/mod.rs @@ -89,9 +89,8 @@ impl MessageSink for NotificationSink { .await .map_err(|_| error::Error::ConnectionClosed)?; - permit.send(notification).map_err(|_| error::Error::ChannelClosed).map(|res| { + permit.send(notification).map_err(|_| error::Error::ChannelClosed).inspect(|_| { metrics::register_notification_sent(sink.0.metrics(), &sink.1, notification_len); - res }) } } @@ -263,13 +262,12 @@ impl NotificationService for NotificationHandle { .map_err(|_| error::Error::ConnectionClosed)? .send(notification) .map_err(|_| error::Error::ChannelClosed) - .map(|res| { + .inspect(|_| { metrics::register_notification_sent( sink.metrics(), &self.protocol, notification_len, ); - res }) } diff --git a/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs b/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs index a8a9e453a7bb..e01bcbe0bad7 100644 --- a/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/substrate/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -151,7 +151,7 @@ where type Future = Pin> + Send>>; type Error = NotificationsHandshakeError; - fn upgrade_inbound(self, mut socket: TSubstream, negotiated_name: Self::Info) -> Self::Future { + fn upgrade_inbound(self, mut socket: TSubstream, _negotiated_name: Self::Info) -> Self::Future { Box::pin(async move { let handshake_len = unsigned_varint::aio::read_usize(&mut socket).await?; if handshake_len > MAX_HANDSHAKE_SIZE { @@ -174,15 +174,7 @@ where handshake: NotificationsInSubstreamHandshake::NotSent, }; - Ok(NotificationsInOpen { - handshake, - negotiated_fallback: if negotiated_name == self.protocol_names[0] { - None - } else { - Some(negotiated_name) - }, - substream, - }) + Ok(NotificationsInOpen { handshake, substream }) }) } } @@ -191,9 +183,6 @@ where pub struct NotificationsInOpen { /// Handshake sent by the remote. pub handshake: Vec, - /// If the negotiated name is not the "main" protocol name but a fallback, contains the - /// name of the negotiated fallback. - pub negotiated_fallback: Option, /// Implementation of `Stream` that allows receives messages from the substream. pub substream: NotificationsInSubstream, } diff --git a/substrate/client/network/src/service/metrics.rs b/substrate/client/network/src/service/metrics.rs index 202dc7b2ed69..e48c53953ff8 100644 --- a/substrate/client/network/src/service/metrics.rs +++ b/substrate/client/network/src/service/metrics.rs @@ -72,7 +72,6 @@ pub struct Metrics { pub distinct_peers_connections_opened_total: Counter, pub incoming_connections_errors_total: CounterVec, pub incoming_connections_total: Counter, - pub issued_light_requests: Counter, pub kademlia_query_duration: HistogramVec, pub kademlia_random_queries_total: Counter, pub kademlia_records_count: Gauge, @@ -126,10 +125,6 @@ impl Metrics { "substrate_sub_libp2p_incoming_connections_total", "Total number of incoming connections on the listening sockets" )?, registry)?, - issued_light_requests: prometheus::register(Counter::new( - "substrate_issued_light_requests", - "Number of light client requests that our node has issued.", - )?, registry)?, kademlia_query_duration: prometheus::register(HistogramVec::new( HistogramOpts { common_opts: Opts::new( diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 96c1750b3116..dceea9954c6e 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -812,7 +812,8 @@ where } if !self.default_peers_set_no_slot_connected_peers.remove(&peer_id) && - info.inbound && info.info.roles.is_full() + info.inbound && + info.info.roles.is_full() { match self.num_in_peers.checked_sub(1) { Some(value) => { diff --git a/substrate/client/network/sync/src/lib.rs b/substrate/client/network/sync/src/lib.rs index ca7280edba5f..c458c7a5da49 100644 --- a/substrate/client/network/sync/src/lib.rs +++ b/substrate/client/network/sync/src/lib.rs @@ -26,7 +26,6 @@ mod block_announce_validator; mod futures_stream; mod justification_requests; mod pending_responses; -mod request_metrics; mod schema; pub mod types; diff --git a/substrate/client/network/sync/src/request_metrics.rs b/substrate/client/network/sync/src/request_metrics.rs deleted file mode 100644 index 455f57ec3933..000000000000 --- a/substrate/client/network/sync/src/request_metrics.rs +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#[derive(Debug)] -pub struct Metrics { - pub pending_requests: u32, - pub active_requests: u32, - pub importing_requests: u32, - pub failed_requests: u32, -} diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 0f73e3194baa..06e243342fb2 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -628,9 +628,8 @@ struct VerifierAdapter { impl Verifier for VerifierAdapter { async fn verify(&self, block: BlockImportParams) -> Result, String> { let hash = block.header.hash(); - self.verifier.lock().await.verify(block).await.map_err(|e| { + self.verifier.lock().await.verify(block).await.inspect_err(|e| { self.failed_verifications.lock().insert(hash, e.clone()); - e }) } } diff --git a/substrate/client/network/test/src/sync.rs b/substrate/client/network/test/src/sync.rs index 4244c49bf7fb..91307d869281 100644 --- a/substrate/client/network/test/src/sync.rs +++ b/substrate/client/network/test/src/sync.rs @@ -749,24 +749,6 @@ async fn sync_blocks_when_block_announce_validator_says_it_is_new_best() { } } -/// Waits for some time until the validation is successful. -struct DeferredBlockAnnounceValidator; - -impl BlockAnnounceValidator for DeferredBlockAnnounceValidator { - fn validate( - &mut self, - _: &Header, - _: &[u8], - ) -> Pin>> + Send>> - { - async { - futures_timer::Delay::new(std::time::Duration::from_millis(500)).await; - Ok(Validation::Success { is_new_best: false }) - } - .boxed() - } -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn wait_until_deferred_block_announce_validation_is_ready() { sp_tracing::try_init_simple(); diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index 4b5b04cca627..bbbe7018d106 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -22,7 +22,10 @@ codec = { features = ["derive"], workspace = true, default-features = true } fnv = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } -hyperv14 = { features = ["http2", "stream"], workspace = true, default-features = true } +hyperv14 = { features = [ + "http2", + "stream", +], workspace = true, default-features = true } hyper-rustls = { features = ["http2"], workspace = true } num_cpus = { workspace = true } once_cell = { workspace = true } @@ -46,7 +49,6 @@ log = { workspace = true, default-features = true } [dev-dependencies] async-trait = { workspace = true } -lazy_static = { workspace = true } tokio = { workspace = true, default-features = true } sc-block-builder = { workspace = true, default-features = true } sc-client-db = { default-features = true, workspace = true } diff --git a/substrate/client/offchain/src/api/http.rs b/substrate/client/offchain/src/api/http.rs index fda5728b0d03..73407b1359d7 100644 --- a/substrate/client/offchain/src/api/http.rs +++ b/substrate/client/offchain/src/api/http.rs @@ -763,14 +763,12 @@ mod tests { use crate::api::timestamp; use core::convert::Infallible; use futures::{future, StreamExt}; - use lazy_static::lazy_static; use sp_core::offchain::{Duration, Externalities, HttpError, HttpRequestId, HttpRequestStatus}; + use std::sync::LazyLock; - // Using lazy_static to avoid spawning lots of different SharedClients, + // Using LazyLock to avoid spawning lots of different SharedClients, // as spawning a SharedClient is CPU-intensive and opens lots of fds. - lazy_static! { - static ref SHARED_CLIENT: SharedClient = SharedClient::new(); - } + static SHARED_CLIENT: LazyLock = LazyLock::new(|| SharedClient::new()); // Returns an `HttpApi` whose worker is ran in the background, and a `SocketAddr` to an HTTP // server that runs in the background as well. diff --git a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs index 073ee34a79f3..fa10fde388f9 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/test_utils.rs @@ -343,7 +343,8 @@ where fn number( &self, hash: Block::Hash, - ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> { + ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> + { self.client.number(hash) } diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index 13e63962fe8f..55bbfcdd8594 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -1748,11 +1748,9 @@ fn respects_block_rules() { } #[test] -#[cfg(disable_flaky)] -#[allow(dead_code)] -// FIXME: https://github.com/paritytech/substrate/issues/11321 +// FIXME: https://github.com/paritytech/polkadot-sdk/issues/48 fn returns_status_for_pruned_blocks() { - use sc_consensus::BlockStatus; + use sp_consensus::BlockStatus; sp_tracing::try_init_simple(); let tmp = tempfile::tempdir().unwrap(); diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index 09571610a3a6..b8f5e40caf83 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -20,7 +20,6 @@ console = { workspace = true } is-terminal = { workspace = true } chrono = { workspace = true } codec = { workspace = true, default-features = true } -lazy_static = { workspace = true } libc = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } @@ -29,7 +28,10 @@ serde = { workspace = true, default-features = true } thiserror = { workspace = true } tracing = { workspace = true, default-features = true } tracing-log = { workspace = true } -tracing-subscriber = { workspace = true, features = ["env-filter", "parking_lot"] } +tracing-subscriber = { workspace = true, features = [ + "env-filter", + "parking_lot", +] } sc-client-api = { workspace = true, default-features = true } sc-tracing-proc-macro = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } diff --git a/substrate/client/transaction-pool/src/graph/tracked_map.rs b/substrate/client/transaction-pool/src/graph/tracked_map.rs index 47ad22603e46..44c2c738ab1b 100644 --- a/substrate/client/transaction-pool/src/graph/tracked_map.rs +++ b/substrate/client/transaction-pool/src/graph/tracked_map.rs @@ -119,10 +119,9 @@ where let new_bytes = val.size(); self.bytes.fetch_add(new_bytes as isize, AtomicOrdering::Relaxed); self.length.fetch_add(1, AtomicOrdering::Relaxed); - self.inner_guard.insert(key, val).map(|old_val| { + self.inner_guard.insert(key, val).inspect(|old_val| { self.bytes.fetch_sub(old_val.size() as isize, AtomicOrdering::Relaxed); self.length.fetch_sub(1, AtomicOrdering::Relaxed); - old_val }) } diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index 6c3a2228952e..485261058d59 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -16,7 +16,6 @@ workspace = true async-channel = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } -lazy_static = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } prometheus = { workspace = true } diff --git a/substrate/client/utils/src/metrics.rs b/substrate/client/utils/src/metrics.rs index 308e90cb2537..9b6e1e47039e 100644 --- a/substrate/client/utils/src/metrics.rs +++ b/substrate/client/utils/src/metrics.rs @@ -18,42 +18,49 @@ //! Metering primitives and globals -use lazy_static::lazy_static; use prometheus::{ core::{AtomicU64, GenericCounter, GenericGauge}, Error as PrometheusError, Registry, }; +use std::sync::LazyLock; use prometheus::{ core::{GenericCounterVec, GenericGaugeVec}, Opts, }; -lazy_static! { - pub static ref TOKIO_THREADS_TOTAL: GenericCounter = - GenericCounter::new("substrate_tokio_threads_total", "Total number of threads created") - .expect("Creating of statics doesn't fail. qed"); - pub static ref TOKIO_THREADS_ALIVE: GenericGauge = - GenericGauge::new("substrate_tokio_threads_alive", "Number of threads alive right now") - .expect("Creating of statics doesn't fail. qed"); -} +pub static TOKIO_THREADS_TOTAL: LazyLock> = LazyLock::new(|| { + GenericCounter::new("substrate_tokio_threads_total", "Total number of threads created") + .expect("Creating of statics doesn't fail. qed") +}); -lazy_static! { - pub static ref UNBOUNDED_CHANNELS_COUNTER: GenericCounterVec = GenericCounterVec::new( - Opts::new( - "substrate_unbounded_channel_len", - "Items sent/received/dropped on each mpsc::unbounded instance" - ), - &["entity", "action"], // name of channel, send|received|dropped - ).expect("Creating of statics doesn't fail. qed"); - pub static ref UNBOUNDED_CHANNELS_SIZE: GenericGaugeVec = GenericGaugeVec::new( +pub static TOKIO_THREADS_ALIVE: LazyLock> = LazyLock::new(|| { + GenericGauge::new("substrate_tokio_threads_alive", "Number of threads alive right now") + .expect("Creating of statics doesn't fail. qed") +}); + +pub static UNBOUNDED_CHANNELS_COUNTER: LazyLock> = + LazyLock::new(|| { + GenericCounterVec::new( + Opts::new( + "substrate_unbounded_channel_len", + "Items sent/received/dropped on each mpsc::unbounded instance", + ), + &["entity", "action"], // name of channel, send|received|dropped + ) + .expect("Creating of statics doesn't fail. qed") + }); + +pub static UNBOUNDED_CHANNELS_SIZE: LazyLock> = LazyLock::new(|| { + GenericGaugeVec::new( Opts::new( "substrate_unbounded_channel_size", "Size (number of messages to be processed) of each mpsc::unbounded instance", ), &["entity"], // name of channel - ).expect("Creating of statics doesn't fail. qed"); -} + ) + .expect("Creating of statics doesn't fail. qed") +}); pub static SENT_LABEL: &'static str = "send"; pub static RECEIVED_LABEL: &'static str = "received"; diff --git a/substrate/client/utils/src/mpsc.rs b/substrate/client/utils/src/mpsc.rs index 91db7e1e7b01..051cb5b387ca 100644 --- a/substrate/client/utils/src/mpsc.rs +++ b/substrate/client/utils/src/mpsc.rs @@ -103,7 +103,7 @@ impl TracingUnboundedSender { /// Proxy function to `async_channel::Sender::try_send`. pub fn unbounded_send(&self, msg: T) -> Result<(), TrySendError> { - self.inner.try_send(msg).map(|s| { + self.inner.try_send(msg).inspect(|_| { UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, SENT_LABEL]).inc(); UNBOUNDED_CHANNELS_SIZE .with_label_values(&[self.name]) @@ -124,8 +124,6 @@ impl TracingUnboundedSender { Backtrace::force_capture(), ); } - - s }) } @@ -144,12 +142,11 @@ impl TracingUnboundedReceiver { /// Proxy function to [`async_channel::Receiver`] /// that discounts the messages taken out. pub fn try_recv(&mut self) -> Result { - self.inner.try_recv().map(|s| { + self.inner.try_recv().inspect(|_| { UNBOUNDED_CHANNELS_COUNTER.with_label_values(&[self.name, RECEIVED_LABEL]).inc(); UNBOUNDED_CHANNELS_SIZE .with_label_values(&[self.name]) .set(self.inner.len().saturated_into()); - s }) } diff --git a/substrate/frame/authorship/src/lib.rs b/substrate/frame/authorship/src/lib.rs index a0cca806e786..1de2262a2014 100644 --- a/substrate/frame/authorship/src/lib.rs +++ b/substrate/frame/authorship/src/lib.rs @@ -84,9 +84,8 @@ impl Pallet { let digest = >::digest(); let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime()); - T::FindAuthor::find_author(pre_runtime_digests).map(|a| { + T::FindAuthor::find_author(pre_runtime_digests).inspect(|a| { >::put(&a); - a }) } } diff --git a/substrate/frame/bags-list/src/lib.rs b/substrate/frame/bags-list/src/lib.rs index f6af1da5e7b7..ee36a3a3ebd8 100644 --- a/substrate/frame/bags-list/src/lib.rs +++ b/substrate/frame/bags-list/src/lib.rs @@ -491,7 +491,7 @@ impl, I: 'static> ScoreProvider for Pallet { Node::::get(id).map(|node| node.score()).unwrap_or_default() } - frame_election_provider_support::runtime_benchmarks_fuzz_or_std_enabled! { + frame_election_provider_support::runtime_benchmarks_or_std_enabled! { fn set_score_of(id: &T::AccountId, new_score: T::Score) { ListNodes::::mutate(id, |maybe_node| { if let Some(node) = maybe_node.as_mut() { diff --git a/substrate/frame/bags-list/src/list/tests.rs b/substrate/frame/bags-list/src/list/tests.rs index e5fff76d75c7..fc4c4fbd088b 100644 --- a/substrate/frame/bags-list/src/list/tests.rs +++ b/substrate/frame/bags-list/src/list/tests.rs @@ -778,7 +778,7 @@ mod bags { assert_eq!(bag_1000.iter().count(), 3); bag_1000.insert_node_unchecked(node(4, None, None, bag_1000.bag_upper)); // panics in debug assert_eq!(bag_1000.iter().count(), 3); // in release we expect it to silently ignore the - // request. + // request. }); } diff --git a/substrate/frame/bags-list/src/mock.rs b/substrate/frame/bags-list/src/mock.rs index ea677cb9e73e..3690a876f62d 100644 --- a/substrate/frame/bags-list/src/mock.rs +++ b/substrate/frame/bags-list/src/mock.rs @@ -41,7 +41,7 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { *NextVoteWeightMap::get().get(id).unwrap_or(&NextVoteWeight::get()) } - frame_election_provider_support::runtime_benchmarks_fuzz_or_std_enabled! { + frame_election_provider_support::runtime_benchmarks_or_std_enabled! { fn set_score_of(id: &AccountId, weight: Self::Score) { NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(*id, weight)); } diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 87d2029d488e..f6858347f24e 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -1031,7 +1031,7 @@ pub mod pallet { } if did_provide && !does_provide { // This could reap the account so must go last. - frame_system::Pallet::::dec_providers(who).map_err(|r| { + frame_system::Pallet::::dec_providers(who).inspect_err(|_| { // best-effort revert consumer change. if did_consume && !does_consume { let _ = frame_system::Pallet::::inc_consumers(who).defensive(); @@ -1039,7 +1039,6 @@ pub mod pallet { if !did_consume && does_consume { let _ = frame_system::Pallet::::dec_consumers(who); } - r })?; } diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 2243859458be..a4984b34f6db 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -1017,7 +1017,7 @@ fn slash_consumed_slash_full_works() { ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { Balances::make_free_balance_be(&1, 1_000); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests - // Slashed completed in full + // Slashed completed in full assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); @@ -1029,7 +1029,7 @@ fn slash_consumed_slash_over_works() { ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { Balances::make_free_balance_be(&1, 1_000); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests - // Slashed completed in full + // Slashed completed in full assert_eq!(Balances::slash(&1, 1_000), (NegativeImbalance::new(900), 100)); // Account is still alive assert!(System::account_exists(&1)); @@ -1041,7 +1041,7 @@ fn slash_consumed_slash_partial_works() { ExtBuilder::default().existential_deposit(100).build_and_execute_with(|| { Balances::make_free_balance_be(&1, 1_000); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests - // Slashed completed in full + // Slashed completed in full assert_eq!(Balances::slash(&1, 800), (NegativeImbalance::new(800), 0)); // Account is still alive assert!(System::account_exists(&1)); diff --git a/substrate/frame/beefy-mmr/src/benchmarking.rs b/substrate/frame/beefy-mmr/src/benchmarking.rs index 135f95eabb99..fea6a2078f0f 100644 --- a/substrate/frame/beefy-mmr/src/benchmarking.rs +++ b/substrate/frame/beefy-mmr/src/benchmarking.rs @@ -51,9 +51,7 @@ mod benchmarks { #[benchmark] fn extract_validation_context() { - if !cfg!(feature = "test") { - pallet_mmr::UseLocalStorage::::set(true); - } + pallet_mmr::UseLocalStorage::::set(true); init_block::(1); let header = System::::finalize(); @@ -71,9 +69,7 @@ mod benchmarks { #[benchmark] fn read_peak() { - if !cfg!(feature = "test") { - pallet_mmr::UseLocalStorage::::set(true); - } + pallet_mmr::UseLocalStorage::::set(true); init_block::(1); @@ -91,9 +87,7 @@ mod benchmarks { /// the verification. We need to account for the peaks separately. #[benchmark] fn n_items_proof_is_non_canonical(n: Linear<2, 512>) { - if !cfg!(feature = "test") { - pallet_mmr::UseLocalStorage::::set(true); - } + pallet_mmr::UseLocalStorage::::set(true); for block_num in 1..=n { init_block::(block_num); diff --git a/substrate/frame/beefy-mmr/src/lib.rs b/substrate/frame/beefy-mmr/src/lib.rs index 73119c3faa9b..ef99bc1e9cf1 100644 --- a/substrate/frame/beefy-mmr/src/lib.rs +++ b/substrate/frame/beefy-mmr/src/lib.rs @@ -258,17 +258,33 @@ where }, }; - let commitment_root = - match commitment.payload.get_decoded::>(&known_payloads::MMR_ROOT_ID) { - Some(commitment_root) => commitment_root, + let mut found_commitment_root = false; + let commitment_roots = commitment + .payload + .get_all_decoded::>(&known_payloads::MMR_ROOT_ID); + for maybe_commitment_root in commitment_roots { + match maybe_commitment_root { + Some(commitment_root) => { + found_commitment_root = true; + if canonical_prev_root != commitment_root { + // If the commitment contains an MMR root, that is not equal to + // `canonical_prev_root`, the commitment is invalid + return true; + } + }, None => { - // If the commitment doesn't contain any MMR root, while the proof is valid, - // the commitment is invalid - return true + // If the commitment contains an MMR root, that can't be decoded, it is invalid. + return true; }, - }; + } + } + if !found_commitment_root { + // If the commitment doesn't contain any MMR root, while the proof is valid, + // the commitment is invalid + return true; + } - canonical_prev_root != commitment_root + false } } diff --git a/substrate/frame/beefy-mmr/src/tests.rs b/substrate/frame/beefy-mmr/src/tests.rs index b126a01012b4..297fb28647ac 100644 --- a/substrate/frame/beefy-mmr/src/tests.rs +++ b/substrate/frame/beefy-mmr/src/tests.rs @@ -278,8 +278,28 @@ fn is_non_canonical_should_work_correctly() { &Commitment { payload: Payload::from_single_entry( known_payloads::MMR_ROOT_ID, - H256::repeat_byte(0).encode(), - ), + prev_roots[250 - 1].encode() + ) + .push_raw(known_payloads::MMR_ROOT_ID, H256::repeat_byte(0).encode(),), + block_number: 250, + validator_set_id: 0, + }, + valid_proof.clone(), + Mmr::mmr_root(), + ), + true + ); + + // If the `commitment.payload` contains an MMR root that can't be decoded, + // it's non-canonical. + assert_eq!( + BeefyMmr::is_non_canonical( + &Commitment { + payload: Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + prev_roots[250 - 1].encode() + ) + .push_raw(known_payloads::MMR_ROOT_ID, vec![],), block_number: 250, validator_set_id: 0, }, diff --git a/substrate/frame/benchmarking/pov/src/weights.rs b/substrate/frame/benchmarking/pov/src/weights.rs index c4fc03d1dd93..1f20d5f0b515 100644 --- a/substrate/frame/benchmarking/pov/src/weights.rs +++ b/substrate/frame/benchmarking/pov/src/weights.rs @@ -45,6 +45,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; /// Weight functions needed for `frame_benchmarking_pallet_pov`. +#[allow(dead_code)] pub trait WeightInfo { fn storage_single_value_read() -> Weight; fn storage_single_value_ignored_read() -> Weight; @@ -79,6 +80,7 @@ pub trait WeightInfo { } /// Weights for `frame_benchmarking_pallet_pov` using the Substrate node and recommended hardware. +#[allow(dead_code)] pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `Pov::Value` (r:1 w:0) diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs index 7b89a6e3e76f..e30d6fa2d143 100644 --- a/substrate/frame/bounties/src/lib.rs +++ b/substrate/frame/bounties/src/lib.rs @@ -459,12 +459,12 @@ pub mod pallet { Bounties::::try_mutate_exists(bounty_id, |maybe_bounty| -> DispatchResult { let bounty = maybe_bounty.as_mut().ok_or(Error::::InvalidIndex)?; - let slash_curator = |curator: &T::AccountId, - curator_deposit: &mut BalanceOf| { - let imbalance = T::Currency::slash_reserved(curator, *curator_deposit).0; - T::OnSlash::on_unbalanced(imbalance); - *curator_deposit = Zero::zero(); - }; + let slash_curator = + |curator: &T::AccountId, curator_deposit: &mut BalanceOf| { + let imbalance = T::Currency::slash_reserved(curator, *curator_deposit).0; + T::OnSlash::on_unbalanced(imbalance); + *curator_deposit = Zero::zero(); + }; match bounty.status { BountyStatus::Proposed | BountyStatus::Approved | BountyStatus::Funded => { diff --git a/substrate/frame/child-bounties/src/lib.rs b/substrate/frame/child-bounties/src/lib.rs index 911fd4c4c49f..660a30ca5d26 100644 --- a/substrate/frame/child-bounties/src/lib.rs +++ b/substrate/frame/child-bounties/src/lib.rs @@ -473,12 +473,13 @@ pub mod pallet { let child_bounty = maybe_child_bounty.as_mut().ok_or(BountiesError::::InvalidIndex)?; - let slash_curator = |curator: &T::AccountId, - curator_deposit: &mut BalanceOf| { - let imbalance = T::Currency::slash_reserved(curator, *curator_deposit).0; - T::OnSlash::on_unbalanced(imbalance); - *curator_deposit = Zero::zero(); - }; + let slash_curator = + |curator: &T::AccountId, curator_deposit: &mut BalanceOf| { + let imbalance = + T::Currency::slash_reserved(curator, *curator_deposit).0; + T::OnSlash::on_unbalanced(imbalance); + *curator_deposit = Zero::zero(); + }; match child_bounty.status { ChildBountyStatus::Added => { diff --git a/substrate/frame/contracts/src/benchmarking/code.rs b/substrate/frame/contracts/src/benchmarking/code.rs index 1473022b5537..b5918a5e182d 100644 --- a/substrate/frame/contracts/src/benchmarking/code.rs +++ b/substrate/frame/contracts/src/benchmarking/code.rs @@ -114,7 +114,6 @@ pub struct ImportedFunction { pub struct WasmModule { pub code: Vec, pub hash: ::Output, - pub memory: Option, } impl From for WasmModule { @@ -233,7 +232,7 @@ impl From for WasmModule { let code = contract.build().into_bytes().unwrap(); let hash = T::Hashing::hash(&code); - Self { code: code.into(), hash, memory: def.memory } + Self { code: code.into(), hash } } } diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 31e0bf50b73e..046affe32d96 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -454,9 +454,6 @@ pub trait Executable: Sized { /// The code hash of the executable. fn code_hash(&self) -> &CodeHash; - /// Size of the contract code in bytes. - fn code_len(&self) -> u32; - /// The code does not contain any instructions which could lead to indeterminism. fn is_deterministic(&self) -> bool; } @@ -1838,10 +1835,6 @@ mod tests { &self.code_info } - fn code_len(&self) -> u32 { - 0 - } - fn is_deterministic(&self) -> bool { true } diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index f4ee76459c4e..c9786fa1516b 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -488,10 +488,6 @@ impl Executable for WasmBlob { &self.code_info } - fn code_len(&self) -> u32 { - self.code.len() as u32 - } - fn is_deterministic(&self) -> bool { matches!(self.code_info.determinism, Determinism::Enforced) } diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 7b8d14b0a611..1d181eb29cab 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -71,8 +71,8 @@ //! - Migrate a `Nominator` account to an `agent` account. See [`Pallet::migrate_to_agent`]. //! Explained in more detail in the `Migration` section. //! - Migrate unclaimed delegated funds from `agent` to delegator. When a nominator migrates to an -//! agent, the funds are held in a proxy account. This function allows the delegator to claim their -//! share of the funds from the proxy account. See [`Pallet::migrate_delegation`]. +//! agent, the funds are held in a proxy account. This function allows the delegator to claim +//! their share of the funds from the proxy account. See [`Pallet::migrate_delegation`]. //! //! ## Lazy Slashing //! One of the reasons why direct nominators on staking pallet cannot scale well is because all diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 09248e77848b..072cfe176b61 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1208,9 +1208,8 @@ pub mod pallet { } let _ = Self::unsigned_pre_dispatch_checks(raw_solution) - .map_err(|err| { + .inspect_err(|err| { log!(debug, "unsigned transaction validation failed due to {:?}", err); - err }) .map_err(dispatch_error_to_invalid)?; diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 394f58a38442..cb3249e388a3 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -687,7 +687,7 @@ sp_core::generate_feature_enabled_macro!( ); sp_core::generate_feature_enabled_macro!( - runtime_benchmarks_fuzz_or_std_enabled, - any(feature = "runtime-benchmarks", feature = "fuzzing", feature = "std"), + runtime_benchmarks_or_std_enabled, + any(feature = "runtime-benchmarks", feature = "std"), $ ); diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index 6d91448fd185..a1c5f69e1b65 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -829,7 +829,7 @@ impl Pallet { T::Currency::unreserve(who, removed.deposit); } - let maybe_next_best = RunnersUp::::mutate(|r| r.pop()).map(|next_best| { + let maybe_next_best = RunnersUp::::mutate(|r| r.pop()).inspect(|next_best| { // defensive-only: Members and runners-up are disjoint. This will always be err and // give us an index to insert. if let Err(index) = members.binary_search_by(|m| m.who.cmp(&next_best.who)) { @@ -839,7 +839,6 @@ impl Pallet { // is already a member, so not much more to do. log::error!(target: LOG_TARGET, "A member seems to also be a runner-up."); } - next_best }); Ok(maybe_next_best) })?; diff --git a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs index 2016b03de45e..6243846d86b0 100644 --- a/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs +++ b/substrate/frame/examples/multi-block-migrations/src/migrations/v1/mod.rs @@ -21,6 +21,8 @@ //! [`v0::MyMap`](`crate::migrations::v1::v0::MyMap`) storage map, transforms them, //! and inserts them into the [`MyMap`](`crate::pallet::MyMap`) storage map. +extern crate alloc; + use super::PALLET_MIGRATIONS_ID; use crate::pallet::{Config, MyMap}; use frame_support::{ @@ -29,6 +31,12 @@ use frame_support::{ weights::WeightMeter, }; +#[cfg(feature = "try-runtime")] +use alloc::collections::btree_map::BTreeMap; + +#[cfg(feature = "try-runtime")] +use alloc::vec::Vec; + mod benchmarks; mod tests; pub mod weights; @@ -115,4 +123,39 @@ impl SteppedMigration for LazyMigrationV1 Result, frame_support::sp_runtime::TryRuntimeError> { + use codec::Encode; + + // Return the state of the storage before the migration. + Ok(v0::MyMap::::iter().collect::>().encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev: Vec) -> Result<(), frame_support::sp_runtime::TryRuntimeError> { + use codec::Decode; + + // Check the state of the storage after the migration. + let prev_map = BTreeMap::::decode(&mut &prev[..]) + .expect("Failed to decode the previous storage state"); + + // Check the len of prev and post are the same. + assert_eq!( + MyMap::::iter().count(), + prev_map.len(), + "Migration failed: the number of items in the storage after the migration is not the same as before" + ); + + for (key, value) in prev_map { + let new_value = + MyMap::::get(key).expect("Failed to get the value after the migration"); + assert_eq!( + value as u64, new_value, + "Migration failed: the value after the migration is not the same as before" + ); + } + + Ok(()) + } } diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index b665cbbb62ae..741adbe6d26a 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -266,11 +266,12 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { { assert_eq!(body, price_payload); - let signature_valid = - ::Public, - frame_system::pallet_prelude::BlockNumberFor, - > as SignedPayload>::verify::(&price_payload, signature); + let signature_valid = ::Public, + frame_system::pallet_prelude::BlockNumberFor, + > as SignedPayload>::verify::( + &price_payload, signature + ); assert!(signature_valid); } @@ -320,11 +321,12 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { { assert_eq!(body, price_payload); - let signature_valid = - ::Public, - frame_system::pallet_prelude::BlockNumberFor, - > as SignedPayload>::verify::(&price_payload, signature); + let signature_valid = ::Public, + frame_system::pallet_prelude::BlockNumberFor, + > as SignedPayload>::verify::( + &price_payload, signature + ); assert!(signature_valid); } diff --git a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs index 55cf7cef9a7a..922c03afdd1e 100644 --- a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs +++ b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs @@ -60,7 +60,7 @@ impl UncheckedOnRuntimeUpgrade for InnerMigrateV0ToV1 { /// /// - If the value doesn't exist, there is nothing to do. /// - If the value exists, it is read and then written back to storage inside a - /// [`crate::CurrentAndPreviousValue`]. + /// [`crate::CurrentAndPreviousValue`]. fn on_runtime_upgrade() -> frame_support::weights::Weight { // Read the old value from storage if let Some(old_value) = v0::Value::::take() { diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 1e7bac64e18f..fe702e1fc395 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -382,9 +382,8 @@ where , >>::try_state(*header.number(), select.clone()) - .map_err(|e| { + .inspect_err(|e| { log::error!(target: LOG_TARGET, "failure: {:?}", e); - e })?; if select.any() { let res = AllPalletsWithSystem::try_decode_entire_state(); diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 5fbed74a4400..a32e48e65280 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -12,6 +12,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["derive"], workspace = true } +cfg-if = { workspace = true } docify = { workspace = true } impl-trait-for-tuples = { workspace = true } log = { workspace = true, default-features = true } diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index 1823e5a2f952..d9490e7dcfe9 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -70,21 +70,26 @@ //! points to the currently active migration and stores its inner cursor. The inner cursor can then //! be used by the migration to store its inner state and advance. Each time when the migration //! returns `Some(cursor)`, it signals the pallet that it is not done yet. +//! //! The cursor is reset on each runtime upgrade. This ensures that it starts to execute at the //! first migration in the vector. The pallets cursor is only ever incremented or set to `Stuck` //! once it encounters an error (Goal 4). Once in the stuck state, the pallet will stay stuck until //! it is fixed through manual governance intervention. +//! //! As soon as the cursor of the pallet becomes `Some(_)`; [`MultiStepMigrator::ongoing`] returns //! `true` (Goal 2). This can be used by upstream code to possibly pause transactions. //! In `on_initialize` the pallet will load the current migration and check whether it was already //! executed in the past by checking for membership of its ID in the [`Historic`] set. Historic //! migrations are skipped without causing an error. Each successfully executed migration is added //! to this set (Goal 5). +//! //! This proceeds until no more migrations remain. At that point, the event `UpgradeCompleted` is //! emitted (Goal 1). +//! //! The execution of each migration happens by calling [`SteppedMigration::transactional_step`]. //! This function wraps the inner `step` function into a transactional layer to allow rollback in //! the error case (Goal 6). +//! //! Weight limits must be checked by the migration itself. The pallet provides a [`WeightMeter`] for //! that purpose. The pallet may return [`SteppedMigrationError::InsufficientWeight`] at any point. //! In that scenario, one of two things will happen: if that migration was exclusively executed @@ -156,11 +161,15 @@ use core::ops::ControlFlow; use frame_support::{ defensive, defensive_assert, migrations::*, + pallet_prelude::*, traits::Get, weights::{Weight, WeightMeter}, BoundedVec, }; -use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System}; +use frame_system::{ + pallet_prelude::{BlockNumberFor, *}, + Pallet as System, +}; use sp_runtime::Saturating; /// Points to the next migration to execute. @@ -262,6 +271,7 @@ pub type IdentifierOf = BoundedVec::IdentifierMaxLen>; pub type ActiveCursorOf = ActiveCursor, BlockNumberFor>; /// Trait for a tuple of No-OP migrations with one element. +#[impl_trait_for_tuples::impl_for_tuples(30)] pub trait MockedMigrations: SteppedMigrations { /// The migration should fail after `n` steps. fn set_fail_after(n: u32); @@ -269,11 +279,24 @@ pub trait MockedMigrations: SteppedMigrations { fn set_success_after(n: u32); } +#[cfg(feature = "try-runtime")] +/// Wrapper for pre-upgrade bytes, allowing us to impl MEL on it. +/// +/// For `try-runtime` testing only. +#[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, scale_info::TypeInfo, Default)] +struct PreUpgradeBytesWrapper(pub Vec); + +/// Data stored by the pre-upgrade hook of the MBMs. Only used for `try-runtime` testing. +/// +/// Define this outside of the pallet so it is not confused with actual storage. +#[cfg(feature = "try-runtime")] +#[frame_support::storage_alias] +type PreUpgradeBytes = + StorageMap, Twox64Concat, IdentifierOf, PreUpgradeBytesWrapper, ValueQuery>; + #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::pallet] pub struct Pallet(_); @@ -701,6 +724,16 @@ impl Pallet { } let max_steps = T::Migrations::nth_max_steps(cursor.index); + + // If this is the first time running this migration, exec the pre-upgrade hook. + #[cfg(feature = "try-runtime")] + if !PreUpgradeBytes::::contains_key(&bounded_id) { + let bytes = T::Migrations::nth_pre_upgrade(cursor.index) + .expect("Invalid cursor.index") + .expect("Pre-upgrade failed"); + PreUpgradeBytes::::insert(&bounded_id, PreUpgradeBytesWrapper(bytes)); + } + let next_cursor = T::Migrations::nth_transactional_step( cursor.index, cursor.inner_cursor.clone().map(|c| c.into_inner()), @@ -735,6 +768,16 @@ impl Pallet { }, Ok(None) => { // A migration is done when it returns cursor `None`. + + // Run post-upgrade checks. + #[cfg(feature = "try-runtime")] + T::Migrations::nth_post_upgrade( + cursor.index, + PreUpgradeBytes::::get(&bounded_id).0, + ) + .expect("Invalid cursor.index.") + .expect("Post-upgrade failed."); + Self::deposit_event(Event::MigrationCompleted { index: cursor.index, took }); Historic::::insert(&bounded_id, ()); cursor.goto_next_migration(System::::block_number()); @@ -759,14 +802,21 @@ impl Pallet { } /// Fail the current runtime upgrade, caused by `migration`. + /// + /// When the `try-runtime` feature is enabled, this function will panic. + // Allow unreachable code so it can compile without warnings when `try-runtime` is enabled. fn upgrade_failed(migration: Option) { use FailedMigrationHandling::*; Self::deposit_event(Event::UpgradeFailed); - match T::FailedMigrationHandler::failed(migration) { - KeepStuck => Cursor::::set(Some(MigrationCursor::Stuck)), - ForceUnstuck => Cursor::::kill(), - Ignore => {}, + if cfg!(feature = "try-runtime") { + panic!("Migration with index {:?} failed.", migration); + } else { + match T::FailedMigrationHandler::failed(migration) { + KeepStuck => Cursor::::set(Some(MigrationCursor::Stuck)), + ForceUnstuck => Cursor::::kill(), + Ignore => {}, + } } } diff --git a/substrate/frame/migrations/src/mock_helpers.rs b/substrate/frame/migrations/src/mock_helpers.rs index 9d3b4d1193f2..a03c70051d30 100644 --- a/substrate/frame/migrations/src/mock_helpers.rs +++ b/substrate/frame/migrations/src/mock_helpers.rs @@ -43,6 +43,12 @@ pub enum MockedMigrationKind { /// Cause an [`SteppedMigrationError::InsufficientWeight`] error after its number of steps /// elapsed. HighWeightAfter(Weight), + /// PreUpgrade should fail. + #[cfg(feature = "try-runtime")] + PreUpgradeFail, + /// PostUpgrade should fail. + #[cfg(feature = "try-runtime")] + PostUpgradeFail, } use MockedMigrationKind::*; // C style @@ -99,6 +105,8 @@ impl SteppedMigrations for MockedMigrations { Err(SteppedMigrationError::Failed) }, TimeoutAfter => unreachable!(), + #[cfg(feature = "try-runtime")] + PreUpgradeFail | PostUpgradeFail => Ok(None), }) } @@ -115,6 +123,31 @@ impl SteppedMigrations for MockedMigrations { MIGRATIONS::get().get(n as usize).map(|(_, s)| Some(*s)) } + #[cfg(feature = "try-runtime")] + fn nth_pre_upgrade(n: u32) -> Option, sp_runtime::TryRuntimeError>> { + let (kind, _) = MIGRATIONS::get()[n as usize]; + + if let PreUpgradeFail = kind { + return Some(Err("Some pre-upgrade error".into())) + } + + Some(Ok(vec![])) + } + + #[cfg(feature = "try-runtime")] + fn nth_post_upgrade( + n: u32, + _state: Vec, + ) -> Option> { + let (kind, _) = MIGRATIONS::get()[n as usize]; + + if let PostUpgradeFail = kind { + return Some(Err("Some post-upgrade error".into())) + } + + Some(Ok(())) + } + fn cursor_max_encoded_len() -> usize { 65_536 } diff --git a/substrate/frame/migrations/src/tests.rs b/substrate/frame/migrations/src/tests.rs index 73ca2a9a09cf..55f212bcf373 100644 --- a/substrate/frame/migrations/src/tests.rs +++ b/substrate/frame/migrations/src/tests.rs @@ -17,12 +17,13 @@ #![cfg(test)] +use frame_support::{pallet_prelude::Weight, traits::OnRuntimeUpgrade}; + use crate::{ mock::{Test as T, *}, mock_helpers::{MockedMigrationKind::*, *}, Cursor, Event, FailedMigrationHandling, MigrationCursor, }; -use frame_support::{pallet_prelude::Weight, traits::OnRuntimeUpgrade}; #[docify::export] #[test] @@ -86,6 +87,7 @@ fn simple_multiple_works() { } #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn failing_migration_sets_cursor_to_stuck() { test_closure(|| { FailedUpgradeResponse::set(FailedMigrationHandling::KeepStuck); @@ -116,6 +118,7 @@ fn failing_migration_sets_cursor_to_stuck() { } #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn failing_migration_force_unstuck_works() { test_closure(|| { FailedUpgradeResponse::set(FailedMigrationHandling::ForceUnstuck); @@ -148,6 +151,7 @@ fn failing_migration_force_unstuck_works() { /// A migration that reports not getting enough weight errors if it is the first one to run in that /// block. #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn high_weight_migration_singular_fails() { test_closure(|| { MockedMigrations::set(vec![(HighWeightAfter(Weight::zero()), 2)]); @@ -176,6 +180,7 @@ fn high_weight_migration_singular_fails() { /// A migration that reports of not getting enough weight is retried once, if it is not the first /// one to run in a block. #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn high_weight_migration_retries_once() { test_closure(|| { MockedMigrations::set(vec![(SucceedAfter, 0), (HighWeightAfter(Weight::zero()), 0)]); @@ -205,6 +210,7 @@ fn high_weight_migration_retries_once() { // Note: Same as `high_weight_migration_retries_once` but with different required weight for the // migration. #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn high_weight_migration_permanently_overweight_fails() { test_closure(|| { MockedMigrations::set(vec![(SucceedAfter, 0), (HighWeightAfter(Weight::MAX), 0)]); @@ -300,6 +306,7 @@ fn historic_skipping_works() { /// When another upgrade happens while a migration is still running, it should set the cursor to /// stuck. #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn upgrade_fails_when_migration_active() { test_closure(|| { MockedMigrations::set(vec![(SucceedAfter, 10)]); @@ -326,6 +333,7 @@ fn upgrade_fails_when_migration_active() { } #[test] +#[cfg_attr(feature = "try-runtime", should_panic)] fn migration_timeout_errors() { test_closure(|| { MockedMigrations::set(vec![(TimeoutAfter, 3)]); @@ -358,3 +366,91 @@ fn migration_timeout_errors() { assert_eq!(upgrades_started_completed_failed(), (0, 0, 1)); }); } + +#[cfg(feature = "try-runtime")] +#[test] +fn try_runtime_success_case() { + use Event::*; + test_closure(|| { + // Add three migrations, each taking one block longer than the previous. + MockedMigrations::set(vec![(SucceedAfter, 0), (SucceedAfter, 1), (SucceedAfter, 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + run_to_block(10); + + // Check that we got all events. + assert_events(vec![ + UpgradeStarted { migrations: 3 }, + MigrationCompleted { index: 0, took: 1 }, + MigrationAdvanced { index: 1, took: 0 }, + MigrationCompleted { index: 1, took: 1 }, + MigrationAdvanced { index: 2, took: 0 }, + MigrationAdvanced { index: 2, took: 1 }, + MigrationCompleted { index: 2, took: 2 }, + UpgradeCompleted, + ]); + }); +} + +#[test] +#[cfg(feature = "try-runtime")] +#[should_panic] +fn try_runtime_pre_upgrade_failure() { + test_closure(|| { + // Add three migrations, it should fail after the second one. + MockedMigrations::set(vec![(SucceedAfter, 0), (PreUpgradeFail, 1), (SucceedAfter, 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + + // should panic + run_to_block(10); + }); +} + +#[test] +#[cfg(feature = "try-runtime")] +#[should_panic] +fn try_runtime_post_upgrade_failure() { + test_closure(|| { + // Add three migrations, it should fail after the second one. + MockedMigrations::set(vec![(SucceedAfter, 0), (PostUpgradeFail, 1), (SucceedAfter, 2)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + + // should panic + run_to_block(10); + }); +} + +#[test] +#[cfg(feature = "try-runtime")] +#[should_panic] +fn try_runtime_migration_failure() { + test_closure(|| { + // Add three migrations, it should fail after the second one. + MockedMigrations::set(vec![(SucceedAfter, 0), (FailAfter, 5), (SucceedAfter, 10)]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + + // should panic + run_to_block(10); + }); +} + +#[test] +fn try_runtime_no_migrations() { + test_closure(|| { + MockedMigrations::set(vec![]); + + System::set_block_number(1); + Migrations::on_runtime_upgrade(); + + run_to_block(10); + + assert_eq!(System::events().len(), 0); + }); +} diff --git a/substrate/frame/nis/src/lib.rs b/substrate/frame/nis/src/lib.rs index 016daa4cb78b..87e2276e768d 100644 --- a/substrate/frame/nis/src/lib.rs +++ b/substrate/frame/nis/src/lib.rs @@ -756,15 +756,13 @@ pub mod pallet { .map(|_| ()) // We ignore this error as it just means the amount we're trying to deposit is // dust and the beneficiary account doesn't exist. - .or_else( - |e| { - if e == TokenError::CannotCreate.into() { - Ok(()) - } else { - Err(e) - } - }, - )?; + .or_else(|e| { + if e == TokenError::CannotCreate.into() { + Ok(()) + } else { + Err(e) + } + })?; summary.receipts_on_hold.saturating_reduce(on_hold); } T::Currency::release(&HoldReason::NftReceipt.into(), &who, amount, Exact)?; diff --git a/substrate/frame/referenda/src/mock.rs b/substrate/frame/referenda/src/mock.rs index bf0fa4e1a12e..c96a50af8658 100644 --- a/substrate/frame/referenda/src/mock.rs +++ b/substrate/frame/referenda/src/mock.rs @@ -24,7 +24,6 @@ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, - SortedMembers, }, weights::Weight, }; @@ -98,14 +97,6 @@ ord_parameter_types! { pub const Five: u64 = 5; pub const Six: u64 = 6; } -pub struct OneToFive; -impl SortedMembers for OneToFive { - fn sorted_members() -> Vec { - vec![1, 2, 3, 4, 5] - } - #[cfg(feature = "runtime-benchmarks")] - fn add(_m: &u64) {} -} pub struct TestTracksInfo; impl TracksInfo for TestTracksInfo { diff --git a/substrate/frame/referenda/src/types.rs b/substrate/frame/referenda/src/types.rs index 1039b288b2ae..e83f28b472cd 100644 --- a/substrate/frame/referenda/src/types.rs +++ b/substrate/frame/referenda/src/types.rs @@ -258,7 +258,8 @@ impl< Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - > ReferendumInfo + > + ReferendumInfo { /// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not /// in a valid state for the Decision Deposit to be refunded. diff --git a/substrate/frame/revive/fixtures/contracts/return_data_api.rs b/substrate/frame/revive/fixtures/contracts/return_data_api.rs new file mode 100644 index 000000000000..846396b0944d --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/return_data_api.rs @@ -0,0 +1,166 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This tests that the `return_data_size` and `return_data_copy` APIs work. +//! +//! It does so by calling and instantiating the "return_with_data" fixture, +//! which always echoes back the input[4..] regardless of the call outcome. +//! +//! We also check that the saved return data is properly reset after a trap +//! and unaffected by plain transfers. + +#![no_std] +#![no_main] + +use common::{input, u256_bytes}; +use uapi::{HostFn, HostFnImpl as api}; + +const INPUT_BUF_SIZE: usize = 128; +static INPUT_DATA: [u8; INPUT_BUF_SIZE] = [0xFF; INPUT_BUF_SIZE]; +/// The "return_with_data" fixture echoes back 4 bytes less than the input +const OUTPUT_BUF_SIZE: usize = INPUT_BUF_SIZE - 4; +static OUTPUT_DATA: [u8; OUTPUT_BUF_SIZE] = [0xEE; OUTPUT_BUF_SIZE]; + +fn assert_return_data_after_call(input: &[u8]) { + assert_return_data_size_of(OUTPUT_BUF_SIZE as u64); + assert_plain_transfer_does_not_reset(OUTPUT_BUF_SIZE as u64); + assert_return_data_copy(&input[4..]); + reset_return_data(); +} + +/// Assert that what we get from [api::return_data_copy] matches `whole_return_data`, +/// either fully or partially with an offset and limited size. +fn assert_return_data_copy(whole_return_data: &[u8]) { + // The full return data should match + let mut buf = OUTPUT_DATA; + let mut full = &mut buf[..whole_return_data.len()]; + api::return_data_copy(&mut full, 0); + assert_eq!(whole_return_data, full); + + // Partial return data should match + let mut buf = OUTPUT_DATA; + let offset = 5; // we just pick some offset + let size = 32; // we just pick some size + let mut partial = &mut buf[offset..offset + size]; + api::return_data_copy(&mut partial, offset as u32); + assert_eq!(*partial, whole_return_data[offset..offset + size]); +} + +/// This function panics in a recursive contract call context. +fn recursion_guard() -> [u8; 20] { + let mut caller_address = [0u8; 20]; + api::caller(&mut caller_address); + + let mut own_address = [0u8; 20]; + api::address(&mut own_address); + + assert_ne!(caller_address, own_address); + + own_address +} + +/// Call ourselves recursively, which panics the callee and thus resets the return data. +fn reset_return_data() { + api::call( + uapi::CallFlags::ALLOW_REENTRY, + &recursion_guard(), + 0u64, + 0u64, + None, + &[0u8; 32], + &[0u8; 32], + None, + ) + .unwrap_err(); + assert_return_data_size_of(0); +} + +/// Assert [api::return_data_size] to match the `expected` value. +fn assert_return_data_size_of(expected: u64) { + let mut return_data_size = [0xff; 32]; + api::return_data_size(&mut return_data_size); + assert_eq!(return_data_size, u256_bytes(expected)); +} + +/// Assert [api::return_data_size] to match the `expected` value after a plain transfer +/// (plain transfers don't issue a call and so should not reset the return data) +fn assert_plain_transfer_does_not_reset(expected: u64) { + api::transfer(&[0; 20], &u256_bytes(128)).unwrap(); + assert_return_data_size_of(expected); +} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + input!(code_hash: &[u8; 32],); + + // We didn't do anything yet; return data size should be 0 + assert_return_data_size_of(0); + + recursion_guard(); + + let mut address_buf = [0; 20]; + let construct_input = |exit_flag| { + let mut input = INPUT_DATA; + input[0] = exit_flag; + input[9] = 7; + input[17 / 2] = 127; + input[89 / 2] = 127; + input + }; + let mut instantiate = |exit_flag| { + api::instantiate( + code_hash, + 0u64, + 0u64, + None, + &[0; 32], + &construct_input(exit_flag), + Some(&mut address_buf), + None, + None, + ) + }; + let call = |exit_flag, address_buf| { + api::call( + uapi::CallFlags::empty(), + address_buf, + 0u64, + 0u64, + None, + &[0; 32], + &construct_input(exit_flag), + None, + ) + }; + + instantiate(0).unwrap(); + assert_return_data_after_call(&construct_input(0)[..]); + + instantiate(1).unwrap_err(); + assert_return_data_after_call(&construct_input(1)[..]); + + call(0, &address_buf).unwrap(); + assert_return_data_after_call(&construct_input(0)[..]); + + call(1, &address_buf).unwrap_err(); + assert_return_data_after_call(&construct_input(1)[..]); +} diff --git a/substrate/frame/revive/proc-macro/src/lib.rs b/substrate/frame/revive/proc-macro/src/lib.rs index 95f4110a2d76..012b4bfab9a9 100644 --- a/substrate/frame/revive/proc-macro/src/lib.rs +++ b/substrate/frame/revive/proc-macro/src/lib.rs @@ -349,18 +349,19 @@ where let Some(ident) = path.path.get_ident() else { panic!("Type needs to be ident"); }; - let size = - if ident == "i8" || - ident == "i16" || ident == "i32" || - ident == "u8" || ident == "u16" || - ident == "u32" - { - 1 - } else if ident == "i64" || ident == "u64" { - 2 - } else { - panic!("Pass by value only supports primitives"); - }; + let size = if ident == "i8" || + ident == "i16" || + ident == "i32" || + ident == "u8" || + ident == "u16" || + ident == "u32" + { + 1 + } else if ident == "i64" || ident == "u64" { + 2 + } else { + panic!("Pass by value only supports primitives"); + }; registers_used += size; if registers_used > ALLOWED_REGISTERS { return quote! { diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 233658696c8f..2e48bab29255 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -189,16 +189,12 @@ pub trait Ext: sealing::Sealed { input_data: Vec, allows_reentry: bool, read_only: bool, - ) -> Result; + ) -> Result<(), ExecError>; /// Execute code in the current frame. /// /// Returns the code size of the called contract. - fn delegate_call( - &mut self, - code: H256, - input_data: Vec, - ) -> Result; + fn delegate_call(&mut self, code: H256, input_data: Vec) -> Result<(), ExecError>; /// Instantiate a contract from the given code. /// @@ -213,7 +209,7 @@ pub trait Ext: sealing::Sealed { value: U256, input_data: Vec, salt: Option<&[u8; 32]>, - ) -> Result<(H160, ExecReturnValue), ExecError>; + ) -> Result; /// Transfer all funds to `beneficiary` and delete the contract. /// @@ -427,6 +423,12 @@ pub trait Ext: sealing::Sealed { /// Check if running in read-only context. fn is_read_only(&self) -> bool; + + /// Returns an immutable reference to the output of the last executed call frame. + fn last_frame_output(&self) -> &ExecReturnValue; + + /// Returns a mutable reference to the output of the last executed call frame. + fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue; } /// Describes the different functions that can be exported by an [`Executable`]. @@ -547,6 +549,8 @@ struct Frame { read_only: bool, /// The caller of the currently executing frame which was spawned by `delegate_call`. delegate_caller: Option>, + /// The output of the last executed call frame. + last_frame_output: ExecReturnValue, } /// Used in a delegate call frame arguments in order to override the executable and caller. @@ -731,7 +735,7 @@ where value, debug_message, )? { - stack.run(executable, input_data) + stack.run(executable, input_data).map(|_| stack.first_frame.last_frame_output) } else { Self::transfer_no_contract(&origin, &dest, value) } @@ -772,7 +776,9 @@ where )? .expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE); let address = T::AddressMapper::to_address(&stack.top_frame().account_id); - stack.run(executable, input_data).map(|ret| (address, ret)) + stack + .run(executable, input_data) + .map(|_| (address, stack.first_frame.last_frame_output)) } #[cfg(all(feature = "runtime-benchmarks", feature = "riscv"))] @@ -865,7 +871,7 @@ where { contract } else { - return Ok(None) + return Ok(None); } }; @@ -911,6 +917,7 @@ where nested_storage: storage_meter.nested(deposit_limit), allows_reentry: true, read_only, + last_frame_output: Default::default(), }; Ok(Some((frame, executable))) @@ -965,12 +972,24 @@ where /// Run the current (top) frame. /// /// This can be either a call or an instantiate. - fn run(&mut self, executable: E, input_data: Vec) -> ExecResult { + fn run(&mut self, executable: E, input_data: Vec) -> Result<(), ExecError> { let frame = self.top_frame(); let entry_point = frame.entry_point; let delegated_code_hash = if frame.delegate_caller.is_some() { Some(*executable.code_hash()) } else { None }; + // The output of the caller frame will be replaced by the output of this run. + // It is also not accessible from nested frames. + // Hence we drop it early to save the memory. + let frames_len = self.frames.len(); + if let Some(caller_frame) = match frames_len { + 0 => None, + 1 => Some(&mut self.first_frame.last_frame_output), + _ => self.frames.get_mut(frames_len - 2).map(|frame| &mut frame.last_frame_output), + } { + *caller_frame = Default::default(); + } + self.transient_storage.start_transaction(); let do_transaction = || { @@ -1109,7 +1128,9 @@ where } self.pop_frame(success); - output + output.map(|output| { + self.top_frame_mut().last_frame_output = output; + }) } /// Remove the current (top) frame from the stack. @@ -1285,7 +1306,7 @@ where input_data: Vec, allows_reentry: bool, read_only: bool, - ) -> ExecResult { + ) -> Result<(), ExecError> { // Before pushing the new frame: Protect the caller contract against reentrancy attacks. // It is important to do this before calling `allows_reentry` so that a direct recursion // is caught by it. @@ -1323,7 +1344,8 @@ where &Origin::from_account_id(self.account_id().clone()), &dest, value, - ) + )?; + Ok(()) } }; @@ -1336,11 +1358,7 @@ where result } - fn delegate_call( - &mut self, - code_hash: H256, - input_data: Vec, - ) -> Result { + fn delegate_call(&mut self, code_hash: H256, input_data: Vec) -> Result<(), ExecError> { let executable = E::from_storage(code_hash, self.gas_meter_mut())?; let top_frame = self.top_frame_mut(); let contract_info = top_frame.contract_info().clone(); @@ -1368,7 +1386,7 @@ where value: U256, input_data: Vec, salt: Option<&[u8; 32]>, - ) -> Result<(H160, ExecReturnValue), ExecError> { + ) -> Result { let executable = E::from_storage(code_hash, self.gas_meter_mut())?; let sender = &self.top_frame().account_id; let executable = self.push_frame( @@ -1385,7 +1403,7 @@ where )?; let address = T::AddressMapper::to_address(&self.top_frame().account_id); self.run(executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE), input_data) - .map(|ret| (address, ret)) + .map(|_| address) } fn terminate(&mut self, beneficiary: &H160) -> DispatchResult { @@ -1690,6 +1708,14 @@ where fn is_read_only(&self) -> bool { self.top_frame().read_only } + + fn last_frame_output(&self) -> &ExecReturnValue { + &self.top_frame().last_frame_output + } + + fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue { + &mut self.top_frame_mut().last_frame_output + } } mod sealing { @@ -2353,15 +2379,17 @@ mod tests { // ALICE is the origin of the call stack assert!(ctx.ext.caller_is_origin()); // BOB calls CHARLIE - ctx.ext.call( - Weight::zero(), - U256::zero(), - &CHARLIE_ADDR, - U256::zero(), - vec![], - true, - false, - ) + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false, + ) + .map(|_| ctx.ext.last_frame_output().clone()) }); ExtBuilder::default().build().execute_with(|| { @@ -2447,15 +2475,17 @@ mod tests { // root is the origin of the call stack. assert!(ctx.ext.caller_is_root()); // BOB calls CHARLIE. - ctx.ext.call( - Weight::zero(), - U256::zero(), - &CHARLIE_ADDR, - U256::zero(), - vec![], - true, - false, - ) + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false, + ) + .map(|_| ctx.ext.last_frame_output().clone()) }); ExtBuilder::default().build().execute_with(|| { @@ -2666,6 +2696,7 @@ mod tests { vec![], Some(&[48; 32]), ) + .map(|address| (address, ctx.ext.last_frame_output().clone())) .unwrap(); *instantiated_contract_address.borrow_mut() = Some(address); @@ -2841,15 +2872,17 @@ mod tests { assert_eq!(info.storage_byte_deposit, 0); info.storage_byte_deposit = 42; assert_eq!( - ctx.ext.call( - Weight::zero(), - U256::zero(), - &CHARLIE_ADDR, - U256::zero(), - vec![], - true, - false - ), + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false + ) + .map(|_| ctx.ext.last_frame_output().clone()), exec_trapped() ); assert_eq!(ctx.ext.contract_info().storage_byte_deposit, 42); @@ -3095,6 +3128,7 @@ mod tests { let dest = H160::from_slice(ctx.input_data.as_ref()); ctx.ext .call(Weight::zero(), U256::zero(), &dest, U256::zero(), vec![], false, false) + .map(|_| ctx.ext.last_frame_output().clone()) }); let code_charlie = MockLoader::insert(Call, |_, _| exec_success()); @@ -3137,15 +3171,17 @@ mod tests { fn call_deny_reentry() { let code_bob = MockLoader::insert(Call, |ctx, _| { if ctx.input_data[0] == 0 { - ctx.ext.call( - Weight::zero(), - U256::zero(), - &CHARLIE_ADDR, - U256::zero(), - vec![], - false, - false, - ) + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + false, + false, + ) + .map(|_| ctx.ext.last_frame_output().clone()) } else { exec_success() } @@ -3153,15 +3189,9 @@ mod tests { // call BOB with input set to '1' let code_charlie = MockLoader::insert(Call, |ctx, _| { - ctx.ext.call( - Weight::zero(), - U256::zero(), - &BOB_ADDR, - U256::zero(), - vec![1], - true, - false, - ) + ctx.ext + .call(Weight::zero(), U256::zero(), &BOB_ADDR, U256::zero(), vec![1], true, false) + .map(|_| ctx.ext.last_frame_output().clone()) }); ExtBuilder::default().build().execute_with(|| { @@ -3360,7 +3390,7 @@ mod tests { let alice_nonce = System::account_nonce(&ALICE); assert_eq!(System::account_nonce(ctx.ext.account_id()), 0); assert_eq!(ctx.ext.caller().account_id().unwrap(), &ALICE); - let (addr, _) = ctx + let addr = ctx .ext .instantiate( Weight::zero(), @@ -3916,15 +3946,17 @@ mod tests { Ok(WriteOutcome::New) ); assert_eq!( - ctx.ext.call( - Weight::zero(), - U256::zero(), - &CHARLIE_ADDR, - U256::zero(), - vec![], - true, - false, - ), + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false, + ) + .map(|_| ctx.ext.last_frame_output().clone()), exec_success() ); assert_eq!(ctx.ext.get_transient_storage(storage_key_1), Some(vec![3])); @@ -4020,15 +4052,17 @@ mod tests { Ok(WriteOutcome::New) ); assert_eq!( - ctx.ext.call( - Weight::zero(), - U256::zero(), - &CHARLIE_ADDR, - U256::zero(), - vec![], - true, - false - ), + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false + ) + .map(|_| ctx.ext.last_frame_output().clone()), exec_trapped() ); assert_eq!(ctx.ext.get_transient_storage(storage_key), Some(vec![1, 2])); @@ -4102,4 +4136,148 @@ mod tests { assert_matches!(result, Ok(_)); }); } + + #[test] + fn last_frame_output_works_on_instantiate() { + let ok_ch = MockLoader::insert(Constructor, move |_, _| { + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![127] }) + }); + let revert_ch = MockLoader::insert(Constructor, move |_, _| { + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70] }) + }); + let trap_ch = MockLoader::insert(Constructor, |_, _| Err("It's a trap!".into())); + let instantiator_ch = MockLoader::insert(Call, { + move |ctx, _| { + let value = ::Currency::minimum_balance().into(); + + // Successful instantiation should set the output + let address = ctx + .ext + .instantiate(Weight::zero(), U256::zero(), ok_ch, value, vec![], None) + .unwrap(); + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::empty(), data: vec![127] } + ); + + // Plain transfers should not set the output + ctx.ext.transfer(&address, U256::from(1)).unwrap(); + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::empty(), data: vec![127] } + ); + + // Reverted instantiation should set the output + ctx.ext + .instantiate(Weight::zero(), U256::zero(), revert_ch, value, vec![], None) + .unwrap(); + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70] } + ); + + // Trapped instantiation should clear the output + ctx.ext + .instantiate(Weight::zero(), U256::zero(), trap_ch, value, vec![], None) + .unwrap_err(); + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::empty(), data: vec![] } + ); + + exec_success() + } + }); + + ExtBuilder::default() + .with_code_hashes(MockLoader::code_hashes()) + .existential_deposit(15) + .build() + .execute_with(|| { + set_balance(&ALICE, 1000); + set_balance(&BOB_CONTRACT_ID, 100); + place_contract(&BOB, instantiator_ch); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); + + MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![], + None, + ) + .unwrap() + }); + } + + #[test] + fn last_frame_output_works_on_nested_call() { + // Call stack: BOB -> CHARLIE(revert) -> BOB' (success) + let code_bob = MockLoader::insert(Call, |ctx, _| { + if ctx.input_data.is_empty() { + // We didn't do anything yet + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::empty(), data: vec![] } + ); + + ctx.ext + .call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false, + ) + .unwrap(); + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70] } + ); + } + + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![127] }) + }); + let code_charlie = MockLoader::insert(Call, |ctx, _| { + // We didn't do anything yet + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::empty(), data: vec![] } + ); + + assert!(ctx + .ext + .call(Weight::zero(), U256::zero(), &BOB_ADDR, U256::zero(), vec![99], true, false) + .is_ok()); + assert_eq!( + ctx.ext.last_frame_output(), + &ExecReturnValue { flags: ReturnFlags::empty(), data: vec![127] } + ); + + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70] }) + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, code_bob); + place_contract(&CHARLIE, code_charlie); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 0, 0).unwrap(); + + let result = MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![0], + None, + ); + assert_matches!(result, Ok(_)); + }); + } } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index d06cdcfd4654..5c5d144f24a2 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -4325,4 +4325,33 @@ mod run_tests { assert_eq!(received.result.data, chain_id.encode()); }); } + + #[test] + fn return_data_api_works() { + let (code_return_data_api, _) = compile_module("return_data_api").unwrap(); + let (code_return_with_data, hash_return_with_data) = + compile_module("return_with_data").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Upload the io echoing fixture for later use + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code_return_with_data, + deposit_limit::(), + )); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code_return_data_api)) + .build_and_unwrap_contract(); + + // Call the contract: It will issue calls and deploys, asserting on + assert_ok!(builder::call(addr) + .value(10 * 1024) + .data(hash_return_with_data.encode()) + .build()); + }); + } } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index ebc407adacd2..4b5a9a04eb73 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -28,7 +28,7 @@ use crate::{ }; use alloc::{boxed::Box, vec, vec::Vec}; use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; -use core::{fmt, marker::PhantomData}; +use core::{fmt, marker::PhantomData, mem}; use frame_support::{ dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types, traits::Get, weights::Weight, @@ -237,8 +237,8 @@ parameter_types! { const XcmExecutionFailed: ReturnErrorCode = ReturnErrorCode::XcmExecutionFailed; } -impl From for ReturnErrorCode { - fn from(from: ExecReturnValue) -> Self { +impl From<&ExecReturnValue> for ReturnErrorCode { + fn from(from: &ExecReturnValue) -> Self { if from.flags.contains(ReturnFlags::REVERT) { Self::CalleeReverted } else { @@ -769,20 +769,16 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { } } - /// Fallible conversion of a `ExecResult` to `ReturnErrorCode`. - fn exec_into_return_code(from: ExecResult) -> Result { + /// Fallible conversion of a `ExecError` to `ReturnErrorCode`. + fn exec_error_into_return_code(from: ExecError) -> Result { use crate::exec::ErrorOrigin::Callee; - let ExecError { error, origin } = match from { - Ok(retval) => return Ok(retval.into()), - Err(err) => err, - }; - - match (error, origin) { + match (from.error, from.origin) { (_, Callee) => Ok(ReturnErrorCode::CalleeTrapped), (err, _) => Self::err_into_return_code(err), } } + fn decode_key(&self, memory: &M, key_ptr: u32, key_len: u32) -> Result { let res = match key_len { SENTINEL => { @@ -1036,28 +1032,32 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { }, }; - // `TAIL_CALL` only matters on an `OK` result. Otherwise the call stack comes to - // a halt anyways without anymore code being executed. - if flags.contains(CallFlags::TAIL_CALL) { - if let Ok(return_value) = call_outcome { + match call_outcome { + // `TAIL_CALL` only matters on an `OK` result. Otherwise the call stack comes to + // a halt anyways without anymore code being executed. + Ok(_) if flags.contains(CallFlags::TAIL_CALL) => { + let output = mem::take(self.ext.last_frame_output_mut()); return Err(TrapReason::Return(ReturnData { - flags: return_value.flags.bits(), - data: return_value.data, + flags: output.flags.bits(), + data: output.data, })); - } - } - - if let Ok(output) = &call_outcome { - self.write_sandbox_output( - memory, - output_ptr, - output_len_ptr, - &output.data, - true, - |len| Some(RuntimeCosts::CopyToContract(len)), - )?; + }, + Ok(_) => { + let output = mem::take(self.ext.last_frame_output_mut()); + let write_result = self.write_sandbox_output( + memory, + output_ptr, + output_len_ptr, + &output.data, + true, + |len| Some(RuntimeCosts::CopyToContract(len)), + ); + *self.ext.last_frame_output_mut() = output; + write_result?; + Ok(self.ext.last_frame_output().into()) + }, + Err(err) => Ok(Self::exec_error_into_return_code(err)?), } - Ok(Self::exec_into_return_code(call_outcome)?) } fn instantiate( @@ -1086,34 +1086,40 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { let salt: [u8; 32] = memory.read_array(salt_ptr)?; Some(salt) }; - let instantiate_outcome = self.ext.instantiate( + + match self.ext.instantiate( weight, deposit_limit, code_hash, value, input_data, salt.as_ref(), - ); - if let Ok((address, output)) = &instantiate_outcome { - if !output.flags.contains(ReturnFlags::REVERT) { - self.write_fixed_sandbox_output( + ) { + Ok(address) => { + if !self.ext.last_frame_output().flags.contains(ReturnFlags::REVERT) { + self.write_fixed_sandbox_output( + memory, + address_ptr, + &address.as_bytes(), + true, + already_charged, + )?; + } + let output = mem::take(self.ext.last_frame_output_mut()); + let write_result = self.write_sandbox_output( memory, - address_ptr, - &address.as_bytes(), + output_ptr, + output_len_ptr, + &output.data, true, - already_charged, - )?; - } - self.write_sandbox_output( - memory, - output_ptr, - output_len_ptr, - &output.data, - true, - |len| Some(RuntimeCosts::CopyToContract(len)), - )?; + |len| Some(RuntimeCosts::CopyToContract(len)), + ); + *self.ext.last_frame_output_mut() = output; + write_result?; + Ok(self.ext.last_frame_output().into()) + }, + Err(err) => Ok(Self::exec_error_into_return_code(err)?), } - Ok(Self::exec_into_return_code(instantiate_outcome.map(|(_, retval)| retval))?) } fn terminate(&mut self, memory: &M, beneficiary_ptr: u32) -> Result<(), TrapReason> { @@ -1993,4 +1999,44 @@ pub mod env { self.ext.unlock_delegate_dependency(&code_hash)?; Ok(()) } + + /// Stores the length of the data returned by the last call into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::return_data_size`]. + #[api_version(0)] + fn return_data_size(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &as_bytes(U256::from(self.ext.last_frame_output().data.len())), + false, + |len| Some(RuntimeCosts::CopyToContract(len)), + )?) + } + + /// Stores data returned by the last call, starting from `offset`, into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::return_data`]. + #[api_version(0)] + fn return_data_copy( + &mut self, + memory: &mut M, + out_ptr: u32, + out_len_ptr: u32, + offset: u32, + ) -> Result<(), TrapReason> { + let output = mem::take(self.ext.last_frame_output_mut()); + let result = if offset as usize > output.data.len() { + Err(Error::::OutOfBounds.into()) + } else { + self.write_sandbox_output( + memory, + out_ptr, + out_len_ptr, + &output.data[offset as usize..], + false, + |len| Some(RuntimeCosts::CopyToContract(len)), + ) + }; + *self.ext.last_frame_output_mut() = output; + Ok(result?) + } } diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 57a03332670f..816fdec3aaaf 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -620,6 +620,20 @@ pub trait HostFn: private::Sealed { /// Returns `ReturnCode::Success` when the message was successfully sent. When the XCM /// execution fails, `ReturnErrorCode::XcmSendFailed` is returned. fn xcm_send(dest: &[u8], msg: &[u8], output: &mut [u8; 32]) -> Result; + + /// Stores the size of the returned data of the last contract call or instantiation. + /// + /// # Parameters + /// + /// - `output`: A reference to the output buffer to write the size. + fn return_data_size(output: &mut [u8; 32]); + + /// Stores the returned data of the last contract call or contract instantiation. + /// + /// # Parameters + /// - `output`: A reference to the output buffer to write the data. + /// - `offset`: Byte offset into the returned data + fn return_data_copy(output: &mut &mut [u8], offset: u32); } mod private { diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv32.rs index a60c338e8bd9..d5ea94c1a910 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv32.rs @@ -131,6 +131,8 @@ mod sys { msg_len: u32, out_ptr: *mut u8, ) -> ReturnCode; + pub fn return_data_size(out_ptr: *mut u8); + pub fn return_data_copy(out_ptr: *mut u8, out_len_ptr: *mut u32, offset: u32); } } @@ -548,4 +550,16 @@ impl HostFn for HostFnImpl { }; ret_code.into() } + + fn return_data_size(output: &mut [u8; 32]) { + unsafe { sys::return_data_size(output.as_mut_ptr()) }; + } + + fn return_data_copy(output: &mut &mut [u8], offset: u32) { + let mut output_len = output.len() as u32; + { + unsafe { sys::return_data_copy(output.as_mut_ptr(), &mut output_len, offset) }; + } + extract_from_slice(output, output_len as usize); + } } diff --git a/substrate/frame/society/src/lib.rs b/substrate/frame/society/src/lib.rs index b4c5c88af3d6..04879cd87091 100644 --- a/substrate/frame/society/src/lib.rs +++ b/substrate/frame/society/src/lib.rs @@ -1387,18 +1387,6 @@ impl_ensure_origin_with_arg_ignoring_arg! { {} } -struct InputFromRng<'a, T>(&'a mut T); -impl<'a, T: RngCore> codec::Input for InputFromRng<'a, T> { - fn remaining_len(&mut self) -> Result, codec::Error> { - return Ok(None) - } - - fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { - self.0.fill_bytes(into); - Ok(()) - } -} - pub enum Period { Voting { elapsed: BlockNumber, more: BlockNumber }, Claim { elapsed: BlockNumber, more: BlockNumber }, diff --git a/substrate/frame/society/src/tests.rs b/substrate/frame/society/src/tests.rs index df8e844cdad9..2a13f99855b5 100644 --- a/substrate/frame/society/src/tests.rs +++ b/substrate/frame/society/src/tests.rs @@ -281,7 +281,7 @@ fn bidding_works() { // No more candidates satisfy the requirements assert_eq!(candidacies(), vec![]); assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around - // Next period + // Next period run_to_block(16); // Same members assert_eq!(members(), vec![10, 30, 40, 50]); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ab2c00ca9ccc..dd178a95bec5 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7995,7 +7995,7 @@ mod ledger_recovery { assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK assert!(Payee::::get(&333).is_some()); // OK - // however, ledger associated with its controller was killed. + // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK // side effects on 444 - ledger, bonded, payee, lock should be completely removed. diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs index 3e38adcc3c59..729a803a302e 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs @@ -592,8 +592,6 @@ pub struct Pallet { pub cfg_pattern: Vec, /// The doc literals pub docs: Vec, - /// attributes - pub attrs: Vec, } impl Pallet { @@ -764,7 +762,6 @@ fn convert_pallets(pallets: Vec) -> syn::Result>>()?; diff --git a/substrate/frame/support/procedural/src/derive_impl.rs b/substrate/frame/support/procedural/src/derive_impl.rs index 69117c026816..5d39c2707def 100644 --- a/substrate/frame/support/procedural/src/derive_impl.rs +++ b/substrate/frame/support/procedural/src/derive_impl.rs @@ -304,6 +304,7 @@ fn test_derive_impl_attr_args_parsing() { #[test] fn test_runtime_type_with_doc() { + #[allow(dead_code)] trait TestTrait { type Test; } diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index d40a571c9eab..a2c1e6eec7f7 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -321,9 +321,10 @@ pub fn derive_debug_no_bound(input: TokenStream) -> TokenStream { /// This behaviour is useful to prevent bloating the runtime WASM blob from unneeded code. #[proc_macro_derive(RuntimeDebugNoBound)] pub fn derive_runtime_debug_no_bound(input: TokenStream) -> TokenStream { - if cfg!(any(feature = "std", feature = "try-runtime")) { - no_bound::debug::derive_debug_no_bound(input) - } else { + let try_runtime_or_std_impl: proc_macro2::TokenStream = + no_bound::debug::derive_debug_no_bound(input.clone()).into(); + + let stripped_impl = { let input = syn::parse_macro_input!(input as syn::DeriveInput); let name = &input.ident; @@ -338,8 +339,22 @@ pub fn derive_runtime_debug_no_bound(input: TokenStream) -> TokenStream { } }; ) - .into() - } + }; + + let frame_support = match generate_access_from_frame_or_crate("frame-support") { + Ok(frame_support) => frame_support, + Err(e) => return e.to_compile_error().into(), + }; + + quote::quote!( + #frame_support::try_runtime_or_std_enabled! { + #try_runtime_or_std_impl + } + #frame_support::try_runtime_and_std_not_enabled! { + #stripped_impl + } + ) + .into() } /// Derive [`PartialEq`] but do not bound any generic. diff --git a/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs b/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs index 248e83469435..b71aed680dc8 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/genesis_build.rs @@ -35,7 +35,7 @@ pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream { let where_clause = &genesis_build.where_clause; quote::quote_spanned!(genesis_build.attr_span => - #[cfg(feature = "std")] + #frame_support::std_enabled! { impl<#type_impl_gen> #frame_support::sp_runtime::BuildStorage for #gen_cfg_ident<#gen_cfg_use_gen> #where_clause { fn assimilate_storage(&self, storage: &mut #frame_support::sp_runtime::Storage) -> std::result::Result<(), std::string::String> { @@ -45,5 +45,6 @@ pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream { }) } } + } ) } diff --git a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs index 1b0c09c4e365..c31ddd8a47ba 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/hooks.rs @@ -324,15 +324,13 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { Self as #frame_support::traits::Hooks< #frame_system::pallet_prelude::BlockNumberFor:: > - >::try_state(n).map_err(|err| { + >::try_state(n).inspect_err(|err| { #frame_support::__private::log::error!( target: #frame_support::LOG_TARGET, "❌ {:?} try_state checks failed: {:?}", #pallet_name, err ); - - err }) } } diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index 346dff46f12e..68ced1bc0ed3 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -400,18 +400,19 @@ impl CallDef { } for (feeless_arg, arg) in feeless_check.inputs.iter().skip(1).zip(args.iter()) { - let feeless_arg_type = - if let syn::Pat::Type(syn::PatType { ty, .. }) = feeless_arg.clone() { - if let syn::Type::Reference(pat) = *ty { - pat.elem.clone() - } else { - let msg = "Invalid pallet::call, feeless_if closure argument must be a reference"; - return Err(syn::Error::new(ty.span(), msg)); - } + let feeless_arg_type = if let syn::Pat::Type(syn::PatType { ty, .. }) = + feeless_arg.clone() + { + if let syn::Type::Reference(pat) = *ty { + pat.elem.clone() } else { - let msg = "Invalid pallet::call, feeless_if closure argument must be a type ascription pattern"; - return Err(syn::Error::new(feeless_arg.span(), msg)); - }; + let msg = "Invalid pallet::call, feeless_if closure argument must be a reference"; + return Err(syn::Error::new(ty.span(), msg)); + } + } else { + let msg = "Invalid pallet::call, feeless_if closure argument must be a type ascription pattern"; + return Err(syn::Error::new(feeless_arg.span(), msg)); + }; if feeless_arg_type != arg.2 { let msg = diff --git a/substrate/frame/support/procedural/src/runtime/expand/mod.rs b/substrate/frame/support/procedural/src/runtime/expand/mod.rs index f34ab1cef543..666bc03aa415 100644 --- a/substrate/frame/support/procedural/src/runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/runtime/expand/mod.rs @@ -77,7 +77,7 @@ pub fn expand(def: Def, legacy_ordering: bool) -> TokenStream2 { }; let res = expander::Expander::new("construct_runtime") - .dry(std::env::var("FRAME_EXPAND").is_err()) + .dry(std::env::var("EXPAND_MACROS").is_err()) .verbose(true) .write_to_out_dir(res) .expect("Does not fail because of IO in OUT_DIR; qed"); diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs index de1efa267c89..52f57cd2cd8b 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs @@ -91,7 +91,6 @@ impl Pallet { cfg_pattern, pallet_parts, docs, - attrs: item.attrs.clone(), }) } } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 28283f2a5a06..269867e38c51 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -2523,6 +2523,8 @@ pub use frame_support_procedural::register_default_impl; sp_core::generate_feature_enabled_macro!(std_enabled, feature = "std", $); // Generate a macro that will enable/disable code based on `try-runtime` feature being active. sp_core::generate_feature_enabled_macro!(try_runtime_enabled, feature = "try-runtime", $); +sp_core::generate_feature_enabled_macro!(try_runtime_or_std_enabled, any(feature = "try-runtime", feature = "std"), $); +sp_core::generate_feature_enabled_macro!(try_runtime_and_std_not_enabled, all(not(feature = "try-runtime"), not(feature = "std")), $); // Helper for implementing GenesisBuilder runtime API pub mod genesis_builder_helper; diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 0eabf9d0ee16..905d6143e4f1 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -529,6 +529,25 @@ pub trait SteppedMigration { }) .map_err(|()| SteppedMigrationError::Failed)? } + + /// Hook for testing that is run before the migration is started. + /// + /// Returns some bytes which are passed into `post_upgrade` after the migration is completed. + /// This is not run for the real migration, so panicking is not an issue here. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + Ok(Vec::new()) + } + + /// Hook for testing that is run after the migration is completed. + /// + /// Should be used to verify the state of the chain after the migration. The `state` parameter + /// is the return value from `pre_upgrade`. This is not run for the real migration, so panicking + /// is not an issue here. + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + Ok(()) + } } /// Error that can occur during a [`SteppedMigration`]. @@ -700,6 +719,19 @@ pub trait SteppedMigrations { meter: &mut WeightMeter, ) -> Option>, SteppedMigrationError>>; + /// Call the pre-upgrade hooks of the `n`th migration. + /// + /// Returns `None` if the index is out of bounds. + #[cfg(feature = "try-runtime")] + fn nth_pre_upgrade(n: u32) -> Option, sp_runtime::TryRuntimeError>>; + + /// Call the post-upgrade hooks of the `n`th migration. + /// + /// Returns `None` if the index is out of bounds. + #[cfg(feature = "try-runtime")] + fn nth_post_upgrade(n: u32, _state: Vec) + -> Option>; + /// The maximal encoded length across all cursors. fn cursor_max_encoded_len() -> usize; @@ -763,6 +795,19 @@ impl SteppedMigrations for () { None } + #[cfg(feature = "try-runtime")] + fn nth_pre_upgrade(_n: u32) -> Option, sp_runtime::TryRuntimeError>> { + Some(Ok(Vec::new())) + } + + #[cfg(feature = "try-runtime")] + fn nth_post_upgrade( + _n: u32, + _state: Vec, + ) -> Option> { + Some(Ok(())) + } + fn cursor_max_encoded_len() -> usize { 0 } @@ -792,11 +837,11 @@ impl SteppedMigrations for T { } fn nth_step( - _n: u32, + n: u32, cursor: Option>, meter: &mut WeightMeter, ) -> Option>, SteppedMigrationError>> { - if !_n.is_zero() { + if !n.is_zero() { defensive!("nth_step should only be called with n==0"); return None } @@ -835,6 +880,23 @@ impl SteppedMigrations for T { ) } + #[cfg(feature = "try-runtime")] + fn nth_pre_upgrade(n: u32) -> Option, sp_runtime::TryRuntimeError>> { + if n != 0 { + defensive!("nth_pre_upgrade should only be called with n==0"); + } + + Some(T::pre_upgrade()) + } + + #[cfg(feature = "try-runtime")] + fn nth_post_upgrade(n: u32, state: Vec) -> Option> { + if n != 0 { + defensive!("nth_post_upgrade should only be called with n==0"); + } + Some(T::post_upgrade(state)) + } + fn cursor_max_encoded_len() -> usize { T::Cursor::max_encoded_len() } @@ -900,6 +962,36 @@ impl SteppedMigrations for Tuple { None } + #[cfg(feature = "try-runtime")] + fn nth_pre_upgrade(n: u32) -> Option, sp_runtime::TryRuntimeError>> { + let mut i = 0; + + for_tuples! ( #( + if (i + Tuple::len()) > n { + return Tuple::nth_pre_upgrade(n - i) + } + + i += Tuple::len(); + )* ); + + None + } + + #[cfg(feature = "try-runtime")] + fn nth_post_upgrade(n: u32, state: Vec) -> Option> { + let mut i = 0; + + for_tuples! ( #( + if (i + Tuple::len()) > n { + return Tuple::nth_post_upgrade(n - i, state) + } + + i += Tuple::len(); + )* ); + + None + } + fn nth_max_steps(n: u32) -> Option> { let mut i = 0; diff --git a/substrate/frame/support/src/storage/generator/double_map.rs b/substrate/frame/support/src/storage/generator/double_map.rs index b68f3fa495ff..a9116f1f66bd 100644 --- a/substrate/frame/support/src/storage/generator/double_map.rs +++ b/substrate/frame/support/src/storage/generator/double_map.rs @@ -346,9 +346,8 @@ where final_key }; - unhashed::take(old_key.as_ref()).map(|value| { + unhashed::take(old_key.as_ref()).inspect(|value| { unhashed::put(Self::storage_double_map_final_key(key1, key2).as_ref(), &value); - value }) } } diff --git a/substrate/frame/support/src/storage/generator/map.rs b/substrate/frame/support/src/storage/generator/map.rs index e905df41a5a6..2d1f6c9f73a2 100644 --- a/substrate/frame/support/src/storage/generator/map.rs +++ b/substrate/frame/support/src/storage/generator/map.rs @@ -311,9 +311,8 @@ impl> storage::StorageMap final_key }; - unhashed::take(old_key.as_ref()).map(|value| { + unhashed::take(old_key.as_ref()).inspect(|value| { unhashed::put(Self::storage_map_final_key(key).as_ref(), &value); - value }) } } diff --git a/substrate/frame/support/src/storage/generator/nmap.rs b/substrate/frame/support/src/storage/generator/nmap.rs index 0466583a2795..9083aba9d32c 100755 --- a/substrate/frame/support/src/storage/generator/nmap.rs +++ b/substrate/frame/support/src/storage/generator/nmap.rs @@ -305,9 +305,8 @@ where final_key }; - unhashed::take(old_key.as_ref()).map(|value| { + unhashed::take(old_key.as_ref()).inspect(|value| { unhashed::put(Self::storage_n_map_final_key::(key).as_ref(), &value); - value }) } } diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index c70d9de54467..24aad3de0b33 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -129,7 +129,8 @@ impl OnEmpty, MaxValues, >, - > where + > +where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, Hasher2: crate::hash::StorageHasher, diff --git a/substrate/frame/support/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index 5e1bcc777df4..7c90a12d4167 100644 --- a/substrate/frame/support/src/tests/mod.rs +++ b/substrate/frame/support/src/tests/mod.rs @@ -769,5 +769,6 @@ fn derive_partial_eq_no_bound_core_mod() { crate::DefaultNoBound, crate::EqNoBound, )] + #[allow(dead_code)] struct Test; } diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 492475d6f63c..4d3b122daf67 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -488,7 +488,7 @@ pub trait DefensiveMin { /// assert_eq!(4, 4_u32.defensive_min(4_u32)); /// ``` /// - /// ```#[cfg_attr(debug_assertions, should_panic)] + /// ```should_panic /// use frame_support::traits::DefensiveMin; /// // min(4, 3) panics. /// 4_u32.defensive_min(3_u32); @@ -505,7 +505,7 @@ pub trait DefensiveMin { /// assert_eq!(3, 3_u32.defensive_strict_min(4_u32)); /// ``` /// - /// ```#[cfg_attr(debug_assertions, should_panic)] + /// ```should_panic /// use frame_support::traits::DefensiveMin; /// // min(4, 4) panics. /// 4_u32.defensive_strict_min(4_u32); @@ -552,7 +552,7 @@ pub trait DefensiveMax { /// assert_eq!(4, 4_u32.defensive_max(4_u32)); /// ``` /// - /// ```#[cfg_attr(debug_assertions, should_panic)] + /// ```should_panic /// use frame_support::traits::DefensiveMax; /// // max(4, 5) panics. /// 4_u32.defensive_max(5_u32); @@ -569,7 +569,7 @@ pub trait DefensiveMax { /// assert_eq!(4, 4_u32.defensive_strict_max(3_u32)); /// ``` /// - /// ```#[cfg_attr(debug_assertions, should_panic)] + /// ```should_panic /// use frame_support::traits::DefensiveMax; /// // max(4, 4) panics. /// 4_u32.defensive_strict_max(4_u32); diff --git a/substrate/frame/support/src/traits/proving.rs b/substrate/frame/support/src/traits/proving.rs index dc44f4cd68e7..84e37bde38db 100644 --- a/substrate/frame/support/src/traits/proving.rs +++ b/substrate/frame/support/src/traits/proving.rs @@ -20,6 +20,10 @@ use alloc::vec::Vec; use codec::{Decode, Encode}; use sp_core::Hasher; +use sp_runtime::DispatchError; + +// Re-export the `proving_trie` types and traits. +pub use sp_runtime::proving_trie::*; /// Something that can verify the existence of some data in a given proof. pub trait VerifyExistenceProof { @@ -31,7 +35,7 @@ pub trait VerifyExistenceProof { /// Verify the given `proof`. /// /// Ensures that the `proof` was build for `root` and returns the proved data. - fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, ()>; + fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, DispatchError>; } /// Implements [`VerifyExistenceProof`] using a binary merkle tree. @@ -44,9 +48,9 @@ where type Proof = binary_merkle_tree::MerkleProof>; type Hash = H::Out; - fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, ()> { + fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, DispatchError> { if proof.root != *root { - return Err(()); + return Err(TrieError::RootMismatch.into()); } if binary_merkle_tree::verify_proof::( @@ -58,13 +62,25 @@ where ) { Ok(proof.leaf) } else { - Err(()) + Err(TrieError::IncompleteProof.into()) } } } +impl ProofToHashes for BinaryMerkleTreeProver { + type Proof = binary_merkle_tree::MerkleProof>; + + // This base 2 merkle trie includes a `proof` field which is a `Vec`. + // The length of this vector tells us the depth of the proof, and how many + // hashes we need to calculate. + fn proof_to_hashes(proof: &Self::Proof) -> Result { + let depth = proof.proof.len(); + Ok(depth as u32) + } +} + /// Proof used by [`SixteenPatriciaMerkleTreeProver`] for [`VerifyExistenceProof`]. -#[derive(Encode, Decode)] +#[derive(Encode, Decode, Clone)] pub struct SixteenPatriciaMerkleTreeExistenceProof { /// The key of the value to prove. pub key: Vec, @@ -81,21 +97,35 @@ impl VerifyExistenceProof for SixteenPatriciaMerkleTreeProver { type Proof = SixteenPatriciaMerkleTreeExistenceProof; type Hash = H::Out; - fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, ()> { + fn verify_proof(proof: Self::Proof, root: &Self::Hash) -> Result, DispatchError> { sp_trie::verify_trie_proof::, _, _, _>( &root, &proof.proof, [&(&proof.key, Some(&proof.value))], ) - .map_err(drop) + .map_err(|err| TrieError::from(err).into()) .map(|_| proof.value) } } +impl ProofToHashes for SixteenPatriciaMerkleTreeProver { + type Proof = SixteenPatriciaMerkleTreeExistenceProof; + + // This base 16 trie uses a raw proof of `Vec`, where the length of the first `Vec` + // is the depth of the trie. We can use this to predict the number of hashes. + fn proof_to_hashes(proof: &Self::Proof) -> Result { + let depth = proof.proof.len(); + Ok(depth as u32) + } +} + #[cfg(test)] mod tests { use super::*; - use sp_runtime::{proving_trie::BasicProvingTrie, traits::BlakeTwo256}; + use sp_runtime::{ + proving_trie::{base16::BasicProvingTrie, ProvingTrie}, + traits::BlakeTwo256, + }; #[test] fn verify_binary_merkle_tree_prover_works() { @@ -113,23 +143,87 @@ mod tests { #[test] fn verify_sixteen_patricia_merkle_tree_prover_works() { - let trie = BasicProvingTrie::::generate_for(vec![ - (0u32, &b"hey"[..]), - (1u32, &b"yes"[..]), + let trie = BasicProvingTrie::::generate_for(vec![ + (0u32, String::from("hey")), + (1u32, String::from("yes")), ]) .unwrap(); - let proof = trie.create_single_value_proof(1u32).unwrap(); + let proof = trie.create_proof(&1u32).unwrap(); + let structured_proof: Vec> = Decode::decode(&mut &proof[..]).unwrap(); let root = *trie.root(); let proof = SixteenPatriciaMerkleTreeExistenceProof { key: 1u32.encode(), - value: b"yes"[..].encode(), - proof, + value: String::from("yes").encode(), + proof: structured_proof, }; assert_eq!( SixteenPatriciaMerkleTreeProver::::verify_proof(proof, &root).unwrap(), - b"yes"[..].encode() + String::from("yes").encode() ); } + + #[test] + fn proof_to_hashes_sixteen() { + let mut i: u32 = 1; + + // Compute log base 16 and round up + let log16 = |x: u32| -> u32 { + let x_f64 = x as f64; + let log16_x = (x_f64.ln() / 16_f64.ln()).ceil(); + log16_x as u32 + }; + + while i < 10_000_000 { + let trie = BasicProvingTrie::::generate_for( + (0..i).map(|i| (i, u128::from(i))), + ) + .unwrap(); + let proof = trie.create_proof(&0).unwrap(); + let structured_proof: Vec> = Decode::decode(&mut &proof[..]).unwrap(); + let root = *trie.root(); + + let proof = SixteenPatriciaMerkleTreeExistenceProof { + key: 0u32.encode(), + value: 0u128.encode(), + proof: structured_proof, + }; + let hashes = + SixteenPatriciaMerkleTreeProver::::proof_to_hashes(&proof).unwrap(); + let log16 = log16(i).max(1); + assert_eq!(hashes, log16); + + assert_eq!( + SixteenPatriciaMerkleTreeProver::::verify_proof(proof.clone(), &root) + .unwrap(), + proof.value + ); + + i = i * 10; + } + } + + #[test] + fn proof_to_hashes_binary() { + let mut i: u32 = 1; + while i < 10_000_000 { + let proof = binary_merkle_tree::merkle_proof::( + (0..i).map(|i| u128::from(i).encode()), + 0, + ); + let root = proof.root; + + let hashes = BinaryMerkleTreeProver::::proof_to_hashes(&proof).unwrap(); + let log2 = (i as f64).log2().ceil() as u32; + assert_eq!(hashes, log2); + + assert_eq!( + BinaryMerkleTreeProver::::verify_proof(proof, &root).unwrap(), + 0u128.encode() + ); + + i = i * 10; + } + } } diff --git a/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs b/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs index 8dbeecd8e860..a7465c87fb27 100644 --- a/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs +++ b/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs @@ -197,7 +197,8 @@ impl TryDecodeEntireS QueryKind, OnEmpty, MaxValues, - > where + > +where Prefix: CountedStorageMapInstance, Hasher: StorageHasher, Key: FullCodec, @@ -229,7 +230,8 @@ impl QueryKind, OnEmpty, MaxValues, - > where + > +where Prefix: StorageInstance, Hasher1: StorageHasher, Key1: FullCodec, diff --git a/substrate/frame/support/src/traits/try_runtime/mod.rs b/substrate/frame/support/src/traits/try_runtime/mod.rs index 09c33c014406..284ba3d7422d 100644 --- a/substrate/frame/support/src/traits/try_runtime/mod.rs +++ b/substrate/frame/support/src/traits/try_runtime/mod.rs @@ -28,7 +28,7 @@ use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_runtime::TryRuntimeError; /// Which state tests to execute. -#[derive(codec::Encode, codec::Decode, Clone, scale_info::TypeInfo)] +#[derive(codec::Encode, codec::Decode, Clone, scale_info::TypeInfo, PartialEq)] pub enum Select { /// None of them. None, @@ -95,7 +95,7 @@ impl std::str::FromStr for Select { } /// Select which checks should be run when trying a runtime upgrade upgrade. -#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy, scale_info::TypeInfo)] +#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy, scale_info::TypeInfo, PartialEq)] pub enum UpgradeCheckSelect { /// Run no checks. None, diff --git a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr index 7e0a02be649b..04203e4b684b 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/bad_return_type_blank_with_question.stderr @@ -8,3 +8,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual>` is not implemented for `()` +help: consider adding return type + | +31 | fn bench() -> Result<(), Box> { + | +++++++++++++++++++++++++++++++++++++++++ diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index b28cae2ddefa..59e36775d464 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -53,7 +53,15 @@ note: required by a bound in `frame_system::Event` | ^^^^^^ required by this bound in `Event` = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | ^ the trait `Config` is not implemented for `Runtime` + | + = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `RawOrigin<_>: TryFrom` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -63,9 +71,12 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEven ... | 27 | | } 28 | | } - | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` + | |_^ the trait `TryFrom` is not implemented for `RawOrigin<_>` | -note: required because it appears within the type `RuntimeEvent` + = help: the trait `TryFrom` is implemented for `RawOrigin<::AccountId>` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -75,15 +86,25 @@ note: required because it appears within the type `RuntimeEvent` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `Clone` - --> $RUST/core/src/clone.rs + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: Callable` | - | pub trait Clone: Sized { - | ^^^^^ required by this bound in `Clone` - = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `Callable` is implemented for `Pallet` + = note: required for `Pallet` to implement `Callable` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:26:3 + | +26 | System: frame_system::{Pallet, Call, Storage, Config, Event}, + | ^^^^^^ the trait `Config` is not implemented for `Runtime` + | +note: required by a bound in `GenesisConfig` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub struct GenesisConfig { + | ^^^^^^ required by this bound in `GenesisConfig` -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -93,9 +114,16 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEven ... | 27 | | } 28 | | } - | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` + | |_^ the trait `Config` is not implemented for `Runtime` | -note: required because it appears within the type `RuntimeEvent` +note: required by a bound in `frame_system::Event` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub enum Event { + | ^^^^^^ required by this bound in `Event` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0369]: binary operation `==` cannot be applied to type `&frame_system::Event` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -106,14 +134,21 @@ note: required because it appears within the type `RuntimeEvent` 27 | | } 28 | | } | |_^ -note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.12/src/encode_like.rs | - | pub trait EncodeLike: Sized + Encode {} - | ^^^^^ required by this bound in `EncodeLike` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +note: an implementation of `Config` might be missing for `Runtime` + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where + | |______________________^ must implement `Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `PartialEq` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -123,9 +158,16 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEven ... | 27 | | } 28 | | } - | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` + | |_^ the trait `Config` is not implemented for `Runtime` | -note: required because it appears within the type `RuntimeEvent` +note: required by a bound in `frame_system::Event` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub enum Event { + | ^^^^^^ required by this bound in `Event` + = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `frame_system::Event: Encode` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -135,15 +177,12 @@ note: required because it appears within the type `RuntimeEvent` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.12/src/codec.rs + | |_^ the trait `Encode` is not implemented for `frame_system::Event` | - | pub trait Decode: Sized { - | ^^^^^ required by this bound in `Decode` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `Encode` is implemented for `frame_system::Event` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_system::Event` +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -153,21 +192,16 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_syste ... | 27 | | } 28 | | } - | |_^ within `frame_system::Event`, the trait `Config` is not implemented for `Runtime`, which is required by `frame_system::Event: Sized` + | |_^ the trait `Config` is not implemented for `Runtime` | -note: required because it appears within the type `frame_system::Event` +note: required by a bound in `frame_system::Event` --> $WORKSPACE/substrate/frame/system/src/lib.rs | | pub enum Event { - | ^^^^^ -note: required by a bound in `From` - --> $RUST/core/src/convert/mod.rs - | - | pub trait From: Sized { - | ^ required by this bound in `From` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^ required by this bound in `Event` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_system::Event` +error[E0277]: the trait bound `frame_system::Event: Decode` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -177,29 +211,40 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_syste ... | 27 | | } 28 | | } - | |_^ within `frame_system::Event`, the trait `Config` is not implemented for `Runtime`, which is required by `frame_system::Event: Sized` + | |_^ the trait `Decode` is not implemented for `frame_system::Event` | -note: required because it appears within the type `frame_system::Event` + = help: the trait `Decode` is implemented for `frame_system::Event` + +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:26:11 + | +26 | System: frame_system::{Pallet, Call, Storage, Config, Event}, + | ^^^^^^^^^^^^ the trait `Config` is not implemented for `Runtime` + | +note: required by a bound in `frame_system::Event` --> $WORKSPACE/substrate/frame/system/src/lib.rs | | pub enum Event { - | ^^^^^ -note: required by a bound in `TryInto` - --> $RUST/core/src/convert/mod.rs - | - | pub trait TryInto: Sized { - | ^ required by this bound in `TryInto` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^ required by this bound in `Event` error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | construct_runtime! { - | ^ the trait `Config` is not implemented for `Runtime` +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `frame_system::Event: std::fmt::Debug` | - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `std::fmt::Debug` is implemented for `frame_system::Event` + = note: required for `frame_system::Event` to implement `std::fmt::Debug` + = note: required for the cast from `&frame_system::Event` to `&dyn std::fmt::Debug` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::RuntimeDebug` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `RawOrigin<_>: TryFrom` is not satisfied +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -209,10 +254,12 @@ error[E0277]: the trait bound `RawOrigin<_>: TryFrom` is not satis ... | 27 | | } 28 | | } - | |_^ the trait `TryFrom` is not implemented for `RawOrigin<_>` + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `frame_system::Error: std::fmt::Debug` | - = help: the trait `TryFrom` is implemented for `RawOrigin<::AccountId>` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `std::fmt::Debug` is implemented for `frame_system::Error` + = note: required for `frame_system::Error` to implement `std::fmt::Debug` + = note: required for the cast from `&frame_system::Error` to `&dyn std::fmt::Debug` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::RuntimeDebug` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 @@ -224,11 +271,15 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: Callable` + | |_^ the trait `Config` is not implemented for `Runtime` | - = help: the trait `Callable` is implemented for `Pallet` - = note: required for `Pallet` to implement `Callable` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:21:13 + | +21 | pub struct Runtime where + | ^^^^^^^ the trait `Config` is not implemented for `Runtime` error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 @@ -240,10 +291,12 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RawOrigin<_>: Into<_>` | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` + = note: required for `RawOrigin<_>` to implement `Into` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -253,13 +306,9 @@ note: required because it appears within the type `RuntimeCall` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `Clone` - --> $RUST/core/src/clone.rs + | |_^ the trait `Config` is not implemented for `Runtime` | - | pub trait Clone: Sized { - | ^^^^^ required by this bound in `Clone` - = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 @@ -271,10 +320,17 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | |_^ the trait `Config` is not implemented for `Runtime` | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::RuntimeDebug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:26:11 + | +26 | System: frame_system::{Pallet, Call, Storage, Config, Event}, + | ^^^^^^^^^^^^ the trait `Config` is not implemented for `Runtime` + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -284,12 +340,10 @@ note: required because it appears within the type `RuntimeCall` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.12/src/encode_like.rs + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: PalletInfoAccess` | - | pub trait EncodeLike: Sized + Encode {} - | ^^^^^ required by this bound in `EncodeLike` + = help: the trait `PalletInfoAccess` is implemented for `Pallet` + = note: required for `Pallet` to implement `PalletInfoAccess` = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied @@ -302,10 +356,13 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: Callable` | + = help: the trait `Callable` is implemented for `Pallet` = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -315,15 +372,13 @@ note: required because it appears within the type `RuntimeCall` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.12/src/codec.rs + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: Callable` | - | pub trait Decode: Sized { - | ^^^^^ required by this bound in `Decode` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `Callable` is implemented for `Pallet` + = note: required for `Pallet` to implement `Callable` + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied +error[E0369]: binary operation `==` cannot be applied to type `&frame_system::Call` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -333,10 +388,22 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | |_^ | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` +note: an implementation of `Config` might be missing for `Runtime` + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where + | |______________________^ must implement `Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `PartialEq` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `frame_system::Call: Encode` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -346,27 +413,31 @@ note: required because it appears within the type `RuntimeCall` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `frame_support::sp_runtime::traits::Dispatchable::Config` - --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs + | |_^ the trait `Encode` is not implemented for `frame_system::Call` | - | type Config; - | ^^^^^^^^^^^^ required by this bound in `Dispatchable::Config` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `Encode` is implemented for `frame_system::Call` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:26:3 + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -26 | System: frame_system::{Pallet, Call, Storage, Config, Event}, - | ^^^^^^ the trait `Config` is not implemented for `Runtime` +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime` | -note: required by a bound in `GenesisConfig` +note: required by a bound in `frame_system::Call` --> $WORKSPACE/substrate/frame/system/src/lib.rs | - | pub struct GenesisConfig { - | ^^^^^^ required by this bound in `GenesisConfig` + | #[pallet::call] + | ^^^^ required by this bound in `Call` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Encode` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied +error[E0277]: the trait bound `frame_system::Call: Decode` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -376,10 +447,12 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | |_^ the trait `Decode` is not implemented for `frame_system::Call` | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` + = help: the trait `Decode` is implemented for `frame_system::Call` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -389,15 +462,256 @@ note: required because it appears within the type `RuntimeCall` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `frame_support::pallet_prelude::ValidateUnsigned::Call` - --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: Callable` + | + = help: the trait `Callable` is implemented for `Pallet` + = note: required for `Pallet` to implement `Callable` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::RuntimeDebug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the method `get_dispatch_info` exists for reference `&Call`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ method cannot be called on `&Call` due to unsatisfied trait bounds + | + ::: $WORKSPACE/substrate/frame/system/src/lib.rs + | + | #[pallet::call] + | ---- doesn't satisfy `frame_system::Call: GetDispatchInfo` + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` + which is required by `frame_system::Call: GetDispatchInfo` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the method `is_feeless` exists for reference `&Call`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ method cannot be called on `&Call` due to unsatisfied trait bounds + | + ::: $WORKSPACE/substrate/frame/system/src/lib.rs + | + | #[pallet::call] + | ---- doesn't satisfy `frame_system::Call: CheckIfFeeless` + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` + which is required by `frame_system::Call: CheckIfFeeless` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs | - | type Call; - | ^^^^^^^^^^ required by this bound in `ValidateUnsigned::Call` + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` +error[E0599]: the method `get_call_name` exists for reference `&Call`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ method cannot be called on `&Call` due to unsatisfied trait bounds + | + ::: $WORKSPACE/substrate/frame/system/src/lib.rs + | + | #[pallet::call] + | ---- doesn't satisfy `frame_system::Call: GetCallName` + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` + which is required by `frame_system::Call: GetCallName` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `storage_metadata` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `call_functions` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the variant or associated item `event_metadata` exists for enum `Event`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ variant or associated item cannot be called on `Event` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `pallet_constants_metadata` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `error_metadata` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `pallet_documentation_metadata` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -407,9 +721,21 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEven ... | 27 | | } 28 | | } - | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` - | -note: required because it appears within the type `RuntimeEvent` + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `GenesisConfig: Serialize` + | + = help: the trait `Serialize` is implemented for `GenesisConfig` + = note: required for `GenesisConfig` to implement `Serialize` +note: required by a bound in `frame_support::sp_runtime::serde::ser::SerializeStruct::serialize_field` + --> $CARGO/serde-1.0.210/src/ser/mod.rs + | + | fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + | --------------- required by a bound in this associated function + | where + | T: ?Sized + Serialize; + | ^^^^^^^^^ required by this bound in `SerializeStruct::serialize_field` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -419,15 +745,16 @@ note: required because it appears within the type `RuntimeEvent` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `Result` - --> $RUST/core/src/result.rs + | |_^ the trait `Config` is not implemented for `Runtime` | - | pub enum Result { - | ^ required by this bound in `Result` - = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `GenesisConfig` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub struct GenesisConfig { + | ^^^^^^ required by this bound in `GenesisConfig` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -437,9 +764,16 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEven ... | 27 | | } 28 | | } - | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` + | |_^ the trait `Config` is not implemented for `Runtime` | -note: required because it appears within the type `RuntimeEvent` +note: required by a bound in `GenesisConfig` + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub struct GenesisConfig { + | ^^^^^^ required by this bound in `GenesisConfig` + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::serde::Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -449,13 +783,11 @@ note: required because it appears within the type `RuntimeEvent` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `TryInto` - --> $RUST/core/src/convert/mod.rs + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `GenesisConfig: std::default::Default` | - | pub trait TryInto: Sized { - | ^^^^^ required by this bound in `TryInto` - = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the trait `std::default::Default` is implemented for `GenesisConfig` + = note: required for `GenesisConfig` to implement `std::default::Default` + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 @@ -467,10 +799,24 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied ... | 27 | | } 28 | | } - | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` - | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `(Pallet,): OnGenesis` + | + = help: the following other types implement trait `OnGenesis`: + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) + and $N others + = note: required for `Pallet` to implement `OnGenesis` + = note: 1 redundant requirement hidden + = note: required for `(Pallet,)` to implement `OnGenesis` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0282]: type annotations needed --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | 20 | / construct_runtime! { @@ -480,10 +826,8 @@ note: required because it appears within the type `RuntimeCall` ... | 27 | | } 28 | | } - | |_^ -note: required by a bound in `Result` - --> $RUST/core/src/result.rs + | |_^ cannot infer type | - | pub enum Result { - | ^ required by this bound in `Result` - = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: internal compiler error: compiler/rustc_middle/src/ty/normalize_erasing_regions.rs:168:90: Failed to normalize std::rc::Rc::RuntimeCall,)>), bound_vars: [Region(BrAnon)] }, Binder { value: Projection(Output = bool), bound_vars: [Region(BrAnon)] }] + '{erased}, std::alloc::Global>, std::alloc::Global>, maybe try to call `try_normalize_erasing_regions` instead diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 0f7afb2b9901..c50cba71d4e7 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -28,7 +28,7 @@ error[E0412]: cannot find type `Event` in module `pallet` | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items +help: consider importing one of these enums | 18 + use frame_support_test::Event; | @@ -48,7 +48,7 @@ error[E0433]: failed to resolve: could not find `Event` in `pallet` | |_^ could not find `Event` in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items +help: consider importing one of these enums | 18 + use frame_support_test::Event; | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index 10093b26f5a8..2aa794edc3c9 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -28,7 +28,7 @@ error[E0412]: cannot find type `GenesisConfig` in module `pallet` | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items +help: consider importing one of these structs | 18 + use frame_system::GenesisConfig; | diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index 30005c07cb63..d8dc7bd45bc6 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -54,8 +54,8 @@ error[E0599]: no function or associated item named `is_inherent` found for struc | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `is_inherent`, perhaps you need to implement one of them: - candidate #1: `ProvideInherent` - candidate #2: `IsInherent` + candidate #1: `IsInherent` + candidate #2: `ProvideInherent` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `check_inherent` found for struct `pallet::Pallet` in the current scope diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index d0f4b44ab0d5..58c42311b87b 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -28,7 +28,7 @@ error[E0412]: cannot find type `Origin` in module `pallet` | |_^ not found in `pallet` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items +help: consider importing one of these type aliases | 18 + use frame_support_test::Origin; | diff --git a/substrate/frame/support/test/tests/derive_impl.rs b/substrate/frame/support/test/tests/derive_impl.rs index 675e85f4bfce..3514593c8568 100644 --- a/substrate/frame/support/test/tests/derive_impl.rs +++ b/substrate/frame/support/test/tests/derive_impl.rs @@ -25,15 +25,9 @@ struct SomeRectangle {} #[frame_support::register_default_impl(SomeRectangle)] impl Shape for SomeRectangle { - #[cfg(not(feature = "feature-frame-testing"))] fn area(&self) -> u32 { 10 } - - #[cfg(feature = "feature-frame-testing")] - fn area(&self) -> u32 { - 0 - } } struct SomeSquare {} @@ -44,9 +38,5 @@ impl Shape for SomeSquare {} #[test] fn test_feature_parsing() { let square = SomeSquare {}; - #[cfg(not(feature = "feature-frame-testing"))] assert_eq!(square.area(), 10); - - #[cfg(feature = "feature-frame-testing")] - assert_eq!(square.area(), 0); } diff --git a/substrate/frame/support/test/tests/derive_no_bound.rs b/substrate/frame/support/test/tests/derive_no_bound.rs index b19147078051..6fc4ea12c513 100644 --- a/substrate/frame/support/test/tests/derive_no_bound.rs +++ b/substrate/frame/support/test/tests/derive_no_bound.rs @@ -159,6 +159,7 @@ fn test_struct_unnamed() { PartialOrdNoBound, OrdNoBound, )] +#[allow(dead_code)] struct StructNoGenerics { field1: u32, field2: u64, diff --git a/substrate/frame/support/test/tests/derive_no_bound_ui/ord.stderr b/substrate/frame/support/test/tests/derive_no_bound_ui/ord.stderr index db8a50796077..8bf82bff7809 100644 --- a/substrate/frame/support/test/tests/derive_no_bound_ui/ord.stderr +++ b/substrate/frame/support/test/tests/derive_no_bound_ui/ord.stderr @@ -23,3 +23,13 @@ note: required by a bound in `std::cmp::Eq` | | pub trait Eq: PartialEq { | ^^^^^^^^^^^^^^^ required by this bound in `Eq` + +error[E0599]: `::C` is not an iterator + --> tests/derive_no_bound_ui/ord.rs:24:2 + | +24 | c: T::C, + | ^ `::C` is not an iterator + | + = note: the following trait bounds were not satisfied: + `::C: Iterator` + which is required by `&mut ::C: Iterator` diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 7f1ce0556eab..3d6aa1d83749 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -2431,9 +2431,10 @@ fn post_runtime_upgrade_detects_storage_version_issues() { // any storage version "enabled". assert!( ExecutiveWithUpgradePallet4::try_runtime_upgrade(UpgradeCheckSelect::PreAndPost) - .unwrap_err() == "On chain storage version set, while the pallet \ + .unwrap_err() == + "On chain storage version set, while the pallet \ doesn't have the `#[pallet::storage_version(VERSION)]` attribute." - .into() + .into() ); }); } diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 2a4ceecd8fa4..1f91f7740238 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -33,3 +33,12 @@ error[E0369]: binary operation `==` cannot be applied to type `&, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ + +error: unused variable: `origin` + --> tests/pallet_ui/call_argument_invalid_bound.rs:38:14 + | +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_origin` + | + = note: `-D unused-variables` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_variables)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index fc993e9ff68f..4657c0a0c601 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -34,7 +34,7 @@ error[E0369]: binary operation `==` cannot be applied to type `&, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ -error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is not satisfied +error[E0277]: the trait bound `::Bar: Encode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 | 18 | #[frame_support::pallet] @@ -45,10 +45,19 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is | = note: required for `::Bar` to implement `Encode` -error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied +error[E0277]: the trait bound `::Bar: Decode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:42 | 38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar`, which is required by `::Bar: Decode` | = note: required for `::Bar` to implement `Decode` + +error: unused variable: `origin` + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:14 + | +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_origin` + | + = note: `-D unused-variables` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_variables)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index d6486a490794..f829baeb4c11 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -27,3 +27,12 @@ help: consider annotating `Bar` with `#[derive(Debug)]` 34 + #[derive(Debug)] 35 | struct Bar; | + +error: unused variable: `origin` + --> tests/pallet_ui/call_argument_invalid_bound_3.rs:40:14 + | +40 | pub fn foo(origin: OriginFor, _bar: Bar) -> DispatchResultWithPostInfo { + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_origin` + | + = note: `-D unused-variables` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_variables)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr index 3256e69528a2..8049c07648ca 100644 --- a/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/compare_unset_storage_version.stderr @@ -5,3 +5,9 @@ error[E0369]: binary operation `!=` cannot be applied to type `NoStorageVersionS | ------------------------------- ^^ -------------------------------- StorageVersion | | | NoStorageVersionSet + | +note: the foreign item type `NoStorageVersionSet` doesn't implement `PartialEq` + --> $WORKSPACE/substrate/frame/support/src/traits/metadata.rs + | + | pub struct NoStorageVersionSet; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not implement `PartialEq` diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr index 629fefebbe2c..2fcc33282140 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr @@ -38,13 +38,13 @@ error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied | |__________________^ the trait `MaxEncodedLen` is not implemented for `Vec`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>: StorageInfoTrait` | = help: the following other types implement trait `MaxEncodedLen`: - bool - i8 - i16 - i32 - i64 - i128 - u8 - u16 + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and $N others = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>` to implement `StorageInfoTrait` diff --git a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr index 44d8d3fcadbf..92fb5b9cb38d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr @@ -5,12 +5,12 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied | ^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` | = help: the following other types implement trait `PalletError`: - bool - i8 - i16 - i32 - i64 - i128 - u8 - u16 + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and $N others diff --git a/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr b/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr index b7327943ee20..c04499dbbd14 100644 --- a/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/hooks_invalid_item.stderr @@ -13,3 +13,9 @@ help: add missing generic argument | 29 | impl Hooks for Pallet {} | +++++++++++++ + +error[E0277]: the trait bound `pallet::Pallet: Hooks<<<::Block as frame_support::sp_runtime::traits::Block>::Header as frame_support::sp_runtime::traits::Header>::Number>` is not satisfied + --> tests/pallet_ui/hooks_invalid_item.rs:28:12 + | +28 | #[pallet::hooks] + | ^^^^^ the trait `Hooks<<<::Block as frame_support::sp_runtime::traits::Block>::Header as frame_support::sp_runtime::traits::Header>::Number>` is not implemented for `pallet::Pallet` diff --git a/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr index 5ea3be470a06..516bddd2c61b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/inherent_check_inner_span.stderr @@ -6,6 +6,6 @@ error[E0046]: not all trait items implemented, missing: `Call`, `Error`, `INHERE | = help: implement the missing item: `type Call = /* Type */;` = help: implement the missing item: `type Error = /* Type */;` - = help: implement the missing item: `const INHERENT_IDENTIFIER: [u8; 8] = value;` + = help: implement the missing item: `const INHERENT_IDENTIFIER: [u8; 8] = [42; 8];` = help: implement the missing item: `fn create_inherent(_: &InherentData) -> std::option::Option<::Call> { todo!() }` = help: implement the missing item: `fn is_inherent(_: &::Call) -> bool { todo!() }` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index c8c41e805014..fa6b7284d889 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -12,10 +12,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -34,14 +34,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `EncodeLike`: - - - - - - - - + `&&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&[(K, V)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[T]` implements `EncodeLike>` and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -61,14 +61,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box - bytes::bytes::Bytes Cow<'a, T> - parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc Vec + bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` @@ -84,14 +84,14 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied | |____________^ the trait `TypeInfo` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `TypeInfo`: - bool - char - i8 - i16 - i32 - i64 - i128 - u8 + &T + &mut T + () + (A, B) + (A, B, C) + (A, B, C, D) + (A, B, C, D, E) + (A, B, C, D, E, F) and $N others = note: required for `Bar` to implement `StaticTypeInfo` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -105,10 +105,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -122,14 +122,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `EncodeLike`: - - - - - - - - + `&&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&[(K, V)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[T]` implements `EncodeLike>` and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -144,14 +144,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box - bytes::bytes::Bytes Cow<'a, T> - parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc Vec + bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` @@ -167,10 +167,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` @@ -184,14 +184,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `EncodeLike`: - - - - - - - - + `&&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&[(K, V)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[T]` implements `EncodeLike>` and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -206,14 +206,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box - bytes::bytes::Bytes Cow<'a, T> - parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc Vec + bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 08b35eb8ed15..944b194b7bcf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -12,10 +12,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `PartialStorageInfoTrait` @@ -34,14 +34,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `EncodeLike`: - - - - - - - - + `&&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&[(K, V)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[T]` implements `EncodeLike>` and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -61,14 +61,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box - bytes::bytes::Bytes Cow<'a, T> - parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc Vec + bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` @@ -84,14 +84,14 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied | |____________^ the trait `TypeInfo` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `TypeInfo`: - bool - char - i8 - i16 - i32 - i64 - i128 - u8 + &T + &mut T + () + (A, B) + (A, B, C) + (A, B, C, D) + (A, B, C, D, E) + (A, B, C, D, E, F) and $N others = note: required for `Bar` to implement `StaticTypeInfo` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -105,10 +105,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` @@ -122,14 +122,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `EncodeLike`: - - - - - - - - + `&&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&[(K, V)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[T]` implements `EncodeLike>` and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -144,14 +144,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box - bytes::bytes::Bytes Cow<'a, T> - parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc Vec + bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` @@ -167,10 +167,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc + frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` @@ -184,14 +184,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `EncodeLike`: - - - - - - - - + `&&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&T` implements `EncodeLike` + `&[(K, V)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[(T,)]` implements `EncodeLike>` + `&[T]` implements `EncodeLike>` and $N others = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` @@ -206,14 +206,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box - bytes::bytes::Bytes Cow<'a, T> - parity_scale_codec::Ref<'a, T, U> - frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes Rc - Arc Vec + bytes::bytes::Bytes and $N others = note: required for `Bar` to implement `Encode` = note: required for `Bar` to implement `FullEncode` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 042a6f67fd31..95ec76e29c0b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -12,13 +12,13 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageInfoTrait` | = help: the following other types implement trait `MaxEncodedLen`: - bool - i8 - i16 - i32 - i64 - i128 - u8 - u16 + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and $N others = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageInfoTrait` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 9f57b85f3a8a..8351dd92d594 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -12,14 +12,14 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>: StorageInfoTrait` | = help: the following other types implement trait `MaxEncodedLen`: - bool - i8 - i16 - i32 - i64 - i128 - u8 - u16 + () + (TupleElement0, TupleElement1) + (TupleElement0, TupleElement1, TupleElement2) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) + (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) and $N others = note: required for `NMapKey` to implement `KeyGeneratorMaxEncodedLen` = note: required for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` to implement `StorageInfoTrait` diff --git a/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr b/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr index 41dcd273d962..0b13dcff90c6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/type_value_error_in_block.stderr @@ -3,3 +3,9 @@ error[E0599]: no function or associated item named `new` found for type `u32` in | 37 | u32::new() | ^^^ function or associated item not found in `u32` + | +help: there is a method `ne` with a similar name, but with different arguments + --> $RUST/core/src/cmp.rs + | + | fn ne(&self, other: &Rhs) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs index 534ba1e863fc..aa1094e3fe48 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -848,6 +848,7 @@ pub fn from_post_weight_info(ref_time: Option, pays_fee: Pays) -> PostDispa #[docify::export] #[test] fn last_runtime_upgrade_spec_version_usage() { + #[allow(dead_code)] struct Migration; impl OnRuntimeUpgrade for Migration { diff --git a/substrate/frame/transaction-payment/src/tests.rs b/substrate/frame/transaction-payment/src/tests.rs index 35d5322a6f33..bac89967d6af 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -273,8 +273,10 @@ fn signed_ext_length_fee_is_also_updated_per_congestion() { NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); let len = 10; - assert_ok!(ChargeTransactionPayment::::from(10) // tipped - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(3, 0)), len)); + assert_ok!( + ChargeTransactionPayment::::from(10) // tipped + .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(3, 0)), len) + ); assert_eq!( Balances::free_balance(1), 100 // original diff --git a/substrate/frame/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs index ed5544fe55ca..a4f66298f3fa 100644 --- a/substrate/frame/utility/src/lib.rs +++ b/substrate/frame/utility/src/lib.rs @@ -134,8 +134,8 @@ pub mod pallet { fn batched_calls_limit() -> u32 { let allocator_limit = sp_core::MAX_POSSIBLE_ALLOCATION; let call_size = ((core::mem::size_of::<::RuntimeCall>() as u32 + - CALL_ALIGN - 1) / CALL_ALIGN) * - CALL_ALIGN; + CALL_ALIGN - 1) / + CALL_ALIGN) * CALL_ALIGN; // The margin to take into account vec doubling capacity. let margin_factor = 3; diff --git a/substrate/frame/vesting/src/tests.rs b/substrate/frame/vesting/src/tests.rs index 004da0dfbfa1..57cb59f27a4d 100644 --- a/substrate/frame/vesting/src/tests.rs +++ b/substrate/frame/vesting/src/tests.rs @@ -182,7 +182,7 @@ fn unvested_balance_should_not_transfer() { ExtBuilder::default().existential_deposit(10).build().execute_with(|| { let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); // Account 1 cannot send more than vested amount... assert_noop!(Balances::transfer_allow_death(Some(1).into(), 2, 56), TokenError::Frozen); @@ -194,7 +194,7 @@ fn vested_balance_should_transfer() { ExtBuilder::default().existential_deposit(10).build().execute_with(|| { let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); assert_ok!(Vesting::vest(Some(1).into())); assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 55)); @@ -232,7 +232,7 @@ fn vested_balance_should_transfer_using_vest_other() { ExtBuilder::default().existential_deposit(10).build().execute_with(|| { let user1_free_balance = Balances::free_balance(&1); assert_eq!(user1_free_balance, 100); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); assert_ok!(Vesting::vest_other(Some(2).into(), 1)); assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 55)); @@ -286,7 +286,7 @@ fn extra_balance_should_transfer() { assert_eq!(Vesting::vesting_balance(&2), Some(200)); assert_ok!(Vesting::vest(Some(2).into())); assert_ok!(Balances::transfer_allow_death(Some(2).into(), 3, 100)); // Account 2 can send extra - // units gained + // units gained }); } @@ -296,7 +296,7 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { let user12_free_balance = Balances::free_balance(&12); assert_eq!(user12_free_balance, 2560); // Account 12 has free balance - // Account 12 has liquid funds + // Account 12 has liquid funds assert_eq!(Vesting::vesting_balance(&12), Some(user12_free_balance - 256 * 5)); // Account 12 has delayed vesting diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 21397abc8fc6..de922e3253e4 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -18,7 +18,7 @@ use crate::{ common::API_VERSION_ATTRIBUTE, utils::{ - extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait, + extract_block_type_from_trait_path, extract_impl_trait, extract_parameter_names_types_and_borrows, generate_crate_access, generate_runtime_mod_name_for_trait, parse_runtime_api_version, prefix_function_with_trait, versioned_trait_name, AllowSelfRefInParameters, RequireQualifiedTraitPath, @@ -632,11 +632,6 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { } fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl { - // All this `UnwindSafe` magic below here is required for this rust bug: - // https://github.com/rust-lang/rust/issues/24159 - // Before we directly had the final block type and rust could determine that it is unwind - // safe, but now we just have a generic parameter `Block`. - let crate_ = generate_crate_access(); // Implement the trait for the `RuntimeApiImpl` @@ -644,9 +639,9 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { Box::new(parse_quote!( RuntimeApiImpl<__SrApiBlock__, RuntimeApiImplCall> )); input.generics.params.push(parse_quote!( - __SrApiBlock__: #crate_::BlockT + std::panic::UnwindSafe + - std::panic::RefUnwindSafe + __SrApiBlock__: #crate_::BlockT )); + input .generics .params @@ -661,17 +656,6 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send }); - // Require that all types used in the function signatures are unwind safe. - extract_all_signature_types(&input.items).iter().for_each(|i| { - where_clause.predicates.push(parse_quote! { - #i: std::panic::UnwindSafe + std::panic::RefUnwindSafe - }); - }); - - where_clause.predicates.push(parse_quote! { - __SrApiBlock__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe - }); - input.attrs = filter_cfg_attrs(&input.attrs); fold::fold_item_impl(self, input) diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index 94da6748cbdb..dc993c2ac420 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -22,8 +22,8 @@ use proc_macro_crate::{crate_name, FoundCrate}; use quote::{format_ident, quote}; use syn::{ parse_quote, punctuated::Punctuated, spanned::Spanned, token::And, Attribute, Error, Expr, - ExprLit, FnArg, GenericArgument, Ident, ImplItem, ItemImpl, Lit, Meta, MetaNameValue, Pat, - Path, PathArguments, Result, ReturnType, Signature, Token, Type, TypePath, + ExprLit, FnArg, GenericArgument, Ident, ItemImpl, Lit, Meta, MetaNameValue, Pat, Path, + PathArguments, Result, ReturnType, Signature, Token, Type, TypePath, }; /// Generates the access to the `sc_client` crate. @@ -159,37 +159,6 @@ pub fn prefix_function_with_trait(trait_: &Ident, function: &F) -> format!("{}_{}", trait_, function.to_string()) } -/// Extract all types that appear in signatures in the given `ImplItem`'s. -/// -/// If a type is a reference, the inner type is extracted (without the reference). -pub fn extract_all_signature_types(items: &[ImplItem]) -> Vec { - items - .iter() - .filter_map(|i| match i { - ImplItem::Fn(method) => Some(&method.sig), - _ => None, - }) - .flat_map(|sig| { - let ret_ty = match &sig.output { - ReturnType::Default => None, - ReturnType::Type(_, ty) => Some((**ty).clone()), - }; - - sig.inputs - .iter() - .filter_map(|i| match i { - FnArg::Typed(arg) => Some(&arg.ty), - _ => None, - }) - .map(|ty| match &**ty { - Type::Reference(t) => (*t.elem).clone(), - _ => (**ty).clone(), - }) - .chain(ret_ty) - }) - .collect() -} - /// Extracts the block type from a trait path. /// /// It is expected that the block type is the first type in the generic arguments. diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 121ce6b99938..1d21f23eb804 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -41,3 +41,4 @@ harness = false [features] "enable-staging-api" = [] +disable-ui-tests = [] diff --git a/substrate/primitives/api/test/tests/trybuild.rs b/substrate/primitives/api/test/tests/trybuild.rs index b0a334eb7a22..b13e5df9d6f8 100644 --- a/substrate/primitives/api/test/tests/trybuild.rs +++ b/substrate/primitives/api/test/tests/trybuild.rs @@ -15,18 +15,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::env; - #[rustversion::attr(not(stable), ignore)] +#[cfg(not(feature = "disable-ui-tests"))] #[test] fn ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. - if env::var("RUN_UI_TESTS").is_err() { + if std::env::var("RUN_UI_TESTS").is_err() { return } // As trybuild is using `cargo check`, we don't need the real WASM binaries. - env::set_var("SKIP_WASM_BUILD", "1"); + std::env::set_var("SKIP_WASM_BUILD", "1"); + + // Warnings are part of our UI. + std::env::set_var("RUSTFLAGS", "--deny warnings"); let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); diff --git a/substrate/primitives/api/test/tests/ui/deprecation_info.stderr b/substrate/primitives/api/test/tests/ui/deprecation_info.stderr index 2466c3ea5d50..78c687e876de 100644 --- a/substrate/primitives/api/test/tests/ui/deprecation_info.stderr +++ b/substrate/primitives/api/test/tests/ui/deprecation_info.stderr @@ -12,6 +12,21 @@ error: Invalid deprecation attribute: missing `note` 20 | #[deprecated(unknown_kw = "test")] | ^ +error: malformed `deprecated` attribute input + --> tests/ui/deprecation_info.rs:24:3 + | +24 | #[deprecated = 5] + | ^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +24 | #[deprecated = "reason"] + | +24 | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +24 | #[deprecated] + | + error[E0541]: unknown meta item 'unknown_kw' --> tests/ui/deprecation_info.rs:20:16 | diff --git a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 535bbb178d5f..d625020fe4d3 100644 --- a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -22,10 +22,7 @@ error[E0053]: method `test` has an incompatible type for trait --> tests/ui/impl_incorrect_method_signature.rs:33:17 | 33 | fn test(data: String) {} - | ^^^^^^ - | | - | expected `u64`, found `std::string::String` - | help: change the parameter type to match the trait: `u64` + | ^^^^^^ expected `u64`, found `std::string::String` | note: type in trait --> tests/ui/impl_incorrect_method_signature.rs:27:17 @@ -34,6 +31,10 @@ note: type in trait | ^^^ = note: expected signature `fn(u64)` found signature `fn(std::string::String)` +help: change the parameter type to match the trait + | +33 | fn test(data: u64) {} + | ~~~ error[E0308]: mismatched types --> tests/ui/impl_incorrect_method_signature.rs:33:11 @@ -53,3 +54,12 @@ note: associated function defined here | 27 | fn test(data: u64); | ^^^^ + +error: unused variable: `data` + --> tests/ui/impl_incorrect_method_signature.rs:33:11 + | +33 | fn test(data: String) {} + | ^^^^ help: if this is intentional, prefix it with an underscore: `_data` + | + = note: `-D unused-variables` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_variables)]` diff --git a/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr b/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr index 845755771877..764a0bafaa4f 100644 --- a/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr +++ b/substrate/primitives/api/test/tests/ui/mock_only_self_reference.stderr @@ -21,8 +21,7 @@ error[E0050]: method `test` has 2 parameters but the declaration in trait `Api:: 29 | / sp_api::mock_impl_runtime_apis! { 30 | | impl Api for MockApi { 31 | | fn test(self, data: u64) {} -32 | | -33 | | fn test2(&mut self, data: u64) {} +... | 34 | | } 35 | | } | |_^ expected 3 parameters, found 2 @@ -41,8 +40,7 @@ error[E0050]: method `test2` has 2 parameters but the declaration in trait `Api: 29 | / sp_api::mock_impl_runtime_apis! { 30 | | impl Api for MockApi { 31 | | fn test(self, data: u64) {} -32 | | -33 | | fn test2(&mut self, data: u64) {} +... | 34 | | } 35 | | } | |_^ expected 3 parameters, found 2 diff --git a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index f4e0f3b0afb0..26be311c02fa 100644 --- a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -22,10 +22,7 @@ error[E0053]: method `test` has an incompatible type for trait --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:17 | 33 | fn test(data: &u64) { - | ^^^^ - | | - | expected `u64`, found `&u64` - | help: change the parameter type to match the trait: `u64` + | ^^^^ expected `u64`, found `&u64` | note: type in trait --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:27:17 @@ -34,6 +31,10 @@ note: type in trait | ^^^ = note: expected signature `fn(_)` found signature `fn(&_)` +help: change the parameter type to match the trait + | +33 | fn test(data: u64) { + | ~~~ error[E0308]: mismatched types --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:11 @@ -57,3 +58,12 @@ help: consider removing the borrow | 33 | fn test(data: &u64) { | + +error: unused variable: `data` + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:11 + | +33 | fn test(data: &u64) { + | ^^^^ help: if this is intentional, prefix it with an underscore: `_data` + | + = note: `-D unused-variables` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_variables)]` diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 57ddab9a70ce..13d80683c853 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -28,7 +28,6 @@ sp-runtime = { workspace = true } sp-keystore = { workspace = true } sp-weights = { workspace = true } strum = { features = ["derive"], workspace = true } -lazy_static = { optional = true, workspace = true } [dev-dependencies] array-bytes = { workspace = true, default-features = true } @@ -38,7 +37,6 @@ w3f-bls = { features = ["std"], workspace = true, default-features = true } default = ["std"] std = [ "codec/std", - "dep:lazy_static", "scale-info/std", "serde/std", "sp-api/std", diff --git a/substrate/primitives/consensus/beefy/src/payload.rs b/substrate/primitives/consensus/beefy/src/payload.rs index d22255c384bc..9e792670fef5 100644 --- a/substrate/primitives/consensus/beefy/src/payload.rs +++ b/substrate/primitives/consensus/beefy/src/payload.rs @@ -56,6 +56,16 @@ impl Payload { Some(&self.0[index].1) } + /// Returns all the raw payloads under given `id`. + pub fn get_all_raw<'a>( + &'a self, + id: &'a BeefyPayloadId, + ) -> impl Iterator> + 'a { + self.0 + .iter() + .filter_map(move |probe| if &probe.0 != id { return None } else { Some(&probe.1) }) + } + /// Returns a decoded payload value under given `id`. /// /// In case the value is not there, or it cannot be decoded `None` is returned. @@ -63,6 +73,14 @@ impl Payload { self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) } + /// Returns all decoded payload values under given `id`. + pub fn get_all_decoded<'a, T: Decode>( + &'a self, + id: &'a BeefyPayloadId, + ) -> impl Iterator> + 'a { + self.get_all_raw(id).map(|raw| T::decode(&mut &raw[..]).ok()) + } + /// Push a `Vec` with a given id into the payload vec. /// This method will internally sort the payload vec after every push. /// diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index bd335ede4893..4460bcefd45f 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -26,7 +26,7 @@ use sp_core::{ecdsa, Pair}; use sp_runtime::traits::{BlockNumber, Hash, Header as HeaderT}; use codec::Encode; -use std::{collections::HashMap, marker::PhantomData}; +use std::{collections::HashMap, marker::PhantomData, sync::LazyLock}; use strum::IntoEnumIterator; /// Set of test accounts using [`crate::ecdsa_crypto`] types. @@ -111,12 +111,15 @@ where } } -lazy_static::lazy_static! { - static ref PRIVATE_KEYS: HashMap, ecdsa_crypto::Pair> = - Keyring::iter().map(|i| (i.clone(), i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap, ecdsa_crypto::Public> = - PRIVATE_KEYS.iter().map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))).collect(); -} +static PRIVATE_KEYS: LazyLock, ecdsa_crypto::Pair>> = + LazyLock::new(|| Keyring::iter().map(|i| (i.clone(), i.pair())).collect()); +static PUBLIC_KEYS: LazyLock, ecdsa_crypto::Public>> = + LazyLock::new(|| { + PRIVATE_KEYS + .iter() + .map(|(name, pair)| (name.clone(), sp_application_crypto::Pair::public(pair))) + .collect() + }); impl From> for ecdsa_crypto::Pair { fn from(k: Keyring) -> Self { diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 51cbfa3bdfbe..f6bc17bccaca 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -26,10 +26,14 @@ impl-serde = { optional = true, workspace = true } hash-db = { workspace = true } hash256-std-hasher = { workspace = true } bs58 = { optional = true, workspace = true } -rand = { features = ["small_rng"], optional = true, workspace = true, default-features = true } +rand = { features = [ + "small_rng", +], optional = true, workspace = true, default-features = true } substrate-bip39 = { workspace = true } # personal fork here as workaround for: https://github.com/rust-bitcoin/rust-bip39/pull/64 -bip39 = { package = "parity-bip39", version = "2.0.1", default-features = false, features = ["alloc"] } +bip39 = { package = "parity-bip39", version = "2.0.1", default-features = false, features = [ + "alloc", +] } zeroize = { workspace = true } secrecy = { features = ["alloc"], workspace = true } parking_lot = { optional = true, workspace = true, default-features = true } @@ -58,17 +62,21 @@ sp-runtime-interface = { workspace = true } # k256 crate, better portability, intended to be used in substrate-runtimes (no-std) k256 = { features = ["alloc", "ecdsa"], workspace = true } # secp256k1 crate, better performance, intended to be used on host side (std) -secp256k1 = { features = ["alloc", "recovery"], optional = true, workspace = true } +secp256k1 = { features = [ + "alloc", + "recovery", +], optional = true, workspace = true } # bls crypto w3f-bls = { optional = true, workspace = true } # bandersnatch crypto -bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "0fef826", default-features = false, features = ["substrate-curves"], optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "0fef826", default-features = false, features = [ + "substrate-curves", +], optional = true } [dev-dependencies] criterion = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -lazy_static = { workspace = true } regex = { workspace = true } [[bench]] diff --git a/substrate/primitives/core/fuzz/Cargo.toml b/substrate/primitives/core/fuzz/Cargo.toml index 46dfe8d483b7..b6ef395adf9a 100644 --- a/substrate/primitives/core/fuzz/Cargo.toml +++ b/substrate/primitives/core/fuzz/Cargo.toml @@ -11,7 +11,6 @@ workspace = true cargo-fuzz = true [dependencies] -lazy_static = { workspace = true } libfuzzer-sys = { workspace = true } regex = { workspace = true } diff --git a/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs b/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs index e2d9e2fc8b08..ac84faf2d898 100644 --- a/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs +++ b/substrate/primitives/core/fuzz/fuzz_targets/fuzz_address_uri.rs @@ -24,11 +24,12 @@ extern crate sp_core; use libfuzzer_sys::fuzz_target; use regex::Regex; use sp_core::crypto::AddressUri; +use std::sync::LazyLock; -lazy_static::lazy_static! { - static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") - .expect("constructed from known-good static value; qed"); -} +static SECRET_PHRASE_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") + .expect("constructed from known-good static value; qed") +}); fuzz_target!(|input: &str| { let regex_result = SECRET_PHRASE_REGEX.captures(input); diff --git a/substrate/primitives/core/src/address_uri.rs b/substrate/primitives/core/src/address_uri.rs index bbe31b7553bd..4877250cf3ac 100644 --- a/substrate/primitives/core/src/address_uri.rs +++ b/substrate/primitives/core/src/address_uri.rs @@ -196,11 +196,12 @@ impl<'a> AddressUri<'a> { mod tests { use super::*; use regex::Regex; + use std::sync::LazyLock; - lazy_static::lazy_static! { - static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") - .expect("constructed from known-good static value; qed"); - } + static SECRET_PHRASE_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"^(?P[a-zA-Z0-9 ]+)?(?P(//?[^/]+)*)(///(?P.*))?$") + .expect("constructed from known-good static value; qed") + }); fn check_with_regex(input: &str) { let regex_result = SECRET_PHRASE_REGEX.captures(input); diff --git a/substrate/primitives/panic-handler/Cargo.toml b/substrate/primitives/panic-handler/Cargo.toml index 395e788eb244..012fe08f7cd5 100644 --- a/substrate/primitives/panic-handler/Cargo.toml +++ b/substrate/primitives/panic-handler/Cargo.toml @@ -18,5 +18,4 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] backtrace = { workspace = true } -lazy_static = { workspace = true } regex = { workspace = true } diff --git a/substrate/primitives/panic-handler/src/lib.rs b/substrate/primitives/panic-handler/src/lib.rs index e2a9bfa195a6..c4a7eb8dc67c 100644 --- a/substrate/primitives/panic-handler/src/lib.rs +++ b/substrate/primitives/panic-handler/src/lib.rs @@ -31,6 +31,7 @@ use std::{ io::{self, Write}, marker::PhantomData, panic::{self, PanicInfo}, + sync::LazyLock, thread, }; @@ -128,8 +129,9 @@ impl Drop for AbortGuard { // NOTE: When making any changes here make sure to also change this function in `sc-tracing`. fn strip_control_codes(input: &str) -> std::borrow::Cow { - lazy_static::lazy_static! { - static ref RE: Regex = Regex::new(r#"(?x) + static RE: LazyLock = LazyLock::new(|| { + Regex::new( + r#"(?x) \x1b\[[^m]+m| # VT100 escape codes [ \x00-\x09\x0B-\x1F # ASCII control codes / Unicode C0 control codes, except \n @@ -138,8 +140,10 @@ fn strip_control_codes(input: &str) -> std::borrow::Cow { \u{202A}-\u{202E} # Unicode left-to-right / right-to-left control characters \u{2066}-\u{2069} # Same as above ] - "#).expect("regex parsing doesn't fail; qed"); - } + "#, + ) + .expect("regex parsing doesn't fail; qed") + }); RE.replace_all(input, "") } diff --git a/substrate/primitives/runtime-interface/tests/ui.rs b/substrate/primitives/runtime-interface/tests/ui.rs index 821d0b73f268..408ddbc981ee 100644 --- a/substrate/primitives/runtime-interface/tests/ui.rs +++ b/substrate/primitives/runtime-interface/tests/ui.rs @@ -15,18 +15,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::env; - #[rustversion::attr(not(stable), ignore)] #[test] fn ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. - if env::var("RUN_UI_TESTS").is_err() { + if std::env::var("RUN_UI_TESTS").is_err() { return } // As trybuild is using `cargo check`, we don't need the real WASM binaries. - env::set_var("SKIP_WASM_BUILD", "1"); + std::env::set_var("SKIP_WASM_BUILD", "1"); let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); diff --git a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr index 10012ede793d..1c1649d011e6 100644 --- a/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr +++ b/substrate/primitives/runtime-interface/tests/ui/no_feature_gated_method.stderr @@ -9,9 +9,41 @@ note: found an item that was configured out | 25 | fn bar() {} | ^^^ - = note: the item is gated behind the `bar-feature` feature +note: the item is gated behind the `bar-feature` feature + --> tests/ui/no_feature_gated_method.rs:24:8 + | +24 | #[cfg(feature = "bar-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^ note: found an item that was configured out --> tests/ui/no_feature_gated_method.rs:25:5 | 25 | fn bar() {} | ^^^ +note: the item is gated here + --> tests/ui/no_feature_gated_method.rs:20:1 + | +20 | #[runtime_interface] + | ^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the attribute macro `runtime_interface` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unexpected `cfg` condition value: `bar-feature` + --> tests/ui/no_feature_gated_method.rs:24:8 + | +24 | #[cfg(feature = "bar-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `default`, `disable_target_static_assertions`, and `std` + = help: consider adding `bar-feature` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + = note: `-D unexpected-cfgs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unexpected_cfgs)]` + +error: unexpected `cfg` condition value: `bar-feature` + --> tests/ui/no_feature_gated_method.rs:27:12 + | +27 | #[cfg(not(feature = "bar-feature"))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `default`, `disable_target_static_assertions`, and `std` + = help: consider adding `bar-feature` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 800bf4bd0737..c3413775b1cc 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -36,6 +36,7 @@ sp-trie = { workspace = true } sp-weights = { workspace = true } docify = { workspace = true } tracing = { workspace = true, features = ["log"], default-features = false } +binary-merkle-tree = { workspace = true } simple-mermaid = { version = "0.1.1", optional = true } @@ -53,6 +54,7 @@ runtime-benchmarks = [] try-runtime = [] default = ["std"] std = [ + "binary-merkle-tree/std", "codec/std", "either/use_std", "hash256-std-hasher/std", diff --git a/substrate/primitives/runtime/src/proving_trie.rs b/substrate/primitives/runtime/src/proving_trie.rs deleted file mode 100644 index 9a423f18284f..000000000000 --- a/substrate/primitives/runtime/src/proving_trie.rs +++ /dev/null @@ -1,391 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Types for a compact base-16 merkle trie used for checking and generating proofs within the -//! runtime. The `sp-trie` crate exposes all of these same functionality (and more), but this -//! library is designed to work more easily with runtime native types, which simply need to -//! implement `Encode`/`Decode`. It also exposes a runtime friendly `TrieError` type which can be -//! use inside of a FRAME Pallet. -//! -//! Proofs are created with latest substrate trie format (`LayoutV1`), and are not compatible with -//! proofs using `LayoutV0`. - -use crate::{Decode, DispatchError, Encode, MaxEncodedLen, TypeInfo}; -#[cfg(feature = "serde")] -use crate::{Deserialize, Serialize}; - -use sp_std::vec::Vec; -use sp_trie::{ - trie_types::{TrieDBBuilder, TrieDBMutBuilderV1, TrieError as SpTrieError}, - LayoutV1, MemoryDB, Trie, TrieMut, VerifyError, -}; - -type HashOf = ::Out; - -/// A runtime friendly error type for tries. -#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum TrieError { - /* From TrieError */ - /// Attempted to create a trie with a state root not in the DB. - InvalidStateRoot, - /// Trie item not found in the database, - IncompleteDatabase, - /// A value was found in the trie with a nibble key that was not byte-aligned. - ValueAtIncompleteKey, - /// Corrupt Trie item. - DecoderError, - /// Hash is not value. - InvalidHash, - /* From VerifyError */ - /// The statement being verified contains multiple key-value pairs with the same key. - DuplicateKey, - /// The proof contains at least one extraneous node. - ExtraneousNode, - /// The proof contains at least one extraneous value which should have been omitted from the - /// proof. - ExtraneousValue, - /// The proof contains at least one extraneous hash reference the should have been omitted. - ExtraneousHashReference, - /// The proof contains an invalid child reference that exceeds the hash length. - InvalidChildReference, - /// The proof indicates that an expected value was not found in the trie. - ValueMismatch, - /// The proof is missing trie nodes required to verify. - IncompleteProof, - /// The root hash computed from the proof is incorrect. - RootMismatch, - /// One of the proof nodes could not be decoded. - DecodeError, -} - -impl From> for TrieError { - fn from(error: SpTrieError) -> Self { - match error { - SpTrieError::InvalidStateRoot(..) => Self::InvalidStateRoot, - SpTrieError::IncompleteDatabase(..) => Self::IncompleteDatabase, - SpTrieError::ValueAtIncompleteKey(..) => Self::ValueAtIncompleteKey, - SpTrieError::DecoderError(..) => Self::DecoderError, - SpTrieError::InvalidHash(..) => Self::InvalidHash, - } - } -} - -impl From> for TrieError { - fn from(error: VerifyError) -> Self { - match error { - VerifyError::DuplicateKey(..) => Self::DuplicateKey, - VerifyError::ExtraneousNode => Self::ExtraneousNode, - VerifyError::ExtraneousValue(..) => Self::ExtraneousValue, - VerifyError::ExtraneousHashReference(..) => Self::ExtraneousHashReference, - VerifyError::InvalidChildReference(..) => Self::InvalidChildReference, - VerifyError::ValueMismatch(..) => Self::ValueMismatch, - VerifyError::IncompleteProof => Self::IncompleteProof, - VerifyError::RootMismatch(..) => Self::RootMismatch, - VerifyError::DecodeError(..) => Self::DecodeError, - } - } -} - -impl From for &'static str { - fn from(e: TrieError) -> &'static str { - match e { - TrieError::InvalidStateRoot => "The state root is not in the database.", - TrieError::IncompleteDatabase => "A trie item was not found in the database.", - TrieError::ValueAtIncompleteKey => - "A value was found with a key that is not byte-aligned.", - TrieError::DecoderError => "A corrupt trie item was encountered.", - TrieError::InvalidHash => "The hash does not match the expected value.", - TrieError::DuplicateKey => "The proof contains duplicate keys.", - TrieError::ExtraneousNode => "The proof contains extraneous nodes.", - TrieError::ExtraneousValue => "The proof contains extraneous values.", - TrieError::ExtraneousHashReference => "The proof contains extraneous hash references.", - TrieError::InvalidChildReference => "The proof contains an invalid child reference.", - TrieError::ValueMismatch => "The proof indicates a value mismatch.", - TrieError::IncompleteProof => "The proof is incomplete.", - TrieError::RootMismatch => "The root hash computed from the proof is incorrect.", - TrieError::DecodeError => "One of the proof nodes could not be decoded.", - } - } -} - -/// A helper structure for building a basic base-16 merkle trie and creating compact proofs for that -/// trie. Proofs are created with latest substrate trie format (`LayoutV1`), and are not compatible -/// with proofs using `LayoutV0`. -pub struct BasicProvingTrie -where - Hashing: sp_core::Hasher, -{ - db: MemoryDB, - root: HashOf, - _phantom: core::marker::PhantomData<(Key, Value)>, -} - -impl BasicProvingTrie -where - Hashing: sp_core::Hasher, - Key: Encode, - Value: Encode, -{ - /// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs. - pub fn generate_for(items: I) -> Result - where - I: IntoIterator, - { - let mut db = MemoryDB::default(); - let mut root = Default::default(); - - { - let mut trie = TrieDBMutBuilderV1::new(&mut db, &mut root).build(); - for (key, value) in items.into_iter() { - key.using_encoded(|k| value.using_encoded(|v| trie.insert(k, v))) - .map_err(|_| "failed to insert into trie")?; - } - } - - Ok(Self { db, root, _phantom: Default::default() }) - } - - /// Access the underlying trie root. - pub fn root(&self) -> &HashOf { - &self.root - } - - /// Query a value contained within the current trie. Returns `None` if the - /// nodes within the current `MemoryDB` are insufficient to query the item. - pub fn query(&self, key: Key) -> Option - where - Value: Decode, - { - let trie = TrieDBBuilder::new(&self.db, &self.root).build(); - key.using_encoded(|s| trie.get(s)) - .ok()? - .and_then(|raw| Value::decode(&mut &*raw).ok()) - } - - /// Create a compact merkle proof needed to prove all `keys` and their values are in the trie. - /// Returns `None` if the nodes within the current `MemoryDB` are insufficient to create a - /// proof. - /// - /// This function makes a proof with latest substrate trie format (`LayoutV1`), and is not - /// compatible with `LayoutV0`. - /// - /// When verifying the proof created by this function, you must include all of the keys and - /// values of the proof, else the verifier will complain that extra nodes are provided in the - /// proof that are not needed. - pub fn create_proof(&self, keys: &[Key]) -> Result>, DispatchError> { - sp_trie::generate_trie_proof::, _, _, _>( - &self.db, - self.root, - &keys.into_iter().map(|k| k.encode()).collect::>>(), - ) - .map_err(|err| TrieError::from(*err).into()) - } - - /// Create a compact merkle proof needed to prove a single key and its value are in the trie. - /// Returns `None` if the nodes within the current `MemoryDB` are insufficient to create a - /// proof. - /// - /// This function makes a proof with latest substrate trie format (`LayoutV1`), and is not - /// compatible with `LayoutV0`. - pub fn create_single_value_proof(&self, key: Key) -> Result>, DispatchError> { - self.create_proof(&[key]) - } -} - -/// Verify the existence or non-existence of `key` and `value` in a given trie root and proof. -/// -/// Proofs must be created with latest substrate trie format (`LayoutV1`). -pub fn verify_single_value_proof( - root: HashOf, - proof: &[Vec], - key: Key, - maybe_value: Option, -) -> Result<(), DispatchError> -where - Hashing: sp_core::Hasher, - Key: Encode, - Value: Encode, -{ - sp_trie::verify_trie_proof::, _, _, _>( - &root, - proof, - &[(key.encode(), maybe_value.map(|value| value.encode()))], - ) - .map_err(|err| TrieError::from(err).into()) -} - -/// Verify the existence or non-existence of multiple `items` in a given trie root and proof. -/// -/// Proofs must be created with latest substrate trie format (`LayoutV1`). -pub fn verify_proof( - root: HashOf, - proof: &[Vec], - items: &[(Key, Option)], -) -> Result<(), DispatchError> -where - Hashing: sp_core::Hasher, - Key: Encode, - Value: Encode, -{ - let items_encoded = items - .into_iter() - .map(|(key, maybe_value)| (key.encode(), maybe_value.as_ref().map(|value| value.encode()))) - .collect::, Option>)>>(); - - sp_trie::verify_trie_proof::, _, _, _>(&root, proof, &items_encoded) - .map_err(|err| TrieError::from(err).into()) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::traits::BlakeTwo256; - use sp_core::H256; - use sp_std::collections::btree_map::BTreeMap; - - // A trie which simulates a trie of accounts (u32) and balances (u128). - type BalanceTrie = BasicProvingTrie; - - // The expected root hash for an empty trie. - fn empty_root() -> H256 { - sp_trie::empty_trie_root::>() - } - - fn create_balance_trie() -> BalanceTrie { - // Create a map of users and their balances. - let mut map = BTreeMap::::new(); - for i in 0..100u32 { - map.insert(i, i.into()); - } - - // Put items into the trie. - let balance_trie = BalanceTrie::generate_for(map).unwrap(); - - // Root is changed. - let root = *balance_trie.root(); - assert!(root != empty_root()); - - // Assert valid keys are queryable. - assert_eq!(balance_trie.query(6u32), Some(6u128)); - assert_eq!(balance_trie.query(9u32), Some(9u128)); - assert_eq!(balance_trie.query(69u32), Some(69u128)); - // Invalid key returns none. - assert_eq!(balance_trie.query(6969u32), None); - - balance_trie - } - - #[test] - fn empty_trie_works() { - let empty_trie = BalanceTrie::generate_for(Vec::new()).unwrap(); - assert_eq!(*empty_trie.root(), empty_root()); - } - - #[test] - fn basic_end_to_end_single_value() { - let balance_trie = create_balance_trie(); - let root = *balance_trie.root(); - - // Create a proof for a valid key. - let proof = balance_trie.create_single_value_proof(6u32).unwrap(); - - // Assert key is provable, all other keys are invalid. - for i in 0..200u32 { - if i == 6 { - assert_eq!( - verify_single_value_proof::( - root, - &proof, - i, - Some(u128::from(i)) - ), - Ok(()) - ); - // Wrong value is invalid. - assert_eq!( - verify_single_value_proof::( - root, - &proof, - i, - Some(u128::from(i + 1)) - ), - Err(TrieError::RootMismatch.into()) - ); - } else { - assert!(verify_single_value_proof::( - root, - &proof, - i, - Some(u128::from(i)) - ) - .is_err()); - assert!(verify_single_value_proof::( - root, - &proof, - i, - None:: - ) - .is_err()); - } - } - } - - #[test] - fn basic_end_to_end_multi_value() { - let balance_trie = create_balance_trie(); - let root = *balance_trie.root(); - - // Create a proof for a valid and invalid key. - let proof = balance_trie.create_proof(&[6u32, 69u32, 6969u32]).unwrap(); - let items = [(6u32, Some(6u128)), (69u32, Some(69u128)), (6969u32, None)]; - - assert_eq!(verify_proof::(root, &proof, &items), Ok(())); - } - - #[test] - fn proof_fails_with_bad_data() { - let balance_trie = create_balance_trie(); - let root = *balance_trie.root(); - - // Create a proof for a valid key. - let proof = balance_trie.create_single_value_proof(6u32).unwrap(); - - // Correct data verifies successfully - assert_eq!( - verify_single_value_proof::(root, &proof, 6u32, Some(6u128)), - Ok(()) - ); - - // Fail to verify proof with wrong root - assert_eq!( - verify_single_value_proof::( - Default::default(), - &proof, - 6u32, - Some(6u128) - ), - Err(TrieError::RootMismatch.into()) - ); - - // Fail to verify proof with wrong data - assert_eq!( - verify_single_value_proof::(root, &[], 6u32, Some(6u128)), - Err(TrieError::IncompleteProof.into()) - ); - } -} diff --git a/substrate/primitives/runtime/src/proving_trie/base16.rs b/substrate/primitives/runtime/src/proving_trie/base16.rs new file mode 100644 index 000000000000..da05c551c6d9 --- /dev/null +++ b/substrate/primitives/runtime/src/proving_trie/base16.rs @@ -0,0 +1,327 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types for a compact base-16 merkle trie used for checking and generating proofs within the +//! runtime. The `sp-trie` crate exposes all of these same functionality (and more), but this +//! library is designed to work more easily with runtime native types, which simply need to +//! implement `Encode`/`Decode`. It also exposes a runtime friendly `TrieError` type which can be +//! use inside of a FRAME Pallet. +//! +//! Proofs are created with latest substrate trie format (`LayoutV1`), and are not compatible with +//! proofs using `LayoutV0`. + +use super::{ProofToHashes, ProvingTrie, TrieError}; +use crate::{Decode, DispatchError, Encode}; +use codec::MaxEncodedLen; +use sp_std::vec::Vec; +use sp_trie::{ + trie_types::{TrieDBBuilder, TrieDBMutBuilderV1}, + LayoutV1, MemoryDB, Trie, TrieMut, +}; + +/// A helper structure for building a basic base-16 merkle trie and creating compact proofs for that +/// trie. Proofs are created with latest substrate trie format (`LayoutV1`), and are not compatible +/// with proofs using `LayoutV0`. +pub struct BasicProvingTrie +where + Hashing: sp_core::Hasher, +{ + db: MemoryDB, + root: Hashing::Out, + _phantom: core::marker::PhantomData<(Key, Value)>, +} + +impl BasicProvingTrie +where + Hashing: sp_core::Hasher, + Key: Encode, +{ + /// Create a compact merkle proof needed to prove all `keys` and their values are in the trie. + /// + /// When verifying the proof created by this function, you must include all of the keys and + /// values of the proof, else the verifier will complain that extra nodes are provided in the + /// proof that are not needed. + pub fn create_multi_proof(&self, keys: &[Key]) -> Result, DispatchError> { + sp_trie::generate_trie_proof::, _, _, _>( + &self.db, + self.root, + &keys.into_iter().map(|k| k.encode()).collect::>>(), + ) + .map_err(|err| TrieError::from(*err).into()) + .map(|structured_proof| structured_proof.encode()) + } +} + +impl ProvingTrie for BasicProvingTrie +where + Hashing: sp_core::Hasher, + Key: Encode, + Value: Encode + Decode, +{ + /// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs. + fn generate_for(items: I) -> Result + where + I: IntoIterator, + { + let mut db = MemoryDB::default(); + let mut root = Default::default(); + + { + let mut trie = TrieDBMutBuilderV1::new(&mut db, &mut root).build(); + for (key, value) in items.into_iter() { + key.using_encoded(|k| value.using_encoded(|v| trie.insert(k, v))) + .map_err(|_| "failed to insert into trie")?; + } + } + + Ok(Self { db, root, _phantom: Default::default() }) + } + + /// Access the underlying trie root. + fn root(&self) -> &Hashing::Out { + &self.root + } + + /// Query a value contained within the current trie. Returns `None` if the + /// nodes within the current `MemoryDB` are insufficient to query the item. + fn query(&self, key: &Key) -> Option { + let trie = TrieDBBuilder::new(&self.db, &self.root).build(); + key.using_encoded(|s| trie.get(s)) + .ok()? + .and_then(|raw| Value::decode(&mut &*raw).ok()) + } + + /// Create a compact merkle proof needed to prove a single key and its value are in the trie. + fn create_proof(&self, key: &Key) -> Result, DispatchError> { + sp_trie::generate_trie_proof::, _, _, _>( + &self.db, + self.root, + &[key.encode()], + ) + .map_err(|err| TrieError::from(*err).into()) + .map(|structured_proof| structured_proof.encode()) + } + + /// Verify the existence of `key` and `value` in a given trie root and proof. + fn verify_proof( + root: &Hashing::Out, + proof: &[u8], + key: &Key, + value: &Value, + ) -> Result<(), DispatchError> { + verify_proof::(root, proof, key, value) + } +} + +impl ProofToHashes for BasicProvingTrie +where + Hashing: sp_core::Hasher, + Hashing::Out: MaxEncodedLen, +{ + // Our proof is just raw bytes. + type Proof = [u8]; + // This base 16 trie uses a raw proof of `Vec`, where the length of the first `Vec` + // is the depth of the trie. We can use this to predict the number of hashes. + fn proof_to_hashes(proof: &[u8]) -> Result { + use codec::DecodeLength; + let depth = + > as DecodeLength>::len(proof).map_err(|_| TrieError::DecodeError)?; + Ok(depth as u32) + } +} + +/// Verify the existence of `key` and `value` in a given trie root and proof. +pub fn verify_proof( + root: &Hashing::Out, + proof: &[u8], + key: &Key, + value: &Value, +) -> Result<(), DispatchError> +where + Hashing: sp_core::Hasher, + Key: Encode, + Value: Encode, +{ + let structured_proof: Vec> = + Decode::decode(&mut &proof[..]).map_err(|_| TrieError::DecodeError)?; + sp_trie::verify_trie_proof::, _, _, _>( + &root, + &structured_proof, + &[(key.encode(), Some(value.encode()))], + ) + .map_err(|err| TrieError::from(err).into()) +} + +/// Verify the existence of multiple `items` in a given trie root and proof. +pub fn verify_multi_proof( + root: &Hashing::Out, + proof: &[u8], + items: &[(Key, Value)], +) -> Result<(), DispatchError> +where + Hashing: sp_core::Hasher, + Key: Encode, + Value: Encode, +{ + let structured_proof: Vec> = + Decode::decode(&mut &proof[..]).map_err(|_| TrieError::DecodeError)?; + let items_encoded = items + .into_iter() + .map(|(key, value)| (key.encode(), Some(value.encode()))) + .collect::, Option>)>>(); + + sp_trie::verify_trie_proof::, _, _, _>( + &root, + &structured_proof, + &items_encoded, + ) + .map_err(|err| TrieError::from(err).into()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::traits::BlakeTwo256; + use sp_core::H256; + use sp_std::collections::btree_map::BTreeMap; + + // A trie which simulates a trie of accounts (u32) and balances (u128). + type BalanceTrie = BasicProvingTrie; + + // The expected root hash for an empty trie. + fn empty_root() -> H256 { + sp_trie::empty_trie_root::>() + } + + fn create_balance_trie() -> BalanceTrie { + // Create a map of users and their balances. + let mut map = BTreeMap::::new(); + for i in 0..100u32 { + map.insert(i, i.into()); + } + + // Put items into the trie. + let balance_trie = BalanceTrie::generate_for(map).unwrap(); + + // Root is changed. + let root = *balance_trie.root(); + assert!(root != empty_root()); + + // Assert valid keys are queryable. + assert_eq!(balance_trie.query(&6u32), Some(6u128)); + assert_eq!(balance_trie.query(&9u32), Some(9u128)); + assert_eq!(balance_trie.query(&69u32), Some(69u128)); + // Invalid key returns none. + assert_eq!(balance_trie.query(&6969u32), None); + + balance_trie + } + + #[test] + fn empty_trie_works() { + let empty_trie = BalanceTrie::generate_for(Vec::new()).unwrap(); + assert_eq!(*empty_trie.root(), empty_root()); + } + + #[test] + fn basic_end_to_end_single_value() { + let balance_trie = create_balance_trie(); + let root = *balance_trie.root(); + + // Create a proof for a valid key. + let proof = balance_trie.create_proof(&6u32).unwrap(); + + // Assert key is provable, all other keys are invalid. + for i in 0..200u32 { + if i == 6 { + assert_eq!( + verify_proof::(&root, &proof, &i, &u128::from(i)), + Ok(()) + ); + // Wrong value is invalid. + assert_eq!( + verify_proof::(&root, &proof, &i, &u128::from(i + 1)), + Err(TrieError::RootMismatch.into()) + ); + } else { + assert!( + verify_proof::(&root, &proof, &i, &u128::from(i)).is_err() + ); + } + } + } + + #[test] + fn basic_end_to_end_multi() { + let balance_trie = create_balance_trie(); + let root = *balance_trie.root(); + + // Create a proof for a valid and invalid key. + let proof = balance_trie.create_multi_proof(&[6u32, 9u32, 69u32]).unwrap(); + let items = [(6u32, 6u128), (9u32, 9u128), (69u32, 69u128)]; + + assert_eq!(verify_multi_proof::(&root, &proof, &items), Ok(())); + } + + #[test] + fn proof_fails_with_bad_data() { + let balance_trie = create_balance_trie(); + let root = *balance_trie.root(); + + // Create a proof for a valid key. + let proof = balance_trie.create_proof(&6u32).unwrap(); + + // Correct data verifies successfully + assert_eq!(verify_proof::(&root, &proof, &6u32, &6u128), Ok(())); + + // Fail to verify proof with wrong root + assert_eq!( + verify_proof::(&Default::default(), &proof, &6u32, &6u128), + Err(TrieError::RootMismatch.into()) + ); + + // Crete a bad proof. + let bad_proof = balance_trie.create_proof(&99u32).unwrap(); + + // Fail to verify data with the wrong proof + assert_eq!( + verify_proof::(&root, &bad_proof, &6u32, &6u128), + Err(TrieError::ExtraneousHashReference.into()) + ); + } + + #[test] + fn proof_to_hashes() { + let mut i: u32 = 1; + // Compute log base 16 and round up + let log16 = |x: u32| -> u32 { + let x_f64 = x as f64; + let log16_x = (x_f64.ln() / 16_f64.ln()).ceil(); + log16_x as u32 + }; + + while i < 10_000_000 { + let trie = BalanceTrie::generate_for((0..i).map(|i| (i, u128::from(i)))).unwrap(); + let proof = trie.create_proof(&0).unwrap(); + let hashes = BalanceTrie::proof_to_hashes(&proof).unwrap(); + let log16 = log16(i).max(1); + + assert_eq!(hashes, log16); + i = i * 10; + } + } +} diff --git a/substrate/primitives/runtime/src/proving_trie/base2.rs b/substrate/primitives/runtime/src/proving_trie/base2.rs new file mode 100644 index 000000000000..2b14a59ab056 --- /dev/null +++ b/substrate/primitives/runtime/src/proving_trie/base2.rs @@ -0,0 +1,288 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types for a base-2 merkle tree used for checking and generating proofs within the +//! runtime. The `binary-merkle-tree` crate exposes all of these same functionality (and more), but +//! this library is designed to work more easily with runtime native types, which simply need to +//! implement `Encode`/`Decode`. + +use super::{ProofToHashes, ProvingTrie, TrieError}; +use crate::{Decode, DispatchError, Encode}; +use binary_merkle_tree::{merkle_proof, merkle_root, MerkleProof}; +use codec::MaxEncodedLen; +use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; + +/// A helper structure for building a basic base-2 merkle trie and creating compact proofs for that +/// trie. +pub struct BasicProvingTrie +where + Hashing: sp_core::Hasher, +{ + db: BTreeMap, + root: Hashing::Out, + _phantom: core::marker::PhantomData<(Key, Value)>, +} + +impl ProvingTrie for BasicProvingTrie +where + Hashing: sp_core::Hasher, + Hashing::Out: Encode + Decode, + Key: Encode + Decode + Ord, + Value: Encode + Decode + Clone, +{ + /// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs. + fn generate_for(items: I) -> Result + where + I: IntoIterator, + { + let mut db = BTreeMap::default(); + for (key, value) in items.into_iter() { + db.insert(key, value); + } + let root = merkle_root::(db.iter().map(|item| item.encode())); + Ok(Self { db, root, _phantom: Default::default() }) + } + + /// Access the underlying trie root. + fn root(&self) -> &Hashing::Out { + &self.root + } + + /// Query a value contained within the current trie. Returns `None` if the + /// nodes within the current `db` are insufficient to query the item. + fn query(&self, key: &Key) -> Option { + self.db.get(&key).cloned() + } + + /// Create a compact merkle proof needed to prove a single key and its value are in the trie. + /// Returns an error if the nodes within the current `db` are insufficient to create a proof. + fn create_proof(&self, key: &Key) -> Result, DispatchError> { + let mut encoded = Vec::with_capacity(self.db.len()); + let mut found_index = None; + + // Find the index of our key, and encode the (key, value) pair. + for (i, (k, v)) in self.db.iter().enumerate() { + // If we found the key we are looking for, save it. + if k == key { + found_index = Some(i); + } + + encoded.push((k, v).encode()); + } + + let index = found_index.ok_or(TrieError::IncompleteDatabase)?; + let proof = merkle_proof::>, Vec>(encoded, index as u32); + Ok(proof.encode()) + } + + /// Verify the existence of `key` and `value` in a given trie root and proof. + fn verify_proof( + root: &Hashing::Out, + proof: &[u8], + key: &Key, + value: &Value, + ) -> Result<(), DispatchError> { + verify_proof::(root, proof, key, value) + } +} + +impl ProofToHashes for BasicProvingTrie +where + Hashing: sp_core::Hasher, + Hashing::Out: MaxEncodedLen + Decode, + Key: Decode, + Value: Decode, +{ + // Our proof is just raw bytes. + type Proof = [u8]; + // This base 2 merkle trie includes a `proof` field which is a `Vec`. + // The length of this vector tells us the depth of the proof, and how many + // hashes we need to calculate. + fn proof_to_hashes(proof: &[u8]) -> Result { + let decoded_proof: MerkleProof> = + Decode::decode(&mut &proof[..]).map_err(|_| TrieError::IncompleteProof)?; + let depth = decoded_proof.proof.len(); + Ok(depth as u32) + } +} + +/// Verify the existence of `key` and `value` in a given trie root and proof. +pub fn verify_proof( + root: &Hashing::Out, + proof: &[u8], + key: &Key, + value: &Value, +) -> Result<(), DispatchError> +where + Hashing: sp_core::Hasher, + Hashing::Out: Decode, + Key: Encode + Decode, + Value: Encode + Decode, +{ + let decoded_proof: MerkleProof> = + Decode::decode(&mut &proof[..]).map_err(|_| TrieError::IncompleteProof)?; + if *root != decoded_proof.root { + return Err(TrieError::RootMismatch.into()); + } + + if (key, value).encode() != decoded_proof.leaf { + return Err(TrieError::ValueMismatch.into()); + } + + if binary_merkle_tree::verify_proof::( + &decoded_proof.root, + decoded_proof.proof, + decoded_proof.number_of_leaves, + decoded_proof.leaf_index, + &decoded_proof.leaf, + ) { + Ok(()) + } else { + Err(TrieError::IncompleteProof.into()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::traits::BlakeTwo256; + use sp_core::H256; + use sp_std::collections::btree_map::BTreeMap; + + // A trie which simulates a trie of accounts (u32) and balances (u128). + type BalanceTrie = BasicProvingTrie; + + // The expected root hash for an empty trie. + fn empty_root() -> H256 { + let tree = BalanceTrie::generate_for(Vec::new()).unwrap(); + *tree.root() + } + + fn create_balance_trie() -> BalanceTrie { + // Create a map of users and their balances. + let mut map = BTreeMap::::new(); + for i in 0..100u32 { + map.insert(i, i.into()); + } + + // Put items into the trie. + let balance_trie = BalanceTrie::generate_for(map).unwrap(); + + // Root is changed. + let root = *balance_trie.root(); + assert!(root != empty_root()); + + // Assert valid keys are queryable. + assert_eq!(balance_trie.query(&6u32), Some(6u128)); + assert_eq!(balance_trie.query(&9u32), Some(9u128)); + assert_eq!(balance_trie.query(&69u32), Some(69u128)); + + balance_trie + } + + #[test] + fn empty_trie_works() { + let empty_trie = BalanceTrie::generate_for(Vec::new()).unwrap(); + assert_eq!(*empty_trie.root(), empty_root()); + } + + #[test] + fn basic_end_to_end_single_value() { + let balance_trie = create_balance_trie(); + let root = *balance_trie.root(); + + // Create a proof for a valid key. + let proof = balance_trie.create_proof(&6u32).unwrap(); + + // Assert key is provable, all other keys are invalid. + for i in 0..200u32 { + if i == 6 { + assert_eq!( + verify_proof::(&root, &proof, &i, &u128::from(i)), + Ok(()) + ); + // Wrong value is invalid. + assert_eq!( + verify_proof::(&root, &proof, &i, &u128::from(i + 1)), + Err(TrieError::ValueMismatch.into()) + ); + } else { + assert!( + verify_proof::(&root, &proof, &i, &u128::from(i)).is_err() + ); + } + } + } + + #[test] + fn proof_fails_with_bad_data() { + let balance_trie = create_balance_trie(); + let root = *balance_trie.root(); + + // Create a proof for a valid key. + let proof = balance_trie.create_proof(&6u32).unwrap(); + + // Correct data verifies successfully + assert_eq!(verify_proof::(&root, &proof, &6u32, &6u128), Ok(())); + + // Fail to verify proof with wrong root + assert_eq!( + verify_proof::(&Default::default(), &proof, &6u32, &6u128), + Err(TrieError::RootMismatch.into()) + ); + + // Fail to verify proof with wrong data + assert_eq!( + verify_proof::(&root, &[], &6u32, &6u128), + Err(TrieError::IncompleteProof.into()) + ); + } + + // We make assumptions about the structure of the merkle proof in order to provide the + // `proof_to_hashes` function. This test keeps those assumptions checked. + #[test] + fn assert_structure_of_merkle_proof() { + let balance_trie = create_balance_trie(); + let root = *balance_trie.root(); + // Create a proof for a valid key. + let proof = balance_trie.create_proof(&6u32).unwrap(); + let decoded_proof: MerkleProof> = Decode::decode(&mut &proof[..]).unwrap(); + + let constructed_proof = MerkleProof::> { + root, + proof: decoded_proof.proof.clone(), + number_of_leaves: 100, + leaf_index: 6, + leaf: (6u32, 6u128).encode(), + }; + assert_eq!(constructed_proof, decoded_proof); + } + + #[test] + fn proof_to_hashes() { + let mut i: u32 = 1; + while i < 10_000_000 { + let trie = BalanceTrie::generate_for((0..i).map(|i| (i, u128::from(i)))).unwrap(); + let proof = trie.create_proof(&0).unwrap(); + let hashes = BalanceTrie::proof_to_hashes(&proof).unwrap(); + let log2 = (i as f64).log2().ceil() as u32; + + assert_eq!(hashes, log2); + i = i * 10; + } + } +} diff --git a/substrate/primitives/runtime/src/proving_trie/mod.rs b/substrate/primitives/runtime/src/proving_trie/mod.rs new file mode 100644 index 000000000000..009aa6d4935f --- /dev/null +++ b/substrate/primitives/runtime/src/proving_trie/mod.rs @@ -0,0 +1,187 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types for merkle tries compatible with the runtime. + +pub mod base16; +pub mod base2; + +use crate::{Decode, DispatchError, Encode, MaxEncodedLen, TypeInfo}; +#[cfg(feature = "serde")] +use crate::{Deserialize, Serialize}; +use sp_std::vec::Vec; +use sp_trie::{trie_types::TrieError as SpTrieError, VerifyError}; + +/// A runtime friendly error type for tries. +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum TrieError { + /* From TrieError */ + /// Attempted to create a trie with a state root not in the DB. + InvalidStateRoot, + /// Trie item not found in the database, + IncompleteDatabase, + /// A value was found in the trie with a nibble key that was not byte-aligned. + ValueAtIncompleteKey, + /// Corrupt Trie item. + DecoderError, + /// Hash is not value. + InvalidHash, + /* From VerifyError */ + /// The statement being verified contains multiple key-value pairs with the same key. + DuplicateKey, + /// The proof contains at least one extraneous node. + ExtraneousNode, + /// The proof contains at least one extraneous value which should have been omitted from the + /// proof. + ExtraneousValue, + /// The proof contains at least one extraneous hash reference the should have been omitted. + ExtraneousHashReference, + /// The proof contains an invalid child reference that exceeds the hash length. + InvalidChildReference, + /// The proof indicates that an expected value was not found in the trie. + ValueMismatch, + /// The proof is missing trie nodes required to verify. + IncompleteProof, + /// The root hash computed from the proof is incorrect. + RootMismatch, + /// One of the proof nodes could not be decoded. + DecodeError, +} + +impl From> for TrieError { + fn from(error: SpTrieError) -> Self { + match error { + SpTrieError::InvalidStateRoot(..) => Self::InvalidStateRoot, + SpTrieError::IncompleteDatabase(..) => Self::IncompleteDatabase, + SpTrieError::ValueAtIncompleteKey(..) => Self::ValueAtIncompleteKey, + SpTrieError::DecoderError(..) => Self::DecoderError, + SpTrieError::InvalidHash(..) => Self::InvalidHash, + } + } +} + +impl From> for TrieError { + fn from(error: VerifyError) -> Self { + match error { + VerifyError::DuplicateKey(..) => Self::DuplicateKey, + VerifyError::ExtraneousNode => Self::ExtraneousNode, + VerifyError::ExtraneousValue(..) => Self::ExtraneousValue, + VerifyError::ExtraneousHashReference(..) => Self::ExtraneousHashReference, + VerifyError::InvalidChildReference(..) => Self::InvalidChildReference, + VerifyError::ValueMismatch(..) => Self::ValueMismatch, + VerifyError::IncompleteProof => Self::IncompleteProof, + VerifyError::RootMismatch(..) => Self::RootMismatch, + VerifyError::DecodeError(..) => Self::DecodeError, + } + } +} + +impl From for &'static str { + fn from(e: TrieError) -> &'static str { + match e { + TrieError::InvalidStateRoot => "The state root is not in the database.", + TrieError::IncompleteDatabase => "A trie item was not found in the database.", + TrieError::ValueAtIncompleteKey => + "A value was found with a key that is not byte-aligned.", + TrieError::DecoderError => "A corrupt trie item was encountered.", + TrieError::InvalidHash => "The hash does not match the expected value.", + TrieError::DuplicateKey => "The proof contains duplicate keys.", + TrieError::ExtraneousNode => "The proof contains extraneous nodes.", + TrieError::ExtraneousValue => "The proof contains extraneous values.", + TrieError::ExtraneousHashReference => "The proof contains extraneous hash references.", + TrieError::InvalidChildReference => "The proof contains an invalid child reference.", + TrieError::ValueMismatch => "The proof indicates a value mismatch.", + TrieError::IncompleteProof => "The proof is incomplete.", + TrieError::RootMismatch => "The root hash computed from the proof is incorrect.", + TrieError::DecodeError => "One of the proof nodes could not be decoded.", + } + } +} + +/// An interface for creating, interacting with, and creating proofs in a merkle trie. +pub trait ProvingTrie +where + Self: Sized, + Hashing: sp_core::Hasher, +{ + /// Create a new instance of a `ProvingTrie` using an iterator of key/value pairs. + fn generate_for(items: I) -> Result + where + I: IntoIterator; + /// Access the underlying trie root. + fn root(&self) -> &Hashing::Out; + /// Query a value contained within the current trie. Returns `None` if the + /// the value does not exist in the trie. + fn query(&self, key: &Key) -> Option; + /// Create a proof that can be used to verify a key and its value are in the trie. + fn create_proof(&self, key: &Key) -> Result, DispatchError>; + /// Verify the existence of `key` and `value` in a given trie root and proof. + fn verify_proof( + root: &Hashing::Out, + proof: &[u8], + key: &Key, + value: &Value, + ) -> Result<(), DispatchError>; +} + +/// This trait is one strategy that can be used to benchmark a trie proof verification for the +/// runtime. This strategy assumes that the majority complexity of verifying a merkle proof comes +/// from computing hashes to recreate the merkle root. This trait converts the the proof, some +/// bytes, to the number of hashes we expect to execute to verify that proof. +pub trait ProofToHashes { + /// The Proof type we will use to determine the number of hashes. + type Proof: ?Sized; + /// This function returns the number of hashes we expect to calculate based on the + /// size of the proof. This is used for benchmarking, so for worst case scenario, we should + /// round up. + /// + /// The major complexity of doing a `verify_proof` is computing the hashes needed + /// to calculate the merkle root. For tries, it should be easy to predict the depth + /// of the trie (which is equivalent to the hashes), by looking at the length of the proof. + fn proof_to_hashes(proof: &Self::Proof) -> Result; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::traits::BlakeTwo256; + + // A trie which simulates a trie of accounts (u32) and balances (u128). + type BalanceTrie2 = base2::BasicProvingTrie; + type BalanceTrie16 = base16::BasicProvingTrie; + + #[test] + fn basic_api_usage_base_2() { + let balance_trie = BalanceTrie2::generate_for((0..100u32).map(|i| (i, i.into()))).unwrap(); + let root = *balance_trie.root(); + assert_eq!(balance_trie.query(&69), Some(69)); + assert_eq!(balance_trie.query(&6969), None); + let proof = balance_trie.create_proof(&69u32).unwrap(); + assert_eq!(BalanceTrie2::verify_proof(&root, &proof, &69u32, &69u128), Ok(())); + } + + #[test] + fn basic_api_usage_base_16() { + let balance_trie = BalanceTrie16::generate_for((0..100u32).map(|i| (i, i.into()))).unwrap(); + let root = *balance_trie.root(); + assert_eq!(balance_trie.query(&69), Some(69)); + assert_eq!(balance_trie.query(&6969), None); + let proof = balance_trie.create_proof(&69u32).unwrap(); + assert_eq!(BalanceTrie16::verify_proof(&root, &proof, &69u32, &69u128), Ok(())); + } +} diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index 25ef15eaf56e..fc63bc76decb 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -2342,8 +2342,6 @@ impl BlockNumberProvider for () { mod tests { use super::*; use crate::codec::{Decode, Encode, Input}; - #[cfg(feature = "bls-experimental")] - use sp_core::{bls377, bls381}; use sp_core::{ crypto::{Pair, UncheckedFrom}, ecdsa, ed25519, sr25519, @@ -2486,14 +2484,4 @@ mod tests { fn ecdsa_verify_works() { signature_verify_test!(ecdsa); } - - #[cfg(feature = "bls-experimental")] - fn bls377_verify_works() { - signature_verify_test!(bls377) - } - - #[cfg(feature = "bls-experimental")] - fn bls381_verify_works() { - signature_verify_test!(bls381) - } } diff --git a/substrate/primitives/state-machine/src/ext.rs b/substrate/primitives/state-machine/src/ext.rs index 7a79c4e8a1f1..baad7e621bed 100644 --- a/substrate/primitives/state-machine/src/ext.rs +++ b/substrate/primitives/state-machine/src/ext.rs @@ -713,6 +713,7 @@ where } /// Implement `Encode` by forwarding the stored raw vec. +#[allow(dead_code)] struct EncodeOpaqueValue(Vec); impl Encode for EncodeOpaqueValue { diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index a28f29b01581..7f27bb097290 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -24,7 +24,6 @@ harness = false ahash = { optional = true, workspace = true } codec = { workspace = true } hash-db = { workspace = true } -lazy_static = { optional = true, workspace = true } memory-db = { workspace = true } nohash-hasher = { optional = true, workspace = true } parking_lot = { optional = true, workspace = true, default-features = true } @@ -51,7 +50,6 @@ std = [ "ahash", "codec/std", "hash-db/std", - "lazy_static", "memory-db/std", "nohash-hasher", "parking_lot", diff --git a/substrate/primitives/trie/src/cache/shared_cache.rs b/substrate/primitives/trie/src/cache/shared_cache.rs index e3ba94a2af7c..7f6da80fe95f 100644 --- a/substrate/primitives/trie/src/cache/shared_cache.rs +++ b/substrate/primitives/trie/src/cache/shared_cache.rs @@ -25,17 +25,15 @@ use schnellru::LruMap; use std::{ collections::{hash_map::Entry as SetEntry, HashMap}, hash::{BuildHasher, Hasher as _}, - sync::Arc, + sync::{Arc, LazyLock}, }; use trie_db::{node::NodeOwned, CachedValue}; -lazy_static::lazy_static! { - static ref RANDOM_STATE: ahash::RandomState = { - use rand::Rng; - let mut rng = rand::thread_rng(); - ahash::RandomState::generate_with(rng.gen(), rng.gen(), rng.gen(), rng.gen()) - }; -} +static RANDOM_STATE: LazyLock = LazyLock::new(|| { + use rand::Rng; + let mut rng = rand::thread_rng(); + ahash::RandomState::generate_with(rng.gen(), rng.gen(), rng.gen(), rng.gen()) +}); pub struct SharedNodeCacheLimiter { /// The maximum size (in bytes) the cache can hold inline. diff --git a/substrate/test-utils/cli/build.rs b/substrate/test-utils/cli/build.rs index a68cb706e8fb..c63f0b8b6674 100644 --- a/substrate/test-utils/cli/build.rs +++ b/substrate/test-utils/cli/build.rs @@ -20,6 +20,6 @@ use std::env; fn main() { if let Ok(profile) = env::var("PROFILE") { - println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + println!("cargo:rustc-cfg=build_profile=\"{}\"", profile); } } diff --git a/substrate/test-utils/cli/src/lib.rs b/substrate/test-utils/cli/src/lib.rs index d77a89b4dbf4..70d68f6f1835 100644 --- a/substrate/test-utils/cli/src/lib.rs +++ b/substrate/test-utils/cli/src/lib.rs @@ -130,7 +130,7 @@ pub fn start_node() -> Child { /// build_substrate(&["--features=try-runtime"]); /// ``` pub fn build_substrate(args: &[&str]) { - let is_release_build = !cfg!(build_type = "debug"); + let is_release_build = !cfg!(build_profile = "debug"); // Get the root workspace directory from the CARGO_MANIFEST_DIR environment variable let mut cmd = Command::new("cargo"); diff --git a/substrate/utils/fork-tree/src/lib.rs b/substrate/utils/fork-tree/src/lib.rs index ff86467c85d5..fe349b6c29af 100644 --- a/substrate/utils/fork-tree/src/lib.rs +++ b/substrate/utils/fork-tree/src/lib.rs @@ -810,12 +810,11 @@ impl<'a, H, N, V> Iterator for ForkTreeIterator<'a, H, N, V> { type Item = &'a Node; fn next(&mut self) -> Option { - self.stack.pop().map(|node| { + self.stack.pop().inspect(|node| { // child nodes are stored ordered by max branch height (decreasing), // we want to keep this ordering while iterating but since we're // using a stack for iterator state we need to reverse it. self.stack.extend(node.children.iter().rev()); - node }) } } diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 4e88e3360e39..ee5522f5bc04 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -24,7 +24,6 @@ comfy-table = { workspace = true } handlebars = { workspace = true } Inflector = { workspace = true } itertools = { workspace = true } -lazy_static = { workspace = true } linked-hash-map = { workspace = true } log = { workspace = true, default-features = true } rand = { features = ["small_rng"], workspace = true, default-features = true } diff --git a/substrate/utils/frame/benchmarking-cli/build.rs b/substrate/utils/frame/benchmarking-cli/build.rs index 1545d1e0c21e..06cdb7973abd 100644 --- a/substrate/utils/frame/benchmarking-cli/build.rs +++ b/substrate/utils/frame/benchmarking-cli/build.rs @@ -24,8 +24,12 @@ use std::env; pub fn main() { if let Ok(opt_level) = env::var("OPT_LEVEL") { println!("cargo:rustc-cfg=build_opt_level={:?}", opt_level); + } else { + println!("cargo:rustc-cfg=build_opt_level={:?}", "unknown"); } if let Ok(profile) = env::var("PROFILE") { println!("cargo:rustc-cfg=build_profile={:?}", profile); + } else { + println!("cargo:rustc-cfg=build_profile={:?}", "unknown"); } } diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs index ee1d490b8547..f542eb60520e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -17,19 +17,17 @@ //! Contains types to define hardware requirements. -use lazy_static::lazy_static; use sc_sysinfo::Requirements; +use std::sync::LazyLock; -lazy_static! { - /// The hardware requirements as measured on reference hardware. - /// - /// These values are provided by Parity, however it is possible - /// to use your own requirements if you are running a custom chain. - pub static ref SUBSTRATE_REFERENCE_HARDWARE: Requirements = { - let raw = include_bytes!("reference_hardware.json").as_slice(); - serde_json::from_slice(raw).expect("Hardcoded data is known good; qed") - }; -} +/// The hardware requirements as measured on reference hardware. +/// +/// These values are provided by Parity, however it is possible +/// to use your own requirements if you are running a custom chain. +pub static SUBSTRATE_REFERENCE_HARDWARE: LazyLock = LazyLock::new(|| { + let raw = include_bytes!("reference_hardware.json").as_slice(); + serde_json::from_slice(raw).expect("Hardcoded data is known good; qed") +}); #[cfg(test)] mod tests { diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 15a1fd007ca2..8f0e8a23e54a 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -39,6 +39,7 @@ frame-metadata = { features = ["current"], optional = true, workspace = true, de codec = { optional = true, workspace = true, default-features = true } array-bytes = { optional = true, workspace = true, default-features = true } sp-tracing = { optional = true, workspace = true, default-features = true } +shlex = { workspace = true } [features] # Enable support for generating the metadata hash. diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index 07de4c15831b..e3f2ff5cd733 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -84,6 +84,9 @@ //! - `WASM_BUILD_STD` - Sets whether the Rust's standard library crates will also be built. This is //! necessary to make sure the standard library crates only use the exact WASM feature set that //! our executor supports. Enabled by default. +//! - `WASM_BUILD_CARGO_ARGS` - This can take a string as space separated list of `cargo` arguments. +//! It was added specifically for the use case of enabling JSON diagnostic messages during the +//! build phase, to be used by IDEs that parse them, but it might be useful for other cases too. //! - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all processes launched to //! prevent network access. Useful in offline environments. //! @@ -161,6 +164,10 @@ const WASM_BUILD_WORKSPACE_HINT: &str = "WASM_BUILD_WORKSPACE_HINT"; /// Environment variable to set whether we'll build `core`/`std`. const WASM_BUILD_STD: &str = "WASM_BUILD_STD"; +/// Environment variable to set additional cargo arguments that might be useful +/// during the build phase. +const WASM_BUILD_CARGO_ARGS: &str = "WASM_BUILD_CARGO_ARGS"; + /// The target to use for the runtime. Valid values are `wasm` (default) or `riscv`. const RUNTIME_TARGET: &str = "SUBSTRATE_RUNTIME_TARGET"; diff --git a/substrate/utils/wasm-builder/src/wasm_project.rs b/substrate/utils/wasm-builder/src/wasm_project.rs index a6eda078fde0..26edd2ea1f22 100644 --- a/substrate/utils/wasm-builder/src/wasm_project.rs +++ b/substrate/utils/wasm-builder/src/wasm_project.rs @@ -601,9 +601,10 @@ fn project_enabled_features( // We don't want to enable the `std`/`default` feature for the wasm build and // we need to check if the feature is enabled by checking the env variable. *f != "std" && - *f != "default" && env::var(format!("CARGO_FEATURE_{}", feature_env)) - .map(|v| v == "1") - .unwrap_or_default() + *f != "default" && + env::var(format!("CARGO_FEATURE_{feature_env}")) + .map(|v| v == "1") + .unwrap_or_default() }) .map(|d| d.0.clone()) .collect::>(); @@ -868,6 +869,18 @@ fn build_bloaty_blob( // We don't want to call ourselves recursively .env(crate::SKIP_BUILD_ENV, ""); + let cargo_args = env::var(crate::WASM_BUILD_CARGO_ARGS).unwrap_or_default(); + if !cargo_args.is_empty() { + let Some(args) = shlex::split(&cargo_args) else { + build_helper::warning(format!( + "the {} environment variable is not a valid shell string", + crate::WASM_BUILD_CARGO_ARGS + )); + std::process::exit(1); + }; + build_cmd.args(args); + } + #[cfg(feature = "metadata-hash")] if let Some(hash) = metadata_hash { build_cmd.env("RUNTIME_METADATA_HASH", array_bytes::bytes2hex("0x", &hash)); @@ -1139,6 +1152,7 @@ fn generate_rerun_if_changed_instructions( println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TOOLCHAIN); println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_STD); println!("cargo:rerun-if-env-changed={}", crate::RUNTIME_TARGET); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_CARGO_ARGS); } /// Track files and paths related to the given package to rerun `build.rs` on any relevant change. diff --git a/templates/parachain/pallets/template/src/benchmarking.rs b/templates/parachain/pallets/template/src/benchmarking.rs index 5acad6e60dec..29572c3ff609 100644 --- a/templates/parachain/pallets/template/src/benchmarking.rs +++ b/templates/parachain/pallets/template/src/benchmarking.rs @@ -1,5 +1,4 @@ //! Benchmarking setup for pallet-template -#![cfg(feature = "runtime-benchmarks")] use super::*; use frame_benchmarking::v2::*; diff --git a/templates/solochain/pallets/template/src/benchmarking.rs b/templates/solochain/pallets/template/src/benchmarking.rs index d1a9554aed6d..8af5d246f761 100644 --- a/templates/solochain/pallets/template/src/benchmarking.rs +++ b/templates/solochain/pallets/template/src/benchmarking.rs @@ -1,5 +1,5 @@ //! Benchmarking setup for pallet-template -#![cfg(feature = "runtime-benchmarks")] + use super::*; #[allow(unused)] diff --git a/templates/zombienet/Cargo.toml b/templates/zombienet/Cargo.toml index cb2adf70dbd8..f29325dbe6a9 100644 --- a/templates/zombienet/Cargo.toml +++ b/templates/zombienet/Cargo.toml @@ -10,11 +10,11 @@ edition.workspace = true publish = false [dependencies] -env_logger = "0.11.2" -log = "0.4" -tokio = { version = "1.36.0", features = ["rt-multi-thread"] } -anyhow = "1.0.81" -zombienet-sdk = "0.2.8" +env_logger = { workspace = true } +log = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } +anyhow = { workspace = true } +zombienet-sdk = { workspace = true } [features] zombienet = [] diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index b7c1c375094f..83cbebbc61cd 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -600,7 +600,7 @@ runtime = [ "sp-wasm-interface", "sp-weights", ] -node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-parachain-lib", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] +node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-parachain-lib", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] tuples-96 = [ "frame-support-procedural?/tuples-96", "frame-support?/tuples-96", @@ -1967,6 +1967,11 @@ path = "../polkadot/node/core/approval-voting" default-features = false optional = true +[dependencies.polkadot-node-core-approval-voting-parallel] +path = "../polkadot/node/core/approval-voting-parallel" +default-features = false +optional = true + [dependencies.polkadot-node-core-av-store] path = "../polkadot/node/core/av-store" default-features = false diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index b7b9c15fe588..4a653dab99b6 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -796,6 +796,10 @@ pub use polkadot_node_collation_generation; #[cfg(feature = "polkadot-node-core-approval-voting")] pub use polkadot_node_core_approval_voting; +/// Approval Voting Subsystem running approval work in parallel. +#[cfg(feature = "polkadot-node-core-approval-voting-parallel")] +pub use polkadot_node_core_approval_voting_parallel; + /// The Availability Store subsystem. Wrapper over the DB that stores availability data and /// chunks. #[cfg(feature = "polkadot-node-core-av-store")]